From e0f1eb5189bbaa290659137c8887aefeea56a32d Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Thu, 21 Apr 2022 21:12:40 -0700 Subject: [PATCH 01/96] chore: @npmcli/template-oss@3.4.2 --- .commitlintrc.js | 10 + .eslintrc.js | 15 + .eslintrc.json | 207 - .gitattributes | 1 - .github/CODEOWNERS | 4 +- .github/ISSUE_TEMPLATE/bug.yml | 54 + .github/ISSUE_TEMPLATE/config.yml | 3 + .github/dependabot.yml | 17 + .github/settings.yml | 2 - .github/workflows/audit.yml | 27 + .github/workflows/ci.yml | 99 +- .github/workflows/codeql-analysis.yml | 71 +- .github/workflows/post-dependabot.yml | 43 + .github/workflows/pull-request.yml | 38 + .github/workflows/release-please.yml | 26 + .gitignore | 50 +- .npmrc | 3 + SECURITY.md | 3 + package-lock.json | 12411 ------------------------ package.json | 44 +- test/fixtures/.gitattributes | 1 + 21 files changed, 387 insertions(+), 12742 deletions(-) create mode 100644 .commitlintrc.js create mode 100644 .eslintrc.js delete mode 100644 .eslintrc.json delete mode 100644 .gitattributes create mode 100644 .github/ISSUE_TEMPLATE/bug.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/dependabot.yml delete mode 100644 .github/settings.yml create mode 100644 .github/workflows/audit.yml create mode 100644 .github/workflows/post-dependabot.yml create mode 100644 .github/workflows/pull-request.yml create mode 100644 .github/workflows/release-please.yml create mode 100644 .npmrc create mode 100644 SECURITY.md delete mode 100644 package-lock.json create mode 100644 test/fixtures/.gitattributes diff --git a/.commitlintrc.js b/.commitlintrc.js new file mode 100644 index 00000000..5b0b1a52 --- /dev/null +++ b/.commitlintrc.js @@ -0,0 +1,10 @@ +/* This file is automatically added by @npmcli/template-oss. Do not edit. */ + +module.exports = { + extends: ['@commitlint/config-conventional'], + rules: { + 'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'deps', 'chore']], + 'header-max-length': [2, 'always', 80], + 'subject-case': [0, 'always', ['lower-case', 'sentence-case', 'start-case']], + }, +} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..0e8ad007 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,15 @@ +/* This file is automatically added by @npmcli/template-oss. Do not edit. */ + +const { readdirSync: readdir } = require('fs') + +const localConfigs = readdir(__dirname) + .filter((file) => file.startsWith('.eslintrc.local.')) + .map((file) => `./${file}`) + +module.exports = { + root: true, + extends: [ + '@npmcli', + ...localConfigs, + ], +} diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 9a124b8b..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,207 +0,0 @@ -{ - "parserOptions": { - "ecmaVersion": 2018, - "ecmaFeatures": {}, - "sourceType": "script" - }, - - "env": { - "es6": true, - "node": true - }, - - "plugins": [ - "import", - "node", - "promise", - "standard" - ], - - "globals": { - "document": "readonly", - "navigator": "readonly", - "window": "readonly" - }, - - "rules": { - "accessor-pairs": "error", - "array-bracket-spacing": ["error", "never"], - "arrow-spacing": ["error", { "before": true, "after": true }], - "block-spacing": ["error", "always"], - "brace-style": ["error", "1tbs", { "allowSingleLine": false }], - "camelcase": ["error", { "properties": "never" }], - "comma-dangle": ["error", { - "arrays": "always-multiline", - "objects": "always-multiline", - "imports": "always-multiline", - "exports": "always-multiline", - "functions": "never" - }], - "comma-spacing": ["error", { "before": false, "after": true }], - "comma-style": ["error", "last"], - "computed-property-spacing": ["error", "never"], - "constructor-super": "error", - "curly": ["error", "multi-or-nest"], - "dot-location": ["error", "property"], - "dot-notation": ["error", { "allowKeywords": true }], - "eol-last": "error", - "eqeqeq": ["error", "always", { "null": "ignore" }], - "func-call-spacing": ["error", "never"], - "generator-star-spacing": ["error", { "before": true, "after": true }], - "handle-callback-err": ["error", "^(err|error)$" ], - "indent": ["error", 2, { - "SwitchCase": 1, - "VariableDeclarator": 1, - "outerIIFEBody": 1, - "MemberExpression": 1, - "FunctionDeclaration": { "parameters": 1, "body": 1 }, - "FunctionExpression": { "parameters": 1, "body": 1 }, - "CallExpression": { "arguments": 1 }, - "ArrayExpression": 1, - "ObjectExpression": 1, - "ImportDeclaration": 1, - "flatTernaryExpressions": true, - "ignoreComments": false, - "ignoredNodes": ["TemplateLiteral *"] - }], - "key-spacing": ["error", { "beforeColon": false, "afterColon": true }], - "keyword-spacing": ["error", { "before": true, "after": true }], - "lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }], - "new-cap": ["error", { "newIsCap": true, "capIsNew": false, "properties": true }], - "new-parens": "error", - "no-array-constructor": "error", - "no-async-promise-executor": "error", - "no-caller": "error", - "no-case-declarations": "error", - "no-class-assign": "error", - "no-compare-neg-zero": "error", - "no-cond-assign": "off", - "no-const-assign": "error", - "no-constant-condition": ["error", { "checkLoops": false }], - "no-control-regex": "error", - "no-debugger": "error", - "no-delete-var": "error", - "no-dupe-args": "error", - "no-dupe-class-members": "error", - "no-dupe-keys": "error", - "no-duplicate-case": "error", - "no-empty-character-class": "error", - "no-empty-pattern": "error", - "no-eval": "error", - "no-ex-assign": "error", - "no-extend-native": "error", - "no-extra-bind": "error", - "no-extra-boolean-cast": "error", - "no-extra-parens": ["error", "functions"], - "no-fallthrough": "off", - "no-floating-decimal": "error", - "no-func-assign": "error", - "no-global-assign": "error", - "no-implied-eval": "error", - "no-inner-declarations": ["error", "functions"], - "no-invalid-regexp": "error", - "no-irregular-whitespace": "error", - "no-iterator": "error", - "no-labels": ["error", { "allowLoop": true, "allowSwitch": false }], - "no-lone-blocks": "error", - "no-misleading-character-class": "error", - "no-prototype-builtins": "error", - "no-useless-catch": "error", - "no-mixed-operators": "off", - "no-mixed-spaces-and-tabs": "error", - "no-multi-spaces": "error", - "no-multi-str": "error", - "no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0 }], - "no-negated-in-lhs": "error", - "no-new": "off", - "no-new-func": "error", - "no-new-object": "error", - "no-new-require": "error", - "no-new-symbol": "error", - "no-new-wrappers": "error", - "no-obj-calls": "error", - "no-octal": "error", - "no-octal-escape": "error", - "no-path-concat": "error", - "no-proto": "error", - "no-redeclare": ["error", { "builtinGlobals": false }], - "no-regex-spaces": "error", - "no-return-assign": "off", - "no-self-assign": "off", - "no-self-compare": "error", - "no-sequences": "off", - "no-shadow-restricted-names": "error", - "no-sparse-arrays": "error", - "no-tabs": "error", - "no-template-curly-in-string": "error", - "no-this-before-super": "error", - "no-throw-literal": "off", - "no-trailing-spaces": "error", - "no-undef": "error", - "no-undef-init": "error", - "no-unexpected-multiline": "error", - "no-unmodified-loop-condition": "error", - "no-unneeded-ternary": ["error", { "defaultAssignment": false }], - "no-unreachable": "error", - "no-unsafe-finally": 0, - "no-unsafe-negation": "error", - "no-unused-expressions": ["off"], - "no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }], - "no-use-before-define": ["error", { "functions": false, "classes": false, "variables": false }], - "no-useless-call": "error", - "no-useless-computed-key": "error", - "no-useless-constructor": "error", - "no-useless-escape": "error", - "no-useless-rename": "error", - "no-useless-return": "error", - "no-void": "error", - "no-whitespace-before-property": "error", - "no-with": "error", - "nonblock-statement-body-position": [2, "below"], - "object-curly-newline": "off", - "object-curly-spacing": "off", - "object-property-newline": ["error", { "allowMultiplePropertiesPerLine": true }], - "one-var": ["error", { "initialized": "never" }], - "operator-linebreak": "off", - "padded-blocks": ["error", { "blocks": "never", "switches": "never", "classes": "never" }], - "prefer-const": ["error", {"destructuring": "all"}], - "prefer-promise-reject-errors": "error", - "quote-props": ["error", "as-needed"], - "quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }], - "rest-spread-spacing": ["error", "never"], - "semi": ["error", "never"], - "semi-spacing": ["error", { "before": false, "after": true }], - "space-before-blocks": ["error", "always"], - "space-before-function-paren": ["error", "always"], - "space-in-parens": ["error", "never"], - "space-infix-ops": "error", - "space-unary-ops": ["error", { "words": true, "nonwords": false }], - "spaced-comment": ["error", "always", { - "line": { "markers": ["*package", "!", "/", ",", "="] }, - "block": { "balanced": true, "markers": ["*package", "!", ",", ":", "::", "flow-include"], "exceptions": ["*"] } - }], - "symbol-description": "error", - "template-curly-spacing": ["error", "never"], - "template-tag-spacing": ["error", "never"], - "unicode-bom": ["error", "never"], - "use-isnan": "error", - "valid-typeof": ["error", { "requireStringLiterals": true }], - "wrap-iife": ["error", "any", { "functionPrototypeMethods": true }], - "yield-star-spacing": ["error", "both"], - "yoda": ["error", "never"], - - "import/export": "error", - "import/first": "error", - "import/no-absolute-path": ["error", { "esmodule": true, "commonjs": true, "amd": false }], - "import/no-duplicates": "error", - "import/no-named-default": "error", - "import/no-webpack-loader-syntax": "error", - - "node/no-deprecated-api": "error", - "node/process-exit-as-throw": "error", - - "promise/param-names": "off", - - "standard/no-callback-literal": "error" - } -} diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 00022d9c..00000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -test/fixtures/files/** text eol=lf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ef874313..2c54b0d2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,3 @@ -* @npm/cli-team +# This file is automatically added by @npmcli/template-oss. Do not edit. + +* @npm/cli-team diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 00000000..d043192f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,54 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Bug +description: File a bug/issue +title: "[BUG] " +labels: [ Bug, Needs Triage ] + +body: + - type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please [search here](./issues) to see if an issue already exists for your problem. + options: + - label: I have searched the existing issues + required: true + - type: textarea + attributes: + label: Current Behavior + description: A clear & concise description of what you're experiencing. + validations: + required: false + - type: textarea + attributes: + label: Expected Behavior + description: A clear & concise description of what you expected to happen. + validations: + required: false + - type: textarea + attributes: + label: Steps To Reproduce + description: Steps to reproduce the behavior. + value: | + 1. In this environment... + 2. With this config... + 3. Run '...' + 4. See error... + validations: + required: false + - type: textarea + attributes: + label: Environment + description: | + examples: + - **npm**: 7.6.3 + - **Node**: 13.14.0 + - **OS**: Ubuntu 20.04 + - **platform**: Macbook Pro + value: | + - npm: + - Node: + - OS: + - platform: + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..d640909f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,3 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +blank_issues_enabled: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..96d8eafb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +version: 2 + +updates: + - package-ecosystem: npm + directory: "/" + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" diff --git a/.github/settings.yml b/.github/settings.yml deleted file mode 100644 index 1019e26f..00000000 --- a/.github/settings.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -_extends: '.github:npm-cli/settings.yml' diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml new file mode 100644 index 00000000..1e35e279 --- /dev/null +++ b/.github/workflows/audit.yml @@ -0,0 +1,27 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Audit + +on: + workflow_dispatch: + schedule: + # "At 01:00 on Monday" https://crontab.guru/#0_1_*_*_1 + - cron: "0 1 * * 1" + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup git user + run: | + git config --global user.email "ops+robot@npmjs.com" + git config --global user.name "npm team" + - uses: actions/setup-node@v3 + with: + node-version: 16.x + - name: Update npm to latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - run: npm -v + - run: npm i --ignore-scripts --no-audit --no-fund --package-lock + - run: npm audit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 41c8c318..c8014892 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,42 +1,85 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + name: CI -on: [push, pull_request] +on: + workflow_dispatch: + pull_request: + branches: + - '*' + push: + branches: + - main + - latest + schedule: + # "At 02:00 on Monday" https://crontab.guru/#0_2_*_*_1 + - cron: "0 2 * * 1" jobs: - build: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup git user + run: | + git config --global user.email "ops+robot@npmjs.com" + git config --global user.name "npm team" + - uses: actions/setup-node@v3 + with: + node-version: 16.x + - name: Update npm to latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - run: npm -v + - run: npm i --ignore-scripts --no-audit --no-fund + - run: npm run lint + + test: strategy: + fail-fast: false matrix: - node-version: [10.x, 12.x, 14.x, 16.x] + node-version: + - 10.0.0 + - 10.x + - 12.x + - 14.x + - 16.x platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: powershell - - fail-fast: false - + - os: ubuntu-latest + shell: bash + - os: macos-latest + shell: bash + - os: windows-latest + shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} - steps: - # there are files here that make windows unhappy by default - - name: Support longpaths - run: git config --global core.longpaths true - - - name: Checkout Repository - uses: actions/checkout@v1.1.0 - - - name: Use Nodejs ${{ matrix.node-version }} - uses: actions/setup-node@v1 + - uses: actions/checkout@v3 + - name: Setup git user + run: | + git config --global user.email "ops+robot@npmjs.com" + git config --global user.name "npm team" + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - - name: Install dependencies - run: npm install - - - name: Run Tap Tests - run: npm test -- -c -t0 + - name: Update to workable npm (windows) + # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows + if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) + run: | + curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz + tar xf npm-7.5.4.tgz + cd package + node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz + cd .. + rmdir /s /q package + - name: Update npm to 7 + # If we do test on npm 10 it needs npm7 + if: startsWith(matrix.node-version, '10.') + run: npm i --prefer-online --no-fund --no-audit -g npm@7 + - name: Update npm to latest + if: ${{ !startsWith(matrix.node-version, '10.') }} + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - run: npm -v + - run: npm i --ignore-scripts --no-audit --no-fund + - run: npm test --ignore-scripts diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 7a99ab09..2fbb6309 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,24 +1,20 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# +# This file is automatically added by @npmcli/template-oss. Do not edit. + name: "CodeQL" on: push: - branches: [ main ] + branches: + - main + - latest pull_request: # The branches below must be a subset of the branches above - branches: [ main ] + branches: + - main + - latest schedule: - - cron: '27 20 * * 4' + # "At 03:00 on Monday" https://crontab.guru/#0_3_*_*_1 + - cron: "0 3 * * 1" jobs: analyze: @@ -32,40 +28,17 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'javascript' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + language: [ javascript ] steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - uses: actions/checkout@v3 + - name: Setup git user + run: | + git config --global user.email "ops+robot@npmjs.com" + git config --global user.name "npm team" + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml new file mode 100644 index 00000000..94f5a8fd --- /dev/null +++ b/.github/workflows/post-dependabot.yml @@ -0,0 +1,43 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Post Dependabot Actions + +on: pull_request + +# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions +permissions: + contents: write + +jobs: + template-oss-apply: + runs-on: ubuntu-latest + if: github.actor == 'dependabot[bot]' + steps: + - uses: actions/checkout@v3 + - name: Setup git user + run: | + git config --global user.email "ops+robot@npmjs.com" + git config --global user.name "npm team" + - uses: actions/setup-node@v3 + with: + node-version: 16.x + - name: Update npm to latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - run: npm -v + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v1.1.1 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + - name: npm install and commit + if: contains(steps.metadata.outputs.dependency-names, '@npmcli/template-oss') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr checkout ${{ github.event.pull_request.number }} + npm install --ignore-scripts --no-audit --no-fund + npm run template-oss-apply + git add . + git commit -am "chore: postinstall for dependabot template-oss PR" + git push + npm run lint diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 00000000..d2bc7dab --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,38 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Pull Request Linting + +on: + pull_request: + types: + - opened + - reopened + - edited + - synchronize + +jobs: + check: + name: Check PR Title or Commits + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup git user + run: | + git config --global user.email "ops+robot@npmjs.com" + git config --global user.name "npm team" + - uses: actions/setup-node@v3 + with: + node-version: 16.x + - name: Update npm to latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - run: npm -v + - name: Install deps + run: npm i -D @commitlint/cli @commitlint/config-conventional + - name: Check commits OR PR title + env: + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + npx --offline commitlint -V --from origin/main --to ${{ github.event.pull_request.head.sha }} \ + || echo $PR_TITLE | npx --offline commitlint -V diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 00000000..ab3a9105 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,26 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Release Please + +on: + push: + branches: + - main + - latest + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: google-github-actions/release-please-action@v3 + id: release + with: + release-type: node + changelog-types: > + [ + {"type":"feat","section":"Features","hidden":false}, + {"type":"fix","section":"Bug Fixes","hidden":false}, + {"type":"docs","section":"Documentation","hidden":false}, + {"type":"deps","section":"Dependencies","hidden":false}, + {"type":"chore","hidden":true} + ] diff --git a/.gitignore b/.gitignore index 9f69fbf7..6066eaa0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,25 @@ -# ignore most things, include some others -/* -/.* +# This file is automatically added by @npmcli/template-oss. Do not edit. -!bin/ -!lib/ -!docs/ -!package.json -!package-lock.json -!README.md -!CONTRIBUTING.md -!LICENSE -!CHANGELOG.md -!example/ -!scripts/ -!tap-snapshots/ -!test/ -!.travis.yml -!.gitignore -!.gitattributes -!map.js -!index.js -!.github -!.eslintrc.json +# ignore everything in the root +/* -.*.swp -node_modules/ -test/fixtures/unpack -benchmarks/ +# keep these +!/.eslintrc.local.* +!**/.gitignore +!/docs/ +!/tap-snapshots/ +!/test/ +!/map.js +!/scripts/ +!/README* +!/LICENSE* +!/CHANGELOG* +!/.commitlintrc.js +!/.eslintrc.js +!/.github/ +!/.gitignore +!/.npmrc +!/SECURITY.md +!/index.js +!/lib/ +!/package.json diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..529f93e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1,3 @@ +; This file is automatically added by @npmcli/template-oss. Do not edit. + +package-lock=false diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..a93106d0 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +<!-- This file is automatically added by @npmcli/template-oss. Do not edit. --> + +Please send vulnerability reports through [hackerone](https://hackerone.com/github). diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 535aa04b..00000000 --- a/package-lock.json +++ /dev/null @@ -1,12411 +0,0 @@ -{ - "name": "tar", - "version": "6.1.11", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "version": "6.1.11", - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "devDependencies": { - "chmodr": "^1.2.0", - "end-of-stream": "^1.4.3", - "eslint": "^7.17.0", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^4.2.1", - "eslint-plugin-standard": "^5.0.0", - "events-to-array": "^1.1.2", - "mutate-fs": "^2.1.1", - "rimraf": "^2.7.1", - "tap": "^15.0.9", - "tar-fs": "^1.16.3", - "tar-stream": "^1.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", - "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.0", - "@babel/helper-module-transforms": "^7.15.0", - "@babel/helpers": "^7.14.8", - "@babel/parser": "^7.15.0", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", - "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz", - "integrity": "sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", - "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", - "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", - "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", - "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", - "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", - "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.0", - "@babel/helper-simple-access": "^7.14.8", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", - "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", - "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", - "dev": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.15.0", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", - "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.14.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.8.tgz", - "integrity": "sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.8", - "@babel/types": "^7.14.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.0.tgz", - "integrity": "sha512-0v7oNOjr6YT9Z2RAOTv4T9aP+ubfx4Q/OhVtAet7PFDt0t9Oy6Jn+/rfC6b8HJ5zEqrQCiMxJfgtHpmIminmJQ==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz", - "integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.14.7", - "@babel/helper-compilation-targets": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz", - "integrity": "sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", - "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz", - "integrity": "sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.9.tgz", - "integrity": "sha512-30PeETvS+AeD1f58i1OVyoDlVYQhap/K20ZrMjLmmzmC2AYR/G43D4sdJAaDAqCD3MYpSWbmrz3kES158QSLjw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-jsx": "^7.14.5", - "@babel/types": "^7.14.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", - "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template/node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", - "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.15.0", - "@babel/types": "^7.15.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", - "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.9", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "dependencies": { - "default-require-extensions": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-includes": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", - "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async-hook-domain": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-2.0.3.tgz", - "integrity": "sha512-MadiLLDEZRZzZwcm0dgS+K99qXZ4H2saAUwUgwzFulbAkXrKi3AX5FvWS3FFTQtLMwrqcGqAJe6o12KrObejQA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bind-obj-methods": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bind-obj-methods/-/bind-obj-methods-3.0.0.tgz", - "integrity": "sha512-nLEaaz3/sEzNSyPWRsN9HNsqwk1AUyECtGj+XwGdIi3xABnEqecvXtIJ0wehQXuuER5uZ/5fTs2usONgYjG+iw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/bl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", - "dev": true, - "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.16.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.7.tgz", - "integrity": "sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA==", - "dev": true, - "dependencies": { - "caniuse-lite": "^1.0.30001248", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.793", - "escalade": "^3.1.1", - "node-releases": "^1.1.73" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "dev": true, - "dependencies": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "node_modules/buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "dev": true - }, - "node_modules/buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", - "dev": true - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "dependencies": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-callsite/node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001249", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001249.tgz", - "integrity": "sha512-vcX4U8lwVXPdqzPWi6cAJ3FnQaqXbBqy/GZseKNQzRj37J7qZdGcBtxq/QLFNLLlfsoXLUdHw8Iwenri86Tagw==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chmodr": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/chmodr/-/chmodr-1.2.0.tgz", - "integrity": "sha512-Y5uI7Iq/Az6HgJEL6pdw7THVd7jbVOTPwsmcPOBjQL8e3N+pz872kzK5QxYGEy21iRys+iHWV0UZQXDFJo1hyA==", - "dev": true - }, - "node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "dependencies": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/coveralls": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.1.tgz", - "integrity": "sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==", - "dev": true, - "dependencies": { - "js-yaml": "^3.13.1", - "lcov-parse": "^1.0.0", - "log-driver": "^1.2.7", - "minimist": "^1.2.5", - "request": "^2.88.2" - }, - "bin": { - "coveralls": "bin/coveralls.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "node_modules/default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", - "dev": true, - "dependencies": { - "strip-bom": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/default-require-extensions/node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.3.798", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.798.tgz", - "integrity": "sha512-fwsr6oXAORoV9a6Ak2vMCdXfmHIpAGgpOGesulS1cbGgJmrMl3H+GicUyRG3t+z9uHTMrIuMTleFDW+EUFYT3g==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", - "dev": true, - "dependencies": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-module-utils": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", - "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "pkg-dir": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", - "dev": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.23.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", - "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.3", - "array.prototype.flat": "^1.2.4", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.4", - "eslint-module-utils": "^2.6.1", - "find-up": "^2.0.0", - "has": "^1.0.3", - "is-core-module": "^2.4.0", - "minimatch": "^3.0.4", - "object.values": "^1.1.3", - "pkg-up": "^2.0.0", - "read-pkg-up": "^3.0.0", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.9.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, - "dependencies": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "peerDependencies": { - "eslint": ">=5.16.0" - } - }, - "node_modules/eslint-plugin-node/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint-plugin-node/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-promise": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz", - "integrity": "sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-plugin-standard": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-5.0.0.tgz", - "integrity": "sha512-eSIXPc9wBM4BrniMzJRBm2uoVuXz2EPa+NXPk2+itrVt+r5SbKFERx/IgrK/HmfjddyKVz2f+j+7gBRvu19xLg==", - "deprecated": "standard 16.0.0 and eslint-config-standard 16.0.0 no longer require the eslint-plugin-standard package. You can remove it from your dependencies with 'npm rm eslint-plugin-standard'. More info here: https://github.com/standard/standard/issues/1316", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peerDependencies": { - "eslint": ">=5.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/events-to-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", - "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=", - "dev": true - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-cache-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-cache-dir/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/findit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", - "integrity": "sha1-ZQnwEmr0wXhVHPqZOU4DLhOk1W4=", - "dev": true - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "node_modules/fs-exists-cached": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz", - "integrity": "sha1-zyVVTKBQ3EmuZla0HeQiWJidy84=", - "dev": true - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/function-loop": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-2.0.1.tgz", - "integrity": "sha512-ktIR+O6i/4h+j/ZhZJNdzeI4i9lEPeEK6UPR2EVyTVBqOwcU3Za9xYKLH64ZR9HmcROyRrOkizNyjjtWJzDDkQ==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", - "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "dependencies": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hasha/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-jsx": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-jsx/-/import-jsx-4.0.0.tgz", - "integrity": "sha512-CnjJ2BZFJzbFDmYG5S47xPQjMlSbZLyLJuG4znzL4TdPtJBxHtFP1xVmR+EYX4synFSldiY3B6m00XkPM3zVnA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.5.5", - "@babel/plugin-proposal-object-rest-spread": "^7.5.5", - "@babel/plugin-transform-destructuring": "^7.5.0", - "@babel/plugin-transform-react-jsx": "^7.3.0", - "caller-path": "^2.0.0", - "find-cache-dir": "^3.2.0", - "make-dir": "^3.0.2", - "resolve-from": "^3.0.0", - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/import-jsx/node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-jsx/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", - "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "dependencies": { - "append-transform": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-processinfo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", - "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", - "dev": true, - "dependencies": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.0", - "istanbul-lib-coverage": "^3.0.0-alpha.1", - "make-dir": "^3.0.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^3.3.3" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jackspeak": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.0.tgz", - "integrity": "sha512-VDcSunT+wcccoG46FtzuBAyQKlzhHjli4q31e1fIHGOsRspqNUFjVzGb+7eIFDlTvqLygxapDHPHS0ouT2o/tw==", - "dev": true, - "dependencies": { - "cliui": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "node_modules/lcov-parse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", - "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", - "dev": true, - "bin": { - "lcov-parse": "bin/cli.js" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/libtap": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/libtap/-/libtap-1.1.1.tgz", - "integrity": "sha512-Fye8fh1+G7E8qqmjQaY+pXGxy7HM0S6bqCCJFLa16+g2jODBByxbJFDpjbDNF69wfRVyvJ+foLZc1WTIv7dx+g==", - "dev": true, - "dependencies": { - "async-hook-domain": "^2.0.1", - "bind-obj-methods": "^3.0.0", - "diff": "^4.0.2", - "function-loop": "^2.0.1", - "minipass": "^3.1.1", - "own-or": "^1.0.0", - "own-or-env": "^1.0.1", - "signal-exit": "^3.0.2", - "stack-utils": "^2.0.1", - "tap-parser": "^10.0.1", - "tap-yaml": "^1.0.0", - "tcompare": "^5.0.1", - "trivial-deferred": "^1.0.1", - "yapool": "^1.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "node_modules/log-driver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", - "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", - "dev": true, - "engines": { - "node": ">=0.8.6" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/mime-db": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", - "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.32", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", - "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", - "dev": true, - "dependencies": { - "mime-db": "1.49.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mutate-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mutate-fs/-/mutate-fs-2.1.1.tgz", - "integrity": "sha512-WI5pPPUNiWqaK2XdK94AVpxIc8GmZEXYlLfFbWuc4gUtBGHTK92jdPqFdx/lilxgb5Ep7tQ15NqCcJEOeq6wdA==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "dependencies": { - "process-on-spawn": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-releases": { - "version": "1.1.73", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", - "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/nyc/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nyc/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "dev": true, - "bin": { - "opener": "bin/opener-bin.js" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/own-or": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/own-or/-/own-or-1.0.0.tgz", - "integrity": "sha1-Tod/vtqaLsgAD7wLyuOWRe6L+Nw=", - "dev": true - }, - "node_modules/own-or-env": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-or-env/-/own-or-env-1.0.1.tgz", - "integrity": "sha512-y8qULRbRAlL6x2+M0vIe7jJbJx/kmUTzYonRAa2ayesR2qWLswninkVyeJe4x3IEXhdgoNodzjQRKAoEs6Fmrw==", - "dev": true, - "dependencies": { - "own-or": "^1.0.0" - } - }, - "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "dependencies": { - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", - "dev": true, - "dependencies": { - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "dependencies": { - "fromentries": "^1.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/pump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", - "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", - "dev": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", - "dev": true, - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "dependencies": { - "es6-error": "^4.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "dependencies": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/spawn-wrap/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", - "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", - "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/tap": { - "version": "15.0.9", - "resolved": "https://registry.npmjs.org/tap/-/tap-15.0.9.tgz", - "integrity": "sha512-bqY5SxEqYKRd37PIUfKBf9HMs/hklyl/fGXkuStr9rYTIGa0/icpSLsm6IVOmx2qT0/TliPNJ6OvS5kddJYHdg==", - "bundleDependencies": [ - "ink", - "treport", - "@types/react" - ], - "dev": true, - "dependencies": { - "@types/react": "^16.9.23", - "chokidar": "^3.3.0", - "coveralls": "^3.0.11", - "findit": "^2.0.0", - "foreground-child": "^2.0.0", - "fs-exists-cached": "^1.0.0", - "glob": "^7.1.6", - "import-jsx": "^4.0.0", - "ink": "^2.7.1", - "isexe": "^2.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "jackspeak": "^1.4.0", - "libtap": "^1.1.1", - "minipass": "^3.1.1", - "mkdirp": "^1.0.4", - "nyc": "^15.1.0", - "opener": "^1.5.1", - "react": "^16.12.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.0", - "source-map-support": "^0.5.16", - "tap-mocha-reporter": "^5.0.0", - "tap-parser": "^10.0.1", - "tap-yaml": "^1.0.0", - "tcompare": "^5.0.6", - "treport": "^2.0.2", - "which": "^2.0.2" - }, - "bin": { - "tap": "bin/run.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "peerDependencies": { - "flow-remove-types": ">=2.112.0", - "ts-node": ">=8.5.2", - "typescript": ">=3.7.2" - }, - "peerDependenciesMeta": { - "flow-remove-types": { - "optional": true - }, - "ts-node": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/tap-mocha-reporter": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-5.0.1.tgz", - "integrity": "sha512-1knFWOwd4khx/7uSEnUeaP9IPW3w+sqTgJMhrwah6t46nZ8P25atOKAjSvVDsT67lOPu0nfdOqUwoyKn+3E5pA==", - "dev": true, - "dependencies": { - "color-support": "^1.1.0", - "debug": "^4.1.1", - "diff": "^4.0.1", - "escape-string-regexp": "^2.0.0", - "glob": "^7.0.5", - "tap-parser": "^10.0.0", - "tap-yaml": "^1.0.0", - "unicode-length": "^2.0.2" - }, - "bin": { - "tap-mocha-reporter": "index.js" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tap-mocha-reporter/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-10.1.0.tgz", - "integrity": "sha512-FujQeciDaOiOvaIVGS1Rpb0v4R6XkOjvWCWowlz5oKuhPkEJ8U6pxgqt38xuzYhPt8dWEnfHn2jqpZdJEkW7pA==", - "dev": true, - "dependencies": { - "events-to-array": "^1.0.1", - "minipass": "^3.0.0", - "tap-yaml": "^1.0.0" - }, - "bin": { - "tap-parser": "bin/cmd.js" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tap-yaml": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.0.tgz", - "integrity": "sha512-Rxbx4EnrWkYk0/ztcm5u3/VznbyFJpyXO12dDBHKWiDVxy7O2Qw6MRrwO5H6Ww0U5YhRY/4C/VzWmFPhBQc4qQ==", - "dev": true, - "dependencies": { - "yaml": "^1.5.0" - } - }, - "node_modules/tap/node_modules/@babel/code-frame": { - "version": "7.12.13", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.12.13" - } - }, - "node_modules/tap/node_modules/@babel/compat-data": { - "version": "7.14.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/@babel/core": { - "version": "7.14.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.14.0", - "@babel/helper-compilation-targets": "^7.13.16", - "@babel/helper-module-transforms": "^7.14.0", - "@babel/helpers": "^7.14.0", - "@babel/parser": "^7.14.0", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.14.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/tap/node_modules/@babel/generator": { - "version": "7.14.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.14.1", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.12.13", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.12.13" - } - }, - "node_modules/tap/node_modules/@babel/helper-compilation-targets": { - "version": "7.13.16", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.13.15", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", - "semver": "^6.3.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-function-name": { - "version": "7.12.13", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "node_modules/tap/node_modules/@babel/helper-get-function-arity": { - "version": "7.12.13", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.12.13" - } - }, - "node_modules/tap/node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.13.12", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.13.12" - } - }, - "node_modules/tap/node_modules/@babel/helper-module-imports": { - "version": "7.13.12", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.13.12" - } - }, - "node_modules/tap/node_modules/@babel/helper-module-transforms": { - "version": "7.14.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-replace-supers": "^7.13.12", - "@babel/helper-simple-access": "^7.13.12", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.14.0", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.14.0" - } - }, - "node_modules/tap/node_modules/@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.12.13" - } - }, - "node_modules/tap/node_modules/@babel/helper-plugin-utils": { - "version": "7.13.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/@babel/helper-replace-supers": { - "version": "7.13.12", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.13.12", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" - } - }, - "node_modules/tap/node_modules/@babel/helper-simple-access": { - "version": "7.13.12", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.13.12" - } - }, - "node_modules/tap/node_modules/@babel/helper-split-export-declaration": { - "version": "7.12.13", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.12.13" - } - }, - "node_modules/tap/node_modules/@babel/helper-validator-identifier": { - "version": "7.14.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/@babel/helper-validator-option": { - "version": "7.12.17", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/@babel/helpers": { - "version": "7.14.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.14.0" - } - }, - "node_modules/tap/node_modules/@babel/highlight": { - "version": "7.14.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/tap/node_modules/@babel/parser": { - "version": "7.14.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.13.8", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.13.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.12.13", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-transform-destructuring": { - "version": "7.13.17", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-transform-parameters": { - "version": "7.13.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.13.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.13.12", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-jsx": "^7.12.13", - "@babel/types": "^7.13.12" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/tap/node_modules/@babel/template": { - "version": "7.12.13", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "node_modules/tap/node_modules/@babel/traverse": { - "version": "7.14.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.14.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.14.0", - "@babel/types": "^7.14.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "node_modules/tap/node_modules/@babel/types": { - "version": "7.14.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.0", - "to-fast-properties": "^2.0.0" - } - }, - "node_modules/tap/node_modules/@types/prop-types": { - "version": "15.7.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/@types/react": { - "version": "16.14.6", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/tap/node_modules/@types/scheduler": { - "version": "0.16.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/@types/yoga-layout": { - "version": "1.9.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/ansi-escapes": { - "version": "4.3.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/ansi-styles": { - "version": "3.2.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/ansicolors": { - "version": "0.3.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/arrify": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/astral-regex": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/auto-bind": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/tap/node_modules/browserslist": { - "version": "4.16.6", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/tap/node_modules/caller-callsite": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/caller-path": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/callsites": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/caniuse-lite": { - "version": "1.0.30001223", - "dev": true, - "inBundle": true, - "license": "CC-BY-4.0" - }, - "node_modules/tap/node_modules/cardinal": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansicolors": "~0.3.2", - "redeyed": "~2.1.0" - }, - "bin": { - "cdl": "bin/cdl.js" - } - }, - "node_modules/tap/node_modules/chalk": { - "version": "2.4.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/ci-info": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/cli-cursor": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/cli-truncate": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/color-convert": { - "version": "1.9.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/tap/node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/colorette": { - "version": "1.2.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/commondir": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/convert-source-map": { - "version": "1.7.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/tap/node_modules/csstype": { - "version": "3.0.8", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/debug": { - "version": "4.3.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/tap/node_modules/electron-to-chromium": { - "version": "1.3.727", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/escalade": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/tap/node_modules/esprima": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/events-to-array": { - "version": "1.1.2", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/find-cache-dir": { - "version": "3.3.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/tap/node_modules/find-up": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/gensync": { - "version": "1.0.0-beta.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/tap/node_modules/glob": { - "version": "7.1.7", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/tap/node_modules/globals": { - "version": "11.12.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/has-flag": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/import-jsx": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.5.5", - "@babel/plugin-proposal-object-rest-spread": "^7.5.5", - "@babel/plugin-transform-destructuring": "^7.5.0", - "@babel/plugin-transform-react-jsx": "^7.3.0", - "caller-path": "^2.0.0", - "find-cache-dir": "^3.2.0", - "make-dir": "^3.0.2", - "resolve-from": "^3.0.0", - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tap/node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/tap/node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/ink": { - "version": "2.7.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^4.2.1", - "arrify": "^2.0.1", - "auto-bind": "^4.0.0", - "chalk": "^3.0.0", - "cli-cursor": "^3.1.0", - "cli-truncate": "^2.1.0", - "is-ci": "^2.0.0", - "lodash.throttle": "^4.1.1", - "log-update": "^3.0.0", - "prop-types": "^15.6.2", - "react-reconciler": "^0.24.0", - "scheduler": "^0.18.0", - "signal-exit": "^3.0.2", - "slice-ansi": "^3.0.0", - "string-length": "^3.1.0", - "widest-line": "^3.1.0", - "wrap-ansi": "^6.2.0", - "yoga-layout-prebuilt": "^1.9.3" - }, - "engines": { - "node": ">=8" - }, - "peerDependencies": { - "@types/react": ">=16.8.0", - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/tap/node_modules/ink/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/tap/node_modules/ink/node_modules/chalk": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/ink/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/tap/node_modules/ink/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/ink/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/ink/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/is-ci": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/tap/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/js-tokens": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/jsesc": { - "version": "2.5.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/json5": { - "version": "2.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/locate-path": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/lodash.throttle": { - "version": "4.1.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/log-update": { - "version": "3.4.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^3.2.0", - "cli-cursor": "^2.1.0", - "wrap-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/log-update/node_modules/ansi-escapes": { - "version": "3.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/log-update/node_modules/ansi-regex": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/log-update/node_modules/cli-cursor": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/log-update/node_modules/emoji-regex": { - "version": "7.0.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/log-update/node_modules/mimic-fn": { - "version": "1.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/log-update/node_modules/onetime": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/log-update/node_modules/restore-cursor": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/log-update/node_modules/string-width": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/log-update/node_modules/strip-ansi": { - "version": "5.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/log-update/node_modules/wrap-ansi": { - "version": "5.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/loose-envify": { - "version": "1.4.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/tap/node_modules/make-dir": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/mimic-fn": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/minimatch": { - "version": "3.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tap/node_modules/minimist": { - "version": "1.2.5", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/minipass": { - "version": "3.1.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/ms": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/node-releases": { - "version": "1.1.71", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/object-assign": { - "version": "4.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap/node_modules/once": { - "version": "1.4.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/tap/node_modules/onetime": { - "version": "5.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/p-limit": { - "version": "2.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/p-locate": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/p-try": { - "version": "2.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap/node_modules/pkg-dir": { - "version": "4.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/prop-types": { - "version": "15.7.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "node_modules/tap/node_modules/punycode": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/react-is": { - "version": "16.13.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/react-reconciler": { - "version": "0.24.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.18.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "react": "^16.0.0" - } - }, - "node_modules/tap/node_modules/redeyed": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "esprima": "~4.0.0" - } - }, - "node_modules/tap/node_modules/resolve-from": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/restore-cursor": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/tap/node_modules/safe-buffer": { - "version": "5.1.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/scheduler": { - "version": "0.18.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/tap/node_modules/semver": { - "version": "6.3.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/tap/node_modules/signal-exit": { - "version": "3.0.3", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/slice-ansi": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/tap/node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/tap/node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/source-map": { - "version": "0.5.7", - "dev": true, - "inBundle": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap/node_modules/string-length": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "astral-regex": "^1.0.0", - "strip-ansi": "^5.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/string-length/node_modules/ansi-regex": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/string-length/node_modules/astral-regex": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/string-length/node_modules/strip-ansi": { - "version": "5.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tap/node_modules/string-width": { - "version": "4.2.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/string-width/node_modules/ansi-regex": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/supports-color": { - "version": "5.5.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/tap-parser": { - "version": "10.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "events-to-array": "^1.0.1", - "minipass": "^3.0.0", - "tap-yaml": "^1.0.0" - }, - "bin": { - "tap-parser": "bin/cmd.js" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tap/node_modules/tap-yaml": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yaml": "^1.5.0" - } - }, - "node_modules/tap/node_modules/to-fast-properties": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/tap/node_modules/treport": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "cardinal": "^2.1.1", - "chalk": "^3.0.0", - "import-jsx": "^4.0.0", - "ink": "^2.6.0", - "ms": "^2.1.2", - "string-length": "^3.1.0", - "tap-parser": "^10.0.1", - "unicode-length": "^2.0.2" - }, - "peerDependencies": { - "react": "^16.8.6" - } - }, - "node_modules/tap/node_modules/treport/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/tap/node_modules/treport/node_modules/chalk": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/treport/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/tap/node_modules/treport/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/treport/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/treport/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/type-fest": { - "version": "0.21.3", - "dev": true, - "inBundle": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tap/node_modules/unicode-length": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.0.0", - "strip-ansi": "^3.0.1" - } - }, - "node_modules/tap/node_modules/unicode-length/node_modules/ansi-regex": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap/node_modules/unicode-length/node_modules/strip-ansi": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tap/node_modules/widest-line": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/wrap-ansi": { - "version": "6.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/tap/node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/tap/node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/tap/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tap/node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/tap/node_modules/yaml": { - "version": "1.10.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/tap/node_modules/yoga-layout-prebuilt": { - "version": "1.10.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "@types/yoga-layout": "1.9.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar-fs": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", - "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", - "dev": true, - "dependencies": { - "chownr": "^1.0.1", - "mkdirp": "^0.5.1", - "pump": "^1.0.0", - "tar-stream": "^1.1.2" - } - }, - "node_modules/tar-fs/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "node_modules/tar-fs/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "dev": true, - "dependencies": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/tcompare": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-5.0.6.tgz", - "integrity": "sha512-OvO7omN/wkdsKzmOqr3sQFfLbghs/2X5mwSkcfgRiXZshfPnTsAs3IRf1RixR/Pff26qG/r9ogcZMpV0YdeGXg==", - "dev": true, - "dependencies": { - "diff": "^4.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/trivial-deferred": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-1.0.1.tgz", - "integrity": "sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM=", - "dev": true - }, - "node_modules/tsconfig-paths": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz", - "integrity": "sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==", - "dev": true, - "dependencies": { - "json5": "^2.2.0", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unicode-length": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unicode-length/-/unicode-length-2.0.2.tgz", - "integrity": "sha512-Ph/j1VbS3/r77nhoY2WU0GWGjVYOHL3xpKp0y/Eq2e5r0mT/6b649vm7KFO6RdAdrZkYLdxphYVgvODxPB+Ebg==", - "dev": true, - "dependencies": { - "punycode": "^2.0.0", - "strip-ansi": "^3.0.1" - } - }, - "node_modules/unicode-length/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unicode-length/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/yapool": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yapool/-/yapool-1.0.0.tgz", - "integrity": "sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o=", - "dev": true - }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/yargs/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", - "dev": true - }, - "@babel/core": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", - "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-compilation-targets": "^7.15.0", - "@babel/helper-module-transforms": "^7.15.0", - "@babel/helpers": "^7.14.8", - "@babel/parser": "^7.15.0", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", - "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", - "dev": true, - "requires": { - "@babel/types": "^7.15.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz", - "integrity": "sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", - "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", - "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", - "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", - "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", - "dev": true, - "requires": { - "@babel/types": "^7.15.0" - } - }, - "@babel/helper-module-imports": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", - "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-module-transforms": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", - "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.0", - "@babel/helper-simple-access": "^7.14.8", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", - "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", - "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.15.0", - "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.15.0", - "@babel/types": "^7.15.0" - } - }, - "@babel/helper-simple-access": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", - "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", - "dev": true, - "requires": { - "@babel/types": "^7.14.8" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", - "dev": true - }, - "@babel/helpers": { - "version": "7.14.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.8.tgz", - "integrity": "sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw==", - "dev": true, - "requires": { - "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.8", - "@babel/types": "^7.14.8" - } - }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.0.tgz", - "integrity": "sha512-0v7oNOjr6YT9Z2RAOTv4T9aP+ubfx4Q/OhVtAet7PFDt0t9Oy6Jn+/rfC6b8HJ5zEqrQCiMxJfgtHpmIminmJQ==", - "dev": true - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz", - "integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.14.7", - "@babel/helper-compilation-targets": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.14.5" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz", - "integrity": "sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", - "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz", - "integrity": "sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.9.tgz", - "integrity": "sha512-30PeETvS+AeD1f58i1OVyoDlVYQhap/K20ZrMjLmmzmC2AYR/G43D4sdJAaDAqCD3MYpSWbmrz3kES158QSLjw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-jsx": "^7.14.5", - "@babel/types": "^7.14.9" - } - }, - "@babel/template": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", - "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - } - } - }, - "@babel/traverse": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", - "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.15.0", - "@babel/types": "^7.15.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", - "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.9", - "to-fast-properties": "^2.0.0" - } - }, - "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - } - }, - "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "requires": { - "default-require-extensions": "^3.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-includes": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", - "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.5" - } - }, - "array.prototype.flat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - } - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "async-hook-domain": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-2.0.3.tgz", - "integrity": "sha512-MadiLLDEZRZzZwcm0dgS+K99qXZ4H2saAUwUgwzFulbAkXrKi3AX5FvWS3FFTQtLMwrqcGqAJe6o12KrObejQA==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "bind-obj-methods": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bind-obj-methods/-/bind-obj-methods-3.0.0.tgz", - "integrity": "sha512-nLEaaz3/sEzNSyPWRsN9HNsqwk1AUyECtGj+XwGdIi3xABnEqecvXtIJ0wehQXuuER5uZ/5fTs2usONgYjG+iw==", - "dev": true - }, - "bl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", - "dev": true, - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.16.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.7.tgz", - "integrity": "sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001248", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.793", - "escalade": "^3.1.1", - "node-releases": "^1.1.73" - } - }, - "buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "dev": true, - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "dev": true - }, - "buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", - "dev": true - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "requires": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - } - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001249", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001249.tgz", - "integrity": "sha512-vcX4U8lwVXPdqzPWi6cAJ3FnQaqXbBqy/GZseKNQzRj37J7qZdGcBtxq/QLFNLLlfsoXLUdHw8Iwenri86Tagw==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chmodr": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/chmodr/-/chmodr-1.2.0.tgz", - "integrity": "sha512-Y5uI7Iq/Az6HgJEL6pdw7THVd7jbVOTPwsmcPOBjQL8e3N+pz872kzK5QxYGEy21iRys+iHWV0UZQXDFJo1hyA==", - "dev": true - }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true - }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "coveralls": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.1.tgz", - "integrity": "sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww==", - "dev": true, - "requires": { - "js-yaml": "^3.13.1", - "lcov-parse": "^1.0.0", - "log-driver": "^1.2.7", - "minimist": "^1.2.5", - "request": "^2.88.2" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", - "dev": true, - "requires": { - "strip-bom": "^4.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - } - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "electron-to-chromium": { - "version": "1.3.798", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.798.tgz", - "integrity": "sha512-fwsr6oXAORoV9a6Ak2vMCdXfmHIpAGgpOGesulS1cbGgJmrMl3H+GicUyRG3t+z9uHTMrIuMTleFDW+EUFYT3g==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-module-utils": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", - "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "pkg-dir": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", - "dev": true, - "requires": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - } - }, - "eslint-plugin-import": { - "version": "2.23.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", - "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", - "dev": true, - "requires": { - "array-includes": "^3.1.3", - "array.prototype.flat": "^1.2.4", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.4", - "eslint-module-utils": "^2.6.1", - "find-up": "^2.0.0", - "has": "^1.0.3", - "is-core-module": "^2.4.0", - "minimatch": "^3.0.4", - "object.values": "^1.1.3", - "pkg-up": "^2.0.0", - "read-pkg-up": "^3.0.0", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.9.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, - "requires": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "eslint-plugin-promise": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz", - "integrity": "sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==", - "dev": true - }, - "eslint-plugin-standard": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-5.0.0.tgz", - "integrity": "sha512-eSIXPc9wBM4BrniMzJRBm2uoVuXz2EPa+NXPk2+itrVt+r5SbKFERx/IgrK/HmfjddyKVz2f+j+7gBRvu19xLg==", - "dev": true, - "requires": {} - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "events-to-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", - "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=", - "dev": true - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - } - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "findit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", - "integrity": "sha1-ZQnwEmr0wXhVHPqZOU4DLhOk1W4=", - "dev": true - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "fs-exists-cached": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz", - "integrity": "sha1-zyVVTKBQ3EmuZla0HeQiWJidy84=", - "dev": true - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "requires": { - "minipass": "^3.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "function-loop": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-2.0.1.tgz", - "integrity": "sha512-ktIR+O6i/4h+j/ZhZJNdzeI4i9lEPeEK6UPR2EVyTVBqOwcU3Za9xYKLH64ZR9HmcROyRrOkizNyjjtWJzDDkQ==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", - "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "requires": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "dependencies": { - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-jsx": { - "version": "https://registry.npmjs.org/import-jsx/-/import-jsx-4.0.0.tgz", - "integrity": "sha512-CnjJ2BZFJzbFDmYG5S47xPQjMlSbZLyLJuG4znzL4TdPtJBxHtFP1xVmR+EYX4synFSldiY3B6m00XkPM3zVnA==", - "dev": true, - "requires": { - "@babel/core": "^7.5.5", - "@babel/plugin-proposal-object-rest-spread": "^7.5.5", - "@babel/plugin-transform-destructuring": "^7.5.0", - "@babel/plugin-transform-react-jsx": "^7.3.0", - "caller-path": "^2.0.0", - "find-cache-dir": "^3.2.0", - "make-dir": "^3.0.2", - "resolve-from": "^3.0.0", - "rimraf": "^3.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true - }, - "is-core-module": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", - "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "requires": { - "append-transform": "^2.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-processinfo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", - "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.0", - "istanbul-lib-coverage": "^3.0.0-alpha.1", - "make-dir": "^3.0.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^3.3.3" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jackspeak": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.0.tgz", - "integrity": "sha512-VDcSunT+wcccoG46FtzuBAyQKlzhHjli4q31e1fIHGOsRspqNUFjVzGb+7eIFDlTvqLygxapDHPHS0ouT2o/tw==", - "dev": true, - "requires": { - "cliui": "^4.1.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "lcov-parse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", - "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "libtap": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/libtap/-/libtap-1.1.1.tgz", - "integrity": "sha512-Fye8fh1+G7E8qqmjQaY+pXGxy7HM0S6bqCCJFLa16+g2jODBByxbJFDpjbDNF69wfRVyvJ+foLZc1WTIv7dx+g==", - "dev": true, - "requires": { - "async-hook-domain": "^2.0.1", - "bind-obj-methods": "^3.0.0", - "diff": "^4.0.2", - "function-loop": "^2.0.1", - "minipass": "^3.1.1", - "own-or": "^1.0.0", - "own-or-env": "^1.0.1", - "signal-exit": "^3.0.2", - "stack-utils": "^2.0.1", - "tap-parser": "^10.0.1", - "tap-yaml": "^1.0.0", - "tcompare": "^5.0.1", - "trivial-deferred": "^1.0.1", - "yapool": "^1.0.0" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "log-driver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", - "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "mime-db": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", - "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==", - "dev": true - }, - "mime-types": { - "version": "2.1.32", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", - "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", - "dev": true, - "requires": { - "mime-db": "1.49.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", - "requires": { - "yallist": "^4.0.0" - } - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "mutate-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mutate-fs/-/mutate-fs-2.1.1.tgz", - "integrity": "sha512-WI5pPPUNiWqaK2XdK94AVpxIc8GmZEXYlLfFbWuc4gUtBGHTK92jdPqFdx/lilxgb5Ep7tQ15NqCcJEOeq6wdA==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "requires": { - "process-on-spawn": "^1.0.0" - } - }, - "node-releases": { - "version": "1.1.73", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", - "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "requires": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.values": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "dev": true - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "own-or": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/own-or/-/own-or-1.0.0.tgz", - "integrity": "sha1-Tod/vtqaLsgAD7wLyuOWRe6L+Nw=", - "dev": true - }, - "own-or-env": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-or-env/-/own-or-env-1.0.1.tgz", - "integrity": "sha512-y8qULRbRAlL6x2+M0vIe7jJbJx/kmUTzYonRAa2ayesR2qWLswninkVyeJe4x3IEXhdgoNodzjQRKAoEs6Fmrw==", - "dev": true, - "requires": { - "own-or": "^1.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "requires": { - "fromentries": "^1.2.0" - } - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "pump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", - "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, - "react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "requires": { - "es6-error": "^4.0.1" - } - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "requires": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", - "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.6.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", - "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "tap": { - "version": "15.0.9", - "resolved": "https://registry.npmjs.org/tap/-/tap-15.0.9.tgz", - "integrity": "sha512-bqY5SxEqYKRd37PIUfKBf9HMs/hklyl/fGXkuStr9rYTIGa0/icpSLsm6IVOmx2qT0/TliPNJ6OvS5kddJYHdg==", - "dev": true, - "requires": { - "@types/react": "^16.9.23", - "chokidar": "^3.3.0", - "coveralls": "^3.0.11", - "findit": "^2.0.0", - "foreground-child": "^2.0.0", - "fs-exists-cached": "^1.0.0", - "glob": "^7.1.6", - "import-jsx": "^4.0.0", - "ink": "^2.7.1", - "isexe": "^2.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "jackspeak": "^1.4.0", - "libtap": "^1.1.1", - "minipass": "^3.1.1", - "mkdirp": "^1.0.4", - "nyc": "^15.1.0", - "opener": "^1.5.1", - "react": "^16.12.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.0", - "source-map-support": "^0.5.16", - "tap-mocha-reporter": "^5.0.0", - "tap-parser": "^10.0.1", - "tap-yaml": "^1.0.0", - "tcompare": "^5.0.6", - "treport": "^2.0.2", - "which": "^2.0.2" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "bundled": true, - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/compat-data": { - "version": "7.14.0", - "bundled": true, - "dev": true - }, - "@babel/core": { - "version": "7.14.0", - "bundled": true, - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.14.0", - "@babel/helper-compilation-targets": "^7.13.16", - "@babel/helper-module-transforms": "^7.14.0", - "@babel/helpers": "^7.14.0", - "@babel/parser": "^7.14.0", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.14.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" - } - }, - "@babel/generator": { - "version": "7.14.1", - "bundled": true, - "dev": true, - "requires": { - "@babel/types": "^7.14.1", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.12.13", - "bundled": true, - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.13.16", - "bundled": true, - "dev": true, - "requires": { - "@babel/compat-data": "^7.13.15", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", - "semver": "^6.3.0" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "bundled": true, - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "bundled": true, - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.13.12", - "bundled": true, - "dev": true, - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-module-imports": { - "version": "7.13.12", - "bundled": true, - "dev": true, - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-module-transforms": { - "version": "7.14.0", - "bundled": true, - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-replace-supers": "^7.13.12", - "@babel/helper-simple-access": "^7.13.12", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.14.0", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.14.0" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "bundled": true, - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "bundled": true, - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.13.12", - "bundled": true, - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.13.12", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-simple-access": { - "version": "7.13.12", - "bundled": true, - "dev": true, - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "bundled": true, - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.14.0", - "bundled": true, - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.12.17", - "bundled": true, - "dev": true - }, - "@babel/helpers": { - "version": "7.14.0", - "bundled": true, - "dev": true, - "requires": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.14.0" - } - }, - "@babel/highlight": { - "version": "7.14.0", - "bundled": true, - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.14.1", - "bundled": true, - "dev": true - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.13.8", - "bundled": true, - "dev": true, - "requires": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.13.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.12.13", - "bundled": true, - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "bundled": true, - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.13.17", - "bundled": true, - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.13.0", - "bundled": true, - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.13.12", - "bundled": true, - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-jsx": "^7.12.13", - "@babel/types": "^7.13.12" - } - }, - "@babel/template": { - "version": "7.12.13", - "bundled": true, - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.14.0", - "bundled": true, - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.14.0", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.14.0", - "@babel/types": "^7.14.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.14.1", - "bundled": true, - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.0", - "to-fast-properties": "^2.0.0" - } - }, - "@types/prop-types": { - "version": "15.7.3", - "bundled": true, - "dev": true - }, - "@types/react": { - "version": "16.14.6", - "bundled": true, - "dev": true, - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/scheduler": { - "version": "0.16.1", - "bundled": true, - "dev": true - }, - "@types/yoga-layout": { - "version": "1.9.2", - "bundled": true, - "dev": true - }, - "ansi-escapes": { - "version": "4.3.2", - "bundled": true, - "dev": true, - "requires": { - "type-fest": "^0.21.3" - } - }, - "ansi-styles": { - "version": "3.2.1", - "bundled": true, - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "ansicolors": { - "version": "0.3.2", - "bundled": true, - "dev": true - }, - "arrify": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "astral-regex": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "auto-bind": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "browserslist": { - "version": "4.16.6", - "bundled": true, - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" - } - }, - "caller-callsite": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "callsites": "^2.0.0" - } - }, - "caller-path": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001223", - "bundled": true, - "dev": true - }, - "cardinal": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "ansicolors": "~0.3.2", - "redeyed": "~2.1.0" - } - }, - "chalk": { - "version": "2.4.2", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "ci-info": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-truncate": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - } - }, - "color-convert": { - "version": "1.9.3", - "bundled": true, - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "bundled": true, - "dev": true - }, - "colorette": { - "version": "1.2.2", - "bundled": true, - "dev": true - }, - "commondir": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "convert-source-map": { - "version": "1.7.0", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "csstype": { - "version": "3.0.8", - "bundled": true, - "dev": true - }, - "debug": { - "version": "4.3.1", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "electron-to-chromium": { - "version": "1.3.727", - "bundled": true, - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "bundled": true, - "dev": true - }, - "escalade": { - "version": "3.1.1", - "bundled": true, - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true, - "dev": true - }, - "esprima": { - "version": "4.0.1", - "bundled": true, - "dev": true - }, - "events-to-array": { - "version": "1.1.2", - "bundled": true, - "dev": true - }, - "find-cache-dir": { - "version": "3.3.1", - "bundled": true, - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "bundled": true, - "dev": true - }, - "glob": { - "version": "7.1.7", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globals": { - "version": "11.12.0", - "bundled": true, - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "import-jsx": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "@babel/core": "^7.5.5", - "@babel/plugin-proposal-object-rest-spread": "^7.5.5", - "@babel/plugin-transform-destructuring": "^7.5.0", - "@babel/plugin-transform-react-jsx": "^7.3.0", - "caller-path": "^2.0.0", - "find-cache-dir": "^3.2.0", - "make-dir": "^3.0.2", - "resolve-from": "^3.0.0", - "rimraf": "^3.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true - }, - "ink": { - "version": "2.7.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "arrify": "^2.0.1", - "auto-bind": "^4.0.0", - "chalk": "^3.0.0", - "cli-cursor": "^3.1.0", - "cli-truncate": "^2.1.0", - "is-ci": "^2.0.0", - "lodash.throttle": "^4.1.1", - "log-update": "^3.0.0", - "prop-types": "^15.6.2", - "react-reconciler": "^0.24.0", - "scheduler": "^0.18.0", - "signal-exit": "^3.0.2", - "slice-ansi": "^3.0.0", - "string-length": "^3.1.0", - "widest-line": "^3.1.0", - "wrap-ansi": "^6.2.0", - "yoga-layout-prebuilt": "^1.9.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "bundled": true, - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "bundled": true, - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "bundled": true, - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "is-ci": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "jsesc": { - "version": "2.5.2", - "bundled": true, - "dev": true - }, - "json5": { - "version": "2.2.0", - "bundled": true, - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "locate-path": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash.throttle": { - "version": "4.1.1", - "bundled": true, - "dev": true - }, - "log-update": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "cli-cursor": "^2.1.0", - "wrap-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "bundled": true, - "dev": true - }, - "ansi-regex": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "emoji-regex": { - "version": "7.0.3", - "bundled": true, - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "mimic-fn": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "onetime": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "string-width": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - } - } - }, - "loose-envify": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "bundled": true, - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "bundled": true, - "dev": true - }, - "minipass": { - "version": "3.1.3", - "bundled": true, - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "ms": { - "version": "2.1.2", - "bundled": true, - "dev": true - }, - "node-releases": { - "version": "1.1.71", - "bundled": true, - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "bundled": true, - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "bundled": true, - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "prop-types": { - "version": "15.7.2", - "bundled": true, - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "punycode": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "react-is": { - "version": "16.13.1", - "bundled": true, - "dev": true - }, - "react-reconciler": { - "version": "0.24.0", - "bundled": true, - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.18.0" - } - }, - "redeyed": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "esprima": "~4.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "rimraf": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true - }, - "scheduler": { - "version": "0.18.0", - "bundled": true, - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "semver": { - "version": "6.3.0", - "bundled": true, - "dev": true - }, - "signal-exit": { - "version": "3.0.3", - "bundled": true, - "dev": true - }, - "slice-ansi": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "bundled": true, - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "bundled": true, - "dev": true - } - } - }, - "source-map": { - "version": "0.5.7", - "bundled": true, - "dev": true - }, - "string-length": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^5.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "string-width": { - "version": "4.2.2", - "bundled": true, - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "bundled": true, - "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "supports-color": { - "version": "5.5.0", - "bundled": true, - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "tap-parser": { - "version": "10.1.0", - "bundled": true, - "dev": true, - "requires": { - "events-to-array": "^1.0.1", - "minipass": "^3.0.0", - "tap-yaml": "^1.0.0" - } - }, - "tap-yaml": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "yaml": "^1.5.0" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "treport": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "cardinal": "^2.1.1", - "chalk": "^3.0.0", - "import-jsx": "^4.0.0", - "ink": "^2.6.0", - "ms": "^2.1.2", - "string-length": "^3.1.0", - "tap-parser": "^10.0.1", - "unicode-length": "^2.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "bundled": true, - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "bundled": true, - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "bundled": true, - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "type-fest": { - "version": "0.21.3", - "bundled": true, - "dev": true - }, - "unicode-length": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "punycode": "^2.0.0", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "widest-line": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^4.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "bundled": true, - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "bundled": true, - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "bundled": true, - "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "yallist": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "yaml": { - "version": "1.10.2", - "bundled": true, - "dev": true - }, - "yoga-layout-prebuilt": { - "version": "1.10.0", - "bundled": true, - "dev": true, - "requires": { - "@types/yoga-layout": "1.9.2" - } - } - } - }, - "tap-mocha-reporter": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-5.0.1.tgz", - "integrity": "sha512-1knFWOwd4khx/7uSEnUeaP9IPW3w+sqTgJMhrwah6t46nZ8P25atOKAjSvVDsT67lOPu0nfdOqUwoyKn+3E5pA==", - "dev": true, - "requires": { - "color-support": "^1.1.0", - "debug": "^4.1.1", - "diff": "^4.0.1", - "escape-string-regexp": "^2.0.0", - "glob": "^7.0.5", - "tap-parser": "^10.0.0", - "tap-yaml": "^1.0.0", - "unicode-length": "^2.0.2" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "tap-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-10.1.0.tgz", - "integrity": "sha512-FujQeciDaOiOvaIVGS1Rpb0v4R6XkOjvWCWowlz5oKuhPkEJ8U6pxgqt38xuzYhPt8dWEnfHn2jqpZdJEkW7pA==", - "dev": true, - "requires": { - "events-to-array": "^1.0.1", - "minipass": "^3.0.0", - "tap-yaml": "^1.0.0" - } - }, - "tap-yaml": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.0.tgz", - "integrity": "sha512-Rxbx4EnrWkYk0/ztcm5u3/VznbyFJpyXO12dDBHKWiDVxy7O2Qw6MRrwO5H6Ww0U5YhRY/4C/VzWmFPhBQc4qQ==", - "dev": true, - "requires": { - "yaml": "^1.5.0" - } - }, - "tar-fs": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", - "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", - "dev": true, - "requires": { - "chownr": "^1.0.1", - "mkdirp": "^0.5.1", - "pump": "^1.0.0", - "tar-stream": "^1.1.2" - }, - "dependencies": { - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - } - } - }, - "tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "dev": true, - "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - } - }, - "tcompare": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-5.0.6.tgz", - "integrity": "sha512-OvO7omN/wkdsKzmOqr3sQFfLbghs/2X5mwSkcfgRiXZshfPnTsAs3IRf1RixR/Pff26qG/r9ogcZMpV0YdeGXg==", - "dev": true, - "requires": { - "diff": "^4.0.2" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "trivial-deferred": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-1.0.1.tgz", - "integrity": "sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM=", - "dev": true - }, - "tsconfig-paths": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz", - "integrity": "sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==", - "dev": true, - "requires": { - "json5": "^2.2.0", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "unicode-length": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unicode-length/-/unicode-length-2.0.2.tgz", - "integrity": "sha512-Ph/j1VbS3/r77nhoY2WU0GWGjVYOHL3xpKp0y/Eq2e5r0mT/6b649vm7KFO6RdAdrZkYLdxphYVgvODxPB+Ebg==", - "dev": true, - "requires": { - "punycode": "^2.0.0", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true - }, - "yapool": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yapool/-/yapool-1.0.0.tgz", - "integrity": "sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o=", - "dev": true - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "dependencies": { - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - } - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } -} diff --git a/package.json b/package.json index 9f9977a0..267f7f2f 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)", + "author": "GitHub Inc.", "name": "tar", "description": "tar for node", "version": "6.1.11", @@ -8,18 +8,17 @@ "url": "https://github.com/npm/node-tar.git" }, "scripts": { - "test:posix": "tap", - "test:win32": "tap --lines=98 --branches=98 --statements=98 --functions=98", - "test": "node test/fixtures/test.js", - "posttest": "npm run lint", - "eslint": "eslint", - "lint": "npm run eslint -- test lib", + "genparse": "node scripts/generate-parse-fixtures.js", + "template-oss-apply": "template-oss-apply --force", + "lint": "eslint \"**/*.js\"", + "postlint": "template-oss-check", "lintfix": "npm run lint -- --fix", "preversion": "npm test", "postversion": "npm publish", "prepublishOnly": "git push origin --follow-tags", - "genparse": "node scripts/generate-parse-fixtures.js", - "bench": "for i in benchmarks/*/*.js; do echo $i; for j in {1..5}; do node $i || break; done; done" + "snap": "tap", + "test": "tap", + "posttest": "npm run lint" }, "dependencies": { "chownr": "^2.0.0", @@ -30,13 +29,10 @@ "yallist": "^4.0.0" }, "devDependencies": { + "@npmcli/eslint-config": "^3.0.1", + "@npmcli/template-oss": "3.4.2", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", - "eslint": "^7.17.0", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^4.2.1", - "eslint-plugin-standard": "^5.0.0", "events-to-array": "^1.1.2", "mutate-fs": "^2.1.1", "rimraf": "^2.7.1", @@ -46,14 +42,30 @@ }, "license": "ISC", "engines": { - "node": ">= 10" + "node": ">=10" }, "files": [ "index.js", - "lib/*.js" + "lib/" ], "tap": { "coverage-map": "map.js", "check-coverage": true + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "3.4.2", + "engines": ">=10", + "distPaths": [ + "index.js", + "lib/" + ], + "ciVersions": [ + "10.0.0", + "10.x", + "12.x", + "14.x", + "16.x" + ] } } diff --git a/test/fixtures/.gitattributes b/test/fixtures/.gitattributes new file mode 100644 index 00000000..f3ae3fe5 --- /dev/null +++ b/test/fixtures/.gitattributes @@ -0,0 +1 @@ +files/** text eol=lf From 88bd796f80fd133495e2df44725a9cbf4055a08f Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Thu, 21 Apr 2022 21:20:58 -0700 Subject: [PATCH 02/96] chore: linting --- .eslintrc.local.js | 8 +++ lib/create.js | 21 ++++-- lib/extract.js | 26 ++++--- lib/header.js | 80 ++++++++++++--------- lib/large-numbers.js | 39 +++++----- lib/list.js | 33 +++++---- lib/mkdir.js | 64 ++++++++++------- lib/mode-fix.js | 12 ++-- lib/normalize-unicode.js | 5 +- lib/pack.js | 85 ++++++++++++++-------- lib/parse.js | 110 ++++++++++++++++------------ lib/path-reservations.js | 44 +++++++----- lib/pax.js | 21 ++++-- lib/read-entry.js | 21 ++++-- lib/replace.js | 73 ++++++++++++------- lib/unpack.js | 112 ++++++++++++++++++----------- lib/update.js | 12 ++-- lib/warn-mixin.js | 11 +-- lib/write-entry.js | 67 +++++++++++------ map.js | 2 +- scripts/generate-parse-fixtures.js | 29 ++++---- test/create.js | 19 ++--- test/extract.js | 24 ++++--- test/fixtures/test.js | 2 +- test/get-write-flag.js | 9 ++- test/list.js | 3 +- test/make-tar.js | 8 ++- test/normalize-windows-path.js | 10 +-- test/pack.js | 31 ++++---- test/parse.js | 26 ++++--- test/path-reservations.js | 12 ++-- test/pax.js | 2 +- test/replace.js | 18 +++-- test/strip-absolute-path.js | 6 +- test/unpack.js | 31 ++++---- test/update.js | 16 +++-- test/write-entry.js | 50 +++++++------ 37 files changed, 708 insertions(+), 434 deletions(-) create mode 100644 .eslintrc.local.js diff --git a/.eslintrc.local.js b/.eslintrc.local.js new file mode 100644 index 00000000..da0d239c --- /dev/null +++ b/.eslintrc.local.js @@ -0,0 +1,8 @@ +module.exports = { + rules: { + 'max-len': 0, + 'no-shadow': 0, + 'no-unused-expressions': 0, + 'no-sequences': 0, + }, +} diff --git a/lib/create.js b/lib/create.js index d033640a..e5c4383f 100644 --- a/lib/create.js +++ b/lib/create.js @@ -9,24 +9,29 @@ const t = require('./list.js') const path = require('path') module.exports = (opt_, files, cb) => { - if (typeof files === 'function') + if (typeof files === 'function') { cb = files + } - if (Array.isArray(opt_)) + if (Array.isArray(opt_)) { files = opt_, opt_ = {} + } - if (!files || !Array.isArray(files) || !files.length) + if (!files || !Array.isArray(files) || !files.length) { throw new TypeError('no files or directories specified') + } files = Array.from(files) const opt = hlo(opt_) - if (opt.sync && typeof cb === 'function') + if (opt.sync && typeof cb === 'function') { throw new TypeError('callback not supported for sync tar functions') + } - if (!opt.file && typeof cb === 'function') + if (!opt.file && typeof cb === 'function') { throw new TypeError('callback only supported with file option') + } return opt.file && opt.sync ? createFileSync(opt, files) : opt.file ? createFile(opt, files, cb) @@ -70,8 +75,9 @@ const addFilesSync = (p, files) => { noResume: true, onentry: entry => p.add(entry), }) - } else + } else { p.add(file) + } }) p.end() } @@ -85,8 +91,9 @@ const addFilesAsync = (p, files) => { noResume: true, onentry: entry => p.add(entry), }).then(_ => addFilesAsync(p, files)) - } else + } else { p.add(file) + } } p.end() } diff --git a/lib/extract.js b/lib/extract.js index 98e946ec..54767982 100644 --- a/lib/extract.js +++ b/lib/extract.js @@ -9,29 +9,35 @@ const path = require('path') const stripSlash = require('./strip-trailing-slashes.js') module.exports = (opt_, files, cb) => { - if (typeof opt_ === 'function') + if (typeof opt_ === 'function') { cb = opt_, files = null, opt_ = {} - else if (Array.isArray(opt_)) + } else if (Array.isArray(opt_)) { files = opt_, opt_ = {} + } - if (typeof files === 'function') + if (typeof files === 'function') { cb = files, files = null + } - if (!files) + if (!files) { files = [] - else + } else { files = Array.from(files) + } const opt = hlo(opt_) - if (opt.sync && typeof cb === 'function') + if (opt.sync && typeof cb === 'function') { throw new TypeError('callback not supported for sync tar functions') + } - if (!opt.file && typeof cb === 'function') + if (!opt.file && typeof cb === 'function') { throw new TypeError('callback only supported with file option') + } - if (files.length) + if (files.length) { filesFilter(opt, files) + } return opt.file && opt.sync ? extractFileSync(opt) : opt.file ? extractFile(opt, cb) @@ -87,9 +93,9 @@ const extractFile = (opt, cb) => { // This trades a zero-byte read() syscall for a stat // However, it will usually result in less memory allocation fs.stat(file, (er, stat) => { - if (er) + if (er) { reject(er) - else { + } else { const stream = new fsm.ReadStream(file, { readSize: readSize, size: stat.size, diff --git a/lib/header.js b/lib/header.js index 12950404..194550dd 100644 --- a/lib/header.js +++ b/lib/header.js @@ -34,18 +34,21 @@ class Header { this.atime = null this.ctime = null - if (Buffer.isBuffer(data)) + if (Buffer.isBuffer(data)) { this.decode(data, off || 0, ex, gex) - else if (data) + } else if (data) { this.set(data) + } } decode (buf, off, ex, gex) { - if (!off) + if (!off) { off = 0 + } - if (!buf || !(buf.length >= off + 512)) + if (!buf || !(buf.length >= off + 512)) { throw new Error('need 512 bytes for header') + } this.path = decString(buf, off, 100) this.mode = decNumber(buf, off + 100, 8) @@ -62,18 +65,21 @@ class Header { // old tar versions marked dirs as a file with a trailing / this[TYPE] = decString(buf, off + 156, 1) - if (this[TYPE] === '') + if (this[TYPE] === '') { this[TYPE] = '0' - if (this[TYPE] === '0' && this.path.substr(-1) === '/') + } + if (this[TYPE] === '0' && this.path.substr(-1) === '/') { this[TYPE] = '5' + } // tar implementations sometimes incorrectly put the stat(dir).size // as the size in the tarball, even though Directory entries are // not able to have any body at all. In the very rare chance that // it actually DOES have a body, we weren't going to do anything with // it anyway, and it'll just be a warning about an invalid header. - if (this[TYPE] === '5') + if (this[TYPE] === '5') { this.size = 0 + } this.linkpath = decString(buf, off + 157, 100) if (buf.slice(off + 257, off + 265).toString() === 'ustar\u000000') { @@ -87,23 +93,27 @@ class Header { this.path = prefix + '/' + this.path } else { const prefix = decString(buf, off + 345, 130) - if (prefix) + if (prefix) { this.path = prefix + '/' + this.path + } this.atime = decDate(buf, off + 476, 12) this.ctime = decDate(buf, off + 488, 12) } } let sum = 8 * 0x20 - for (let i = off; i < off + 148; i++) + for (let i = off; i < off + 148; i++) { sum += buf[i] + } - for (let i = off + 156; i < off + 512; i++) + for (let i = off + 156; i < off + 512; i++) { sum += buf[i] + } this.cksumValid = sum === this.cksum - if (this.cksum === null && sum === 8 * 0x20) + if (this.cksum === null && sum === 8 * 0x20) { this.nullBlock = true + } } [SLURP] (ex, global) { @@ -111,8 +121,9 @@ class Header { // we slurp in everything except for the path attribute in // a global extended header, because that's weird. if (ex[k] !== null && ex[k] !== undefined && - !(global && k === 'path')) + !(global && k === 'path')) { this[k] = ex[k] + } } } @@ -122,11 +133,13 @@ class Header { off = 0 } - if (!off) + if (!off) { off = 0 + } - if (!(buf.length >= off + 512)) + if (!(buf.length >= off + 512)) { throw new Error('need 512 bytes for header') + } const prefixSize = this.ctime || this.atime ? 130 : 155 const split = splitPrefix(this.path || '', prefixSize) @@ -148,20 +161,22 @@ class Header { this.needPax = encNumber(buf, off + 329, 8, this.devmaj) || this.needPax this.needPax = encNumber(buf, off + 337, 8, this.devmin) || this.needPax this.needPax = encString(buf, off + 345, prefixSize, prefix) || this.needPax - if (buf[off + 475] !== 0) + if (buf[off + 475] !== 0) { this.needPax = encString(buf, off + 345, 155, prefix) || this.needPax - else { + } else { this.needPax = encString(buf, off + 345, 130, prefix) || this.needPax this.needPax = encDate(buf, off + 476, 12, this.atime) || this.needPax this.needPax = encDate(buf, off + 488, 12, this.ctime) || this.needPax } let sum = 8 * 0x20 - for (let i = off; i < off + 148; i++) + for (let i = off; i < off + 148; i++) { sum += buf[i] + } - for (let i = off + 156; i < off + 512; i++) + for (let i = off + 156; i < off + 512; i++) { sum += buf[i] + } this.cksum = sum encNumber(buf, off + 148, 8, this.cksum) @@ -172,8 +187,9 @@ class Header { set (data) { for (const i in data) { - if (data[i] !== null && data[i] !== undefined) + if (data[i] !== null && data[i] !== undefined) { this[i] = data[i] + } } } @@ -186,10 +202,11 @@ class Header { } set type (type) { - if (types.code.has(type)) + if (types.code.has(type)) { this[TYPE] = types.code.get(type) - else + } else { this[TYPE] = type + } } } @@ -200,25 +217,23 @@ const splitPrefix = (p, prefixSize) => { let ret const root = pathModule.parse(p).root || '.' - if (Buffer.byteLength(pp) < pathSize) + if (Buffer.byteLength(pp) < pathSize) { ret = [pp, prefix, false] - else { + } else { // first set prefix to the dir, and path to the base prefix = pathModule.dirname(pp) pp = pathModule.basename(pp) do { - // both fit! if (Buffer.byteLength(pp) <= pathSize && - Buffer.byteLength(prefix) <= prefixSize) + Buffer.byteLength(prefix) <= prefixSize) { + // both fit! ret = [pp, prefix, false] - - // prefix fits in prefix, but path doesn't fit in path - else if (Buffer.byteLength(pp) > pathSize && - Buffer.byteLength(prefix) <= prefixSize) + } else if (Buffer.byteLength(pp) > pathSize && + Buffer.byteLength(prefix) <= prefixSize) { + // prefix fits in prefix, but path doesn't fit in path ret = [pp.substr(0, pathSize - 1), prefix, true] - - else { + } else { // make path take a bit from prefix pp = pathModule.join(pathModule.basename(prefix), pp) prefix = pathModule.dirname(prefix) @@ -226,8 +241,9 @@ const splitPrefix = (p, prefixSize) => { } while (prefix !== root && !ret) // at this point, found no resolution, just truncate - if (!ret) + if (!ret) { ret = [p.substr(0, pathSize - 1), '', true] + } } return ret } diff --git a/lib/large-numbers.js b/lib/large-numbers.js index dd6f690b..b11e72d9 100644 --- a/lib/large-numbers.js +++ b/lib/large-numbers.js @@ -3,14 +3,15 @@ // 0xff for negative, and 0x80 for positive. const encode = (num, buf) => { - if (!Number.isSafeInteger(num)) - // The number is so large that javascript cannot represent it with integer - // precision. + if (!Number.isSafeInteger(num)) { + // The number is so large that javascript cannot represent it with integer + // precision. throw Error('cannot encode number outside of javascript safe integer range') - else if (num < 0) + } else if (num < 0) { encodeNegative(num, buf) - else + } else { encodePositive(num, buf) + } return buf } @@ -30,11 +31,11 @@ const encodeNegative = (num, buf) => { for (var i = buf.length; i > 1; i--) { var byte = num & 0xff num = Math.floor(num / 0x100) - if (flipped) + if (flipped) { buf[i - 1] = onesComp(byte) - else if (byte === 0) + } else if (byte === 0) { buf[i - 1] = 0 - else { + } else { flipped = true buf[i - 1] = twosComp(byte) } @@ -46,13 +47,15 @@ const parse = (buf) => { const value = pre === 0x80 ? pos(buf.slice(1, buf.length)) : pre === 0xff ? twos(buf) : null - if (value === null) + if (value === null) { throw Error('invalid base256 encoding') + } - if (!Number.isSafeInteger(value)) - // The number is so large that javascript cannot represent it with integer - // precision. + if (!Number.isSafeInteger(value)) { + // The number is so large that javascript cannot represent it with integer + // precision. throw Error('parsed number outside of javascript safe integer range') + } return value } @@ -64,16 +67,17 @@ const twos = (buf) => { for (var i = len - 1; i > -1; i--) { var byte = buf[i] var f - if (flipped) + if (flipped) { f = onesComp(byte) - else if (byte === 0) + } else if (byte === 0) { f = byte - else { + } else { flipped = true f = twosComp(byte) } - if (f !== 0) + if (f !== 0) { sum -= f * Math.pow(256, len - i - 1) + } } return sum } @@ -83,8 +87,9 @@ const pos = (buf) => { var sum = 0 for (var i = len - 1; i > -1; i--) { var byte = buf[i] - if (byte !== 0) + if (byte !== 0) { sum += byte * Math.pow(256, len - i - 1) + } } return sum } diff --git a/lib/list.js b/lib/list.js index a0c1cf2f..f2358c25 100644 --- a/lib/list.js +++ b/lib/list.js @@ -12,32 +12,39 @@ const path = require('path') const stripSlash = require('./strip-trailing-slashes.js') module.exports = (opt_, files, cb) => { - if (typeof opt_ === 'function') + if (typeof opt_ === 'function') { cb = opt_, files = null, opt_ = {} - else if (Array.isArray(opt_)) + } else if (Array.isArray(opt_)) { files = opt_, opt_ = {} + } - if (typeof files === 'function') + if (typeof files === 'function') { cb = files, files = null + } - if (!files) + if (!files) { files = [] - else + } else { files = Array.from(files) + } const opt = hlo(opt_) - if (opt.sync && typeof cb === 'function') + if (opt.sync && typeof cb === 'function') { throw new TypeError('callback not supported for sync tar functions') + } - if (!opt.file && typeof cb === 'function') + if (!opt.file && typeof cb === 'function') { throw new TypeError('callback only supported with file option') + } - if (files.length) + if (files.length) { filesFilter(opt, files) + } - if (!opt.noResume) + if (!opt.noResume) { onentryFunction(opt) + } return opt.file && opt.sync ? listFileSync(opt) : opt.file ? listFile(opt, cb) @@ -81,9 +88,9 @@ const listFileSync = opt => { try { const stat = fs.statSync(file) const readSize = opt.maxReadSize || 16 * 1024 * 1024 - if (stat.size < readSize) + if (stat.size < readSize) { p.end(fs.readFileSync(file)) - else { + } else { let pos = 0 const buf = Buffer.allocUnsafe(readSize) fd = fs.openSync(file, 'r') @@ -114,9 +121,9 @@ const listFile = (opt, cb) => { parse.on('end', resolve) fs.stat(file, (er, stat) => { - if (er) + if (er) { reject(er) - else { + } else { const stream = new fsm.ReadStream(file, { readSize: readSize, size: stat.size, diff --git a/lib/mkdir.js b/lib/mkdir.js index a0719e6c..8ee8de78 100644 --- a/lib/mkdir.js +++ b/lib/mkdir.js @@ -39,8 +39,9 @@ const cSet = (cache, key, val) => cache.set(normPath(key), val) const checkCwd = (dir, cb) => { fs.stat(dir, (er, st) => { - if (er || !st.isDirectory()) + if (er || !st.isDirectory()) { er = new CwdError(dir, er && er.code || 'ENOTDIR') + } cb(er) }) } @@ -66,27 +67,31 @@ module.exports = (dir, opt, cb) => { const cwd = normPath(opt.cwd) const done = (er, created) => { - if (er) + if (er) { cb(er) - else { + } else { cSet(cache, dir, true) - if (created && doChown) + if (created && doChown) { chownr(created, uid, gid, er => done(er)) - else if (needChmod) + } else if (needChmod) { fs.chmod(dir, mode, cb) - else + } else { cb() + } } } - if (cache && cGet(cache, dir) === true) + if (cache && cGet(cache, dir) === true) { return done() + } - if (dir === cwd) + if (dir === cwd) { return checkCwd(dir, done) + } - if (preserve) - return mkdirp(dir, {mode}).then(made => done(null, made), done) + if (preserve) { + return mkdirp(dir, { mode }).then(made => done(null, made), done) + } const sub = normPath(path.relative(cwd, dir)) const parts = sub.split('/') @@ -94,12 +99,14 @@ module.exports = (dir, opt, cb) => { } const mkdir_ = (base, parts, mode, cache, unlink, cwd, created, cb) => { - if (!parts.length) + if (!parts.length) { return cb(null, created) + } const p = parts.shift() const part = normPath(path.resolve(base + '/' + p)) - if (cGet(cache, part)) + if (cGet(cache, part)) { return mkdir_(part, parts, mode, cache, unlink, cwd, created, cb) + } fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb)) } @@ -109,18 +116,20 @@ const onmkdir = (part, parts, mode, cache, unlink, cwd, created, cb) => er => { if (statEr) { statEr.path = statEr.path && normPath(statEr.path) cb(statEr) - } else if (st.isDirectory()) + } else if (st.isDirectory()) { mkdir_(part, parts, mode, cache, unlink, cwd, created, cb) - else if (unlink) { + } else if (unlink) { fs.unlink(part, er => { - if (er) + if (er) { return cb(er) + } fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb)) }) - } else if (st.isSymbolicLink()) + } else if (st.isSymbolicLink()) { return cb(new SymlinkError(part, part + '/' + parts.join('/'))) - else + } else { cb(er) + } }) } else { created = created || part @@ -136,8 +145,9 @@ const checkCwdSync = dir => { } catch (er) { code = er.code } finally { - if (!ok) + if (!ok) { throw new CwdError(dir, code) + } } } @@ -162,22 +172,26 @@ module.exports.sync = (dir, opt) => { const done = (created) => { cSet(cache, dir, true) - if (created && doChown) + if (created && doChown) { chownr.sync(created, uid, gid) - if (needChmod) + } + if (needChmod) { fs.chmodSync(dir, mode) + } } - if (cache && cGet(cache, dir) === true) + if (cache && cGet(cache, dir) === true) { return done() + } if (dir === cwd) { checkCwdSync(cwd) return done() } - if (preserve) + if (preserve) { return done(mkdirp.sync(dir, mode)) + } const sub = normPath(path.relative(cwd, dir)) const parts = sub.split('/') @@ -186,8 +200,9 @@ module.exports.sync = (dir, opt) => { p && (part += '/' + p); p = parts.shift()) { part = normPath(path.resolve(part)) - if (cGet(cache, part)) + if (cGet(cache, part)) { continue + } try { fs.mkdirSync(part, mode) @@ -204,8 +219,9 @@ module.exports.sync = (dir, opt) => { created = created || part cSet(cache, part, true) continue - } else if (st.isSymbolicLink()) + } else if (st.isSymbolicLink()) { return new SymlinkError(part, part + '/' + parts.join('/')) + } } } diff --git a/lib/mode-fix.js b/lib/mode-fix.js index 6a045ffc..42f1d6e6 100644 --- a/lib/mode-fix.js +++ b/lib/mode-fix.js @@ -7,17 +7,21 @@ module.exports = (mode, isDir, portable) => { // (as some linux distros do), then we'll write the // archive with 0o644 instead. Also, don't ever create // a file that is not readable/writable by the owner. - if (portable) + if (portable) { mode = (mode | 0o600) & ~0o22 + } // if dirs are readable, then they should be listable if (isDir) { - if (mode & 0o400) + if (mode & 0o400) { mode |= 0o100 - if (mode & 0o40) + } + if (mode & 0o40) { mode |= 0o10 - if (mode & 0o4) + } + if (mode & 0o4) { mode |= 0o1 + } } return mode } diff --git a/lib/normalize-unicode.js b/lib/normalize-unicode.js index 4aeb1d50..43dc406e 100644 --- a/lib/normalize-unicode.js +++ b/lib/normalize-unicode.js @@ -3,9 +3,10 @@ // within npm install on large package trees. // Do not edit without careful benchmarking. const normalizeCache = Object.create(null) -const {hasOwnProperty} = Object.prototype +const { hasOwnProperty } = Object.prototype module.exports = s => { - if (!hasOwnProperty.call(normalizeCache, s)) + if (!hasOwnProperty.call(normalizeCache, s)) { normalizeCache[s] = s.normalize('NFKD') + } return normalizeCache[s] } diff --git a/lib/pack.js b/lib/pack.js index 9522c10b..a3f4ff22 100644 --- a/lib/pack.js +++ b/lib/pack.js @@ -73,23 +73,27 @@ const Pack = warner(class Pack extends MiniPass { this.readdirCache = opt.readdirCache || new Map() this[WRITEENTRYCLASS] = WriteEntry - if (typeof opt.onwarn === 'function') + if (typeof opt.onwarn === 'function') { this.on('warn', opt.onwarn) + } this.portable = !!opt.portable this.zip = null if (opt.gzip) { - if (typeof opt.gzip !== 'object') + if (typeof opt.gzip !== 'object') { opt.gzip = {} - if (this.portable) + } + if (this.portable) { opt.gzip.portable = true + } this.zip = new zlib.Gzip(opt.gzip) this.zip.on('data', chunk => super.write(chunk)) this.zip.on('end', _ => super.end()) this.zip.on('drain', _ => this[ONDRAIN]()) this.on('resume', _ => this.zip.resume()) - } else + } else { this.on('drain', this[ONDRAIN]) + } this.noDirRecurse = !!opt.noDirRecurse this.follow = !!opt.follow @@ -115,30 +119,33 @@ const Pack = warner(class Pack extends MiniPass { } end (path) { - if (path) + if (path) { this.write(path) + } this[ENDED] = true this[PROCESS]() return this } write (path) { - if (this[ENDED]) + if (this[ENDED]) { throw new Error('write after end') + } - if (path instanceof ReadEntry) + if (path instanceof ReadEntry) { this[ADDTARENTRY](path) - else + } else { this[ADDFSENTRY](path) + } return this.flowing } [ADDTARENTRY] (p) { const absolute = normPath(path.resolve(this.cwd, p.path)) // in this case, we don't have to wait for the stat - if (!this.filter(p.path, p)) + if (!this.filter(p.path, p)) { p.resume() - else { + } else { const job = new PackJob(p.path, absolute, false) job.entry = new WriteEntryTar(p, this[ENTRYOPT](job)) job.entry.on('end', _ => this[JOBDONE](job)) @@ -162,10 +169,11 @@ const Pack = warner(class Pack extends MiniPass { fs[stat](job.absolute, (er, stat) => { job.pending = false this[JOBS] -= 1 - if (er) + if (er) { this.emit('error', er) - else + } else { this[ONSTAT](job, stat) + } }) } @@ -174,8 +182,9 @@ const Pack = warner(class Pack extends MiniPass { job.stat = stat // now we have the stat, we can filter it. - if (!this.filter(job.path, stat)) + if (!this.filter(job.path, stat)) { job.ignore = true + } this[PROCESS]() } @@ -186,8 +195,9 @@ const Pack = warner(class Pack extends MiniPass { fs.readdir(job.absolute, (er, entries) => { job.pending = false this[JOBS] -= 1 - if (er) + if (er) { return this.emit('error', er) + } this[ONREADDIR](job, entries) }) } @@ -199,8 +209,9 @@ const Pack = warner(class Pack extends MiniPass { } [PROCESS] () { - if (this[PROCESSING]) + if (this[PROCESSING]) { return + } this[PROCESSING] = true for (let w = this[QUEUE].head; @@ -217,9 +228,9 @@ const Pack = warner(class Pack extends MiniPass { this[PROCESSING] = false if (this[ENDED] && !this[QUEUE].length && this[JOBS] === 0) { - if (this.zip) + if (this.zip) { this.zip.end(EOF) - else { + } else { super.write(EOF) super.end() } @@ -237,35 +248,42 @@ const Pack = warner(class Pack extends MiniPass { } [PROCESSJOB] (job) { - if (job.pending) + if (job.pending) { return + } if (job.entry) { - if (job === this[CURRENT] && !job.piped) + if (job === this[CURRENT] && !job.piped) { this[PIPE](job) + } return } if (!job.stat) { - if (this.statCache.has(job.absolute)) + if (this.statCache.has(job.absolute)) { this[ONSTAT](job, this.statCache.get(job.absolute)) - else + } else { this[STAT](job) + } } - if (!job.stat) + if (!job.stat) { return + } // filtered out! - if (job.ignore) + if (job.ignore) { return + } if (!this.noDirRecurse && job.stat.isDirectory() && !job.readdir) { - if (this.readdirCache.has(job.absolute)) + if (this.readdirCache.has(job.absolute)) { this[ONREADDIR](job, this.readdirCache.get(job.absolute)) - else + } else { this[READDIR](job) - if (!job.readdir) + } + if (!job.readdir) { return + } } // we know it doesn't have an entry, because that got checked above @@ -275,8 +293,9 @@ const Pack = warner(class Pack extends MiniPass { return } - if (job === this[CURRENT] && !job.piped) + if (job === this[CURRENT] && !job.piped) { this[PIPE](job) + } } [ENTRYOPT] (job) { @@ -309,8 +328,9 @@ const Pack = warner(class Pack extends MiniPass { } [ONDRAIN] () { - if (this[CURRENT] && this[CURRENT].entry) + if (this[CURRENT] && this[CURRENT].entry) { this[CURRENT].entry.resume() + } } // like .pipe() but using super, because our write() is special @@ -330,20 +350,23 @@ const Pack = warner(class Pack extends MiniPass { if (zip) { source.on('data', chunk => { - if (!zip.write(chunk)) + if (!zip.write(chunk)) { source.pause() + } }) } else { source.on('data', chunk => { - if (!super.write(chunk)) + if (!super.write(chunk)) { source.pause() + } }) } } pause () { - if (this.zip) + if (this.zip) { this.zip.pause() + } return super.pause() } }) diff --git a/lib/parse.js b/lib/parse.js index b1b4e7e4..16023f08 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -82,9 +82,9 @@ module.exports = warner(class Parser extends EE { } }) - if (opt.ondone) + if (opt.ondone) { this.on(DONE, opt.ondone) - else { + } else { this.on(DONE, _ => { this.emit('prefinish') this.emit('finish') @@ -114,15 +114,18 @@ module.exports = warner(class Parser extends EE { this[ABORTED] = false this[SAW_NULL_BLOCK] = false this[SAW_EOF] = false - if (typeof opt.onwarn === 'function') + if (typeof opt.onwarn === 'function') { this.on('warn', opt.onwarn) - if (typeof opt.onentry === 'function') + } + if (typeof opt.onentry === 'function') { this.on('entry', opt.onentry) + } } [CONSUMEHEADER] (chunk, position) { - if (this[SAW_VALID_ENTRY] === null) + if (this[SAW_VALID_ENTRY] === null) { this[SAW_VALID_ENTRY] = false + } let header try { header = new Header(chunk, position, this[EX], this[GEX]) @@ -134,8 +137,9 @@ module.exports = warner(class Parser extends EE { if (this[SAW_NULL_BLOCK]) { this[SAW_EOF] = true // ending an archive with no entries. pointless, but legal. - if (this[STATE] === 'begin') + if (this[STATE] === 'begin') { this[STATE] = 'header' + } this[EMIT]('eof') } else { this[SAW_NULL_BLOCK] = true @@ -143,17 +147,17 @@ module.exports = warner(class Parser extends EE { } } else { this[SAW_NULL_BLOCK] = false - if (!header.cksumValid) - this.warn('TAR_ENTRY_INVALID', 'checksum failure', {header}) - else if (!header.path) - this.warn('TAR_ENTRY_INVALID', 'path is required', {header}) - else { + if (!header.cksumValid) { + this.warn('TAR_ENTRY_INVALID', 'checksum failure', { header }) + } else if (!header.path) { + this.warn('TAR_ENTRY_INVALID', 'path is required', { header }) + } else { const type = header.type - if (/^(Symbolic)?Link$/.test(type) && !header.linkpath) - this.warn('TAR_ENTRY_INVALID', 'linkpath required', {header}) - else if (!/^(Symbolic)?Link$/.test(type) && header.linkpath) - this.warn('TAR_ENTRY_INVALID', 'linkpath forbidden', {header}) - else { + if (/^(Symbolic)?Link$/.test(type) && !header.linkpath) { + this.warn('TAR_ENTRY_INVALID', 'linkpath required', { header }) + } else if (!/^(Symbolic)?Link$/.test(type) && header.linkpath) { + this.warn('TAR_ENTRY_INVALID', 'linkpath forbidden', { header }) + } else { const entry = this[WRITEENTRY] = new Entry(header, this[EX], this[GEX]) // we do this for meta & ignored entries as well, because they @@ -162,12 +166,14 @@ module.exports = warner(class Parser extends EE { if (entry.remain) { // this might be the one! const onend = () => { - if (!entry.invalid) + if (!entry.invalid) { this[SAW_VALID_ENTRY] = true + } } entry.on('end', onend) - } else + } else { this[SAW_VALID_ENTRY] = true + } } if (entry.meta) { @@ -191,9 +197,9 @@ module.exports = warner(class Parser extends EE { this[STATE] = entry.remain ? 'ignore' : 'header' entry.resume() } else { - if (entry.remain) + if (entry.remain) { this[STATE] = 'body' - else { + } else { this[STATE] = 'header' entry.end() } @@ -201,8 +207,9 @@ module.exports = warner(class Parser extends EE { if (!this[READENTRY]) { this[QUEUE].push(entry) this[NEXTENTRY]() - } else + } else { this[QUEUE].push(entry) + } } } } @@ -216,9 +223,9 @@ module.exports = warner(class Parser extends EE { if (!entry) { this[READENTRY] = null go = false - } else if (Array.isArray(entry)) + } else if (Array.isArray(entry)) { this.emit.apply(this, entry) - else { + } else { this[READENTRY] = entry this.emit('entry', entry) if (!entry.emittedEnd) { @@ -244,10 +251,12 @@ module.exports = warner(class Parser extends EE { const re = this[READENTRY] const drainNow = !re || re.flowing || re.size === re.remain if (drainNow) { - if (!this[WRITING]) + if (!this[WRITING]) { this.emit('drain') - } else + } + } else { re.once('drain', _ => this.emit('drain')) + } } } @@ -274,17 +283,19 @@ module.exports = warner(class Parser extends EE { const ret = this[CONSUMEBODY](chunk, position) // if we finished, then the entry is reset - if (!this[WRITEENTRY]) + if (!this[WRITEENTRY]) { this[EMITMETA](entry) + } return ret } [EMIT] (ev, data, extra) { - if (!this[QUEUE].length && !this[READENTRY]) + if (!this[QUEUE].length && !this[READENTRY]) { this.emit(ev, data, extra) - else + } else { this[QUEUE].push([ev, data, extra]) + } } [EMITMETA] (entry) { @@ -323,8 +334,9 @@ module.exports = warner(class Parser extends EE { } write (chunk) { - if (this[ABORTED]) + if (this[ABORTED]) { return + } // first write, might be gzipped if (this[UNZIP] === null && chunk) { @@ -337,8 +349,9 @@ module.exports = warner(class Parser extends EE { return true } for (let i = 0; this[UNZIP] === null && i < gzipHeader.length; i++) { - if (chunk[i] !== gzipHeader[i]) + if (chunk[i] !== gzipHeader[i]) { this[UNZIP] = false + } } if (this[UNZIP] === null) { const ended = this[ENDED] @@ -358,10 +371,11 @@ module.exports = warner(class Parser extends EE { } this[WRITING] = true - if (this[UNZIP]) + if (this[UNZIP]) { this[UNZIP].write(chunk) - else + } else { this[CONSUMECHUNK](chunk) + } this[WRITING] = false // return false if there's a queue, or if the current entry isn't flowing @@ -371,15 +385,17 @@ module.exports = warner(class Parser extends EE { true // if we have no queue, then that means a clogged READENTRY - if (!ret && !this[QUEUE].length) + if (!ret && !this[QUEUE].length) { this[READENTRY].once('drain', _ => this.emit('drain')) + } return ret } [BUFFERCONCAT] (c) { - if (c && !this[ABORTED]) + if (c && !this[ABORTED]) { this[BUFFER] = this[BUFFER] ? Buffer.concat([this[BUFFER], c]) : c + } } [MAYBEEND] () { @@ -393,9 +409,10 @@ module.exports = warner(class Parser extends EE { // truncated, likely a damaged file const have = this[BUFFER] ? this[BUFFER].length : 0 this.warn('TAR_BAD_ARCHIVE', `Truncated input (needed ${ - entry.blockRemain} more bytes, only ${have} available)`, {entry}) - if (this[BUFFER]) + entry.blockRemain} more bytes, only ${have} available)`, { entry }) + if (this[BUFFER]) { entry.write(this[BUFFER]) + } entry.end() } this[EMIT](DONE) @@ -403,19 +420,20 @@ module.exports = warner(class Parser extends EE { } [CONSUMECHUNK] (chunk) { - if (this[CONSUMING]) + if (this[CONSUMING]) { this[BUFFERCONCAT](chunk) - else if (!chunk && !this[BUFFER]) + } else if (!chunk && !this[BUFFER]) { this[MAYBEEND]() - else { + } else { this[CONSUMING] = true if (this[BUFFER]) { this[BUFFERCONCAT](chunk) const c = this[BUFFER] this[BUFFER] = null this[CONSUMECHUNKSUB](c) - } else + } else { this[CONSUMECHUNKSUB](chunk) + } while (this[BUFFER] && this[BUFFER].length >= 512 && @@ -428,8 +446,9 @@ module.exports = warner(class Parser extends EE { this[CONSUMING] = false } - if (!this[BUFFER] || this[ENDED]) + if (!this[BUFFER] || this[ENDED]) { this[MAYBEEND]() + } } [CONSUMECHUNKSUB] (chunk) { @@ -461,18 +480,19 @@ module.exports = warner(class Parser extends EE { } if (position < length) { - if (this[BUFFER]) + if (this[BUFFER]) { this[BUFFER] = Buffer.concat([chunk.slice(position), this[BUFFER]]) - else + } else { this[BUFFER] = chunk.slice(position) + } } } end (chunk) { if (!this[ABORTED]) { - if (this[UNZIP]) + if (this[UNZIP]) { this[UNZIP].end(chunk) - else { + } else { this[ENDED] = true this.write(chunk) } diff --git a/lib/path-reservations.js b/lib/path-reservations.js index 8183c45f..ef380cab 100644 --- a/lib/path-reservations.js +++ b/lib/path-reservations.js @@ -27,8 +27,9 @@ module.exports = () => { // '/a/b/c/d' -> ['/', '/a', '/a/b', '/a/b/c', '/a/b/c/d'] const getDirs = path => { const dirs = path.split('/').slice(0, -1).reduce((set, path) => { - if (set.length) + if (set.length) { path = join(set[set.length - 1], path) + } set.push(path || '/') return set }, []) @@ -43,8 +44,9 @@ module.exports = () => { const getQueues = fn => { const res = reservations.get(fn) /* istanbul ignore if - unpossible */ - if (!res) + if (!res) { throw new Error('function does not have any path reservations') + } return { paths: res.paths.map(path => queues.get(path)), dirs: [...res.dirs].map(path => queues.get(path)), @@ -54,23 +56,25 @@ module.exports = () => { // check if fn is first in line for all its paths, and is // included in the first set for all its dir queues const check = fn => { - const {paths, dirs} = getQueues(fn) + const { paths, dirs } = getQueues(fn) return paths.every(q => q[0] === fn) && dirs.every(q => q[0] instanceof Set && q[0].has(fn)) } // run the function if it's first in line and not already running const run = fn => { - if (running.has(fn) || !check(fn)) + if (running.has(fn) || !check(fn)) { return false + } running.add(fn) fn(() => clear(fn)) return true } const clear = fn => { - if (!running.has(fn)) + if (!running.has(fn)) { return false + } const { paths, dirs } = reservations.get(fn) const next = new Set() @@ -78,29 +82,31 @@ module.exports = () => { paths.forEach(path => { const q = queues.get(path) assert.equal(q[0], fn) - if (q.length === 1) + if (q.length === 1) { queues.delete(path) - else { + } else { q.shift() - if (typeof q[0] === 'function') + if (typeof q[0] === 'function') { next.add(q[0]) - else + } else { q[0].forEach(fn => next.add(fn)) + } } }) dirs.forEach(dir => { const q = queues.get(dir) assert(q[0] instanceof Set) - if (q[0].size === 1 && q.length === 1) + if (q[0].size === 1 && q.length === 1) { queues.delete(dir) - else if (q[0].size === 1) { + } else if (q[0].size === 1) { q.shift() // must be a function or else the Set would've been reused next.add(q[0]) - } else + } else { q[0].delete(fn) + } }) running.delete(fn) @@ -123,22 +129,24 @@ module.exports = () => { const dirs = new Set( paths.map(path => getDirs(path)).reduce((a, b) => a.concat(b)) ) - reservations.set(fn, {dirs, paths}) + reservations.set(fn, { dirs, paths }) paths.forEach(path => { const q = queues.get(path) - if (!q) + if (!q) { queues.set(path, [fn]) - else + } else { q.push(fn) + } }) dirs.forEach(dir => { const q = queues.get(dir) - if (!q) + if (!q) { queues.set(dir, [new Set([fn])]) - else if (q[q.length - 1] instanceof Set) + } else if (q[q.length - 1] instanceof Set) { q[q.length - 1].add(fn) - else + } else { q.push(new Set([fn])) + } }) return run(fn) diff --git a/lib/pax.js b/lib/pax.js index 7768c7b4..a505c1ab 100644 --- a/lib/pax.js +++ b/lib/pax.js @@ -24,8 +24,9 @@ class Pax { encode () { const body = this.encodeBody() - if (body === '') + if (body === '') { return null + } const bodyLen = Buffer.byteLength(body) // round up to 512 bytes @@ -34,8 +35,9 @@ class Pax { const buf = Buffer.allocUnsafe(bufLen) // 0-fill the header section, it might not hit every field - for (let i = 0; i < 512; i++) + for (let i = 0; i < 512; i++) { buf[i] = 0 + } new Header({ // XXX split the path @@ -60,8 +62,9 @@ class Pax { buf.write(body, 512, bodyLen, 'utf8') // null pad after the body - for (let i = bodyLen + 512; i < buf.length; i++) + for (let i = bodyLen + 512; i < buf.length; i++) { buf[i] = 0 + } return buf } @@ -87,8 +90,9 @@ class Pax { } encodeField (field) { - if (this[field] === null || this[field] === undefined) + if (this[field] === null || this[field] === undefined) { return '' + } const v = this[field] instanceof Date ? this[field].getTime() / 1000 : this[field] const s = ' ' + @@ -100,8 +104,9 @@ class Pax { // so if it's 9 characters, then adding 1 for the 9 makes it 10 // which makes it 11 chars. let digits = Math.floor(Math.log(byteLen) / Math.log(10)) + 1 - if (byteLen + digits >= Math.pow(10, digits)) + if (byteLen + digits >= Math.pow(10, digits)) { digits += 1 + } const len = digits + byteLen return len + s } @@ -123,14 +128,16 @@ const parseKVLine = (set, line) => { // XXX Values with \n in them will fail this. // Refactor to not be a naive line-by-line parse. - if (n !== Buffer.byteLength(line) + 1) + if (n !== Buffer.byteLength(line) + 1) { return set + } line = line.substr((n + ' ').length) const kv = line.split('=') const k = kv.shift().replace(/^SCHILY\.(dev|ino|nlink)/, '$1') - if (!k) + if (!k) { return set + } const v = kv.join('=') set[k] = /^([A-Z]+\.)?([mac]|birth|creation)time$/.test(k) diff --git a/lib/read-entry.js b/lib/read-entry.js index 183a6050..7f44bebf 100644 --- a/lib/read-entry.js +++ b/lib/read-entry.js @@ -49,8 +49,9 @@ module.exports = class ReadEntry extends MiniPass { this.path = normPath(header.path) this.mode = header.mode - if (this.mode) + if (this.mode) { this.mode = this.mode & 0o7777 + } this.uid = header.uid this.gid = header.gid this.uname = header.uname @@ -63,26 +64,31 @@ module.exports = class ReadEntry extends MiniPass { this.uname = header.uname this.gname = header.gname - if (ex) + if (ex) { this[SLURP](ex) - if (gex) + } + if (gex) { this[SLURP](gex, true) + } } write (data) { const writeLen = data.length - if (writeLen > this.blockRemain) + if (writeLen > this.blockRemain) { throw new Error('writing more to entry than is appropriate') + } const r = this.remain const br = this.blockRemain this.remain = Math.max(0, r - writeLen) this.blockRemain = Math.max(0, br - writeLen) - if (this.ignore) + if (this.ignore) { return true + } - if (r >= writeLen) + if (r >= writeLen) { return super.write(data) + } // r < writeLen return super.write(data.slice(0, r)) @@ -93,8 +99,9 @@ module.exports = class ReadEntry extends MiniPass { // we slurp in everything except for the path attribute in // a global extended header, because that's weird. if (ex[k] !== null && ex[k] !== undefined && - !(global && k === 'path')) + !(global && k === 'path')) { this[k] = k === 'path' || k === 'linkpath' ? normPath(ex[k]) : ex[k] + } } } } diff --git a/lib/replace.js b/lib/replace.js index 1374f3f2..60d07375 100644 --- a/lib/replace.js +++ b/lib/replace.js @@ -19,14 +19,17 @@ const Header = require('./header.js') module.exports = (opt_, files, cb) => { const opt = hlo(opt_) - if (!opt.file) + if (!opt.file) { throw new TypeError('file is required') + } - if (opt.gzip) + if (opt.gzip) { throw new TypeError('cannot append to compressed archives') + } - if (!files || !Array.isArray(files) || !files.length) + if (!files || !Array.isArray(files) || !files.length) { throw new TypeError('no files or directories specified') + } files = Array.from(files) @@ -45,10 +48,11 @@ const replaceSync = (opt, files) => { try { fd = fs.openSync(opt.file, 'r+') } catch (er) { - if (er.code === 'ENOENT') + if (er.code === 'ENOENT') { fd = fs.openSync(opt.file, 'w+') - else + } else { throw er + } } const st = fs.fstatSync(fd) @@ -60,24 +64,29 @@ const replaceSync = (opt, files) => { fd, headBuf, bufPos, headBuf.length - bufPos, position + bufPos ) - if (position === 0 && headBuf[0] === 0x1f && headBuf[1] === 0x8b) + if (position === 0 && headBuf[0] === 0x1f && headBuf[1] === 0x8b) { throw new Error('cannot append to compressed archives') + } - if (!bytes) + if (!bytes) { break POSITION + } } const h = new Header(headBuf) - if (!h.cksumValid) + if (!h.cksumValid) { break + } const entryBlockSize = 512 * Math.ceil(h.size / 512) - if (position + entryBlockSize + 512 > st.size) + if (position + entryBlockSize + 512 > st.size) { break + } // the 512 for the header we just parsed will be added as well // also jump ahead all the blocks for the body position += entryBlockSize - if (opt.mtimeCache) + if (opt.mtimeCache) { opt.mtimeCache.set(h.path, h.mtime) + } } threw = false @@ -106,21 +115,24 @@ const replace = (opt, files, cb) => { const getPos = (fd, size, cb_) => { const cb = (er, pos) => { - if (er) + if (er) { fs.close(fd, _ => cb_(er)) - else + } else { cb_(null, pos) + } } let position = 0 - if (size === 0) + if (size === 0) { return cb(null, 0) + } let bufPos = 0 const headBuf = Buffer.alloc(512) const onread = (er, bytes) => { - if (er) + if (er) { return cb(er) + } bufPos += bytes if (bufPos < 512 && bytes) { return fs.read( @@ -129,27 +141,33 @@ const replace = (opt, files, cb) => { ) } - if (position === 0 && headBuf[0] === 0x1f && headBuf[1] === 0x8b) + if (position === 0 && headBuf[0] === 0x1f && headBuf[1] === 0x8b) { return cb(new Error('cannot append to compressed archives')) + } // truncated header - if (bufPos < 512) + if (bufPos < 512) { return cb(null, position) + } const h = new Header(headBuf) - if (!h.cksumValid) + if (!h.cksumValid) { return cb(null, position) + } const entryBlockSize = 512 * Math.ceil(h.size / 512) - if (position + entryBlockSize + 512 > size) + if (position + entryBlockSize + 512 > size) { return cb(null, position) + } position += entryBlockSize + 512 - if (position >= size) + if (position >= size) { return cb(null, position) + } - if (opt.mtimeCache) + if (opt.mtimeCache) { opt.mtimeCache.set(h.path, h.mtime) + } bufPos = 0 fs.read(fd, headBuf, 0, 512, position, onread) } @@ -165,16 +183,19 @@ const replace = (opt, files, cb) => { return fs.open(opt.file, flag, onopen) } - if (er) + if (er) { return reject(er) + } fs.fstat(fd, (er, st) => { - if (er) + if (er) { return fs.close(fd, () => reject(er)) + } getPos(fd, st.size, (er, position) => { - if (er) + if (er) { return reject(er) + } const stream = new fsm.WriteStream(opt.file, { fd: fd, start: position, @@ -201,8 +222,9 @@ const addFilesSync = (p, files) => { noResume: true, onentry: entry => p.add(entry), }) - } else + } else { p.add(file) + } }) p.end() } @@ -216,8 +238,9 @@ const addFilesAsync = (p, files) => { noResume: true, onentry: entry => p.add(entry), }).then(_ => addFilesAsync(p, files)) - } else + } else { p.add(file) + } } p.end() } diff --git a/lib/unpack.js b/lib/unpack.js index 7d39dc0f..458f593d 100644 --- a/lib/unpack.js +++ b/lib/unpack.js @@ -66,21 +66,24 @@ const isWindows = platform === 'win32' // See: https://github.com/npm/node-tar/issues/183 /* istanbul ignore next */ const unlinkFile = (path, cb) => { - if (!isWindows) + if (!isWindows) { return fs.unlink(path, cb) + } const name = path + '.DELETE.' + crypto.randomBytes(16).toString('hex') fs.rename(path, name, er => { - if (er) + if (er) { return cb(er) + } fs.unlink(name, cb) }) } /* istanbul ignore next */ const unlinkFileSync = path => { - if (!isWindows) + if (!isWindows) { return fs.unlinkSync(path) + } const name = path + '.DELETE.' + crypto.randomBytes(16).toString('hex') fs.renameSync(path, name) @@ -109,20 +112,23 @@ const pruneCache = (cache, abs) => { abs = cacheKeyNormalize(abs) for (const path of cache.keys()) { const pnorm = cacheKeyNormalize(path) - if (pnorm === abs || pnorm.indexOf(abs + '/') === 0) + if (pnorm === abs || pnorm.indexOf(abs + '/') === 0) { cache.delete(path) + } } } const dropCache = cache => { - for (const key of cache.keys()) + for (const key of cache.keys()) { cache.delete(key) + } } class Unpack extends Parser { constructor (opt) { - if (!opt) + if (!opt) { opt = {} + } opt.ondone = _ => { this[ENDED] = true @@ -147,8 +153,9 @@ class Unpack extends Parser { if (typeof opt.uid === 'number' || typeof opt.gid === 'number') { // need both or neither - if (typeof opt.uid !== 'number' || typeof opt.gid !== 'number') + if (typeof opt.uid !== 'number' || typeof opt.gid !== 'number') { throw new TypeError('cannot set owner without number uid and gid') + } if (opt.preserveOwner) { throw new TypeError( 'cannot preserve owner in archive and also set owner explicitly') @@ -163,10 +170,11 @@ class Unpack extends Parser { } // default true for root - if (opt.preserveOwner === undefined && typeof opt.uid !== 'number') + if (opt.preserveOwner === undefined && typeof opt.uid !== 'number') { this.preserveOwner = process.getuid && process.getuid() === 0 - else + } else { this.preserveOwner = !!opt.preserveOwner + } this.processUid = (this.preserveOwner || this.setOwner) && process.getuid ? process.getuid() : null @@ -215,8 +223,9 @@ class Unpack extends Parser { // when extracting. Mark those errors as unrecoverable, because // the Unpack contract cannot be met. warn (code, msg, data = {}) { - if (code === 'TAR_BAD_ARCHIVE' || code === 'TAR_ABORT') + if (code === 'TAR_BAD_ARCHIVE' || code === 'TAR_ABORT') { data.recoverable = false + } return super.warn(code, msg, data) } @@ -232,16 +241,18 @@ class Unpack extends Parser { [CHECKPATH] (entry) { if (this.strip) { const parts = normPath(entry.path).split('/') - if (parts.length < this.strip) + if (parts.length < this.strip) { return false + } entry.path = parts.slice(this.strip).join('/') if (entry.type === 'Link') { const linkparts = normPath(entry.linkpath).split('/') - if (linkparts.length >= this.strip) + if (linkparts.length >= this.strip) { entry.linkpath = linkparts.slice(this.strip).join('/') - else + } else { return false + } } } @@ -267,10 +278,11 @@ class Unpack extends Parser { } } - if (path.isAbsolute(entry.path)) + if (path.isAbsolute(entry.path)) { entry.absolute = normPath(path.resolve(entry.path)) - else + } else { entry.absolute = normPath(path.resolve(this.cwd, entry.path)) + } // if we somehow ended up with a path that escapes the cwd, and we are // not in preservePaths mode, then something is fishy! This should have @@ -292,8 +304,9 @@ class Unpack extends Parser { // may not replace the cwd with a different kind of thing entirely. if (entry.absolute === this.cwd && entry.type !== 'Directory' && - entry.type !== 'GNUDumpDir') + entry.type !== 'GNUDumpDir') { return false + } // only encode : chars that aren't drive letter indicators if (this.win32) { @@ -307,17 +320,20 @@ class Unpack extends Parser { } [ONENTRY] (entry) { - if (!this[CHECKPATH](entry)) + if (!this[CHECKPATH](entry)) { return entry.resume() + } assert.equal(typeof entry.absolute, 'string') switch (entry.type) { case 'Directory': case 'GNUDumpDir': - if (entry.mode) + if (entry.mode) { entry.mode = entry.mode | 0o700 + } + // eslint-disable-next-line no-fallthrough case 'File': case 'OldFile': case 'ContiguousFile': @@ -337,10 +353,10 @@ class Unpack extends Parser { // Cwd has to exist, or else nothing works. That's serious. // Other errors are warnings, which raise the error in strict // mode, but otherwise continue on. - if (er.name === 'CwdError') + if (er.name === 'CwdError') { this.emit('error', er) - else { - this.warn('TAR_ENTRY_ERROR', er, {entry}) + } else { + this.warn('TAR_ENTRY_ERROR', er, { entry }) this[UNPEND]() entry.resume() } @@ -390,8 +406,9 @@ class Unpack extends Parser { autoClose: false, }) stream.on('error', er => { - if (stream.fd) + if (stream.fd) { fs.close(stream.fd, () => {}) + } // flush all the data out so that we aren't left hanging // if the error wasn't actually fatal. otherwise the parse @@ -405,8 +422,9 @@ class Unpack extends Parser { const done = er => { if (er) { /* istanbul ignore else - we should always have a fd by now */ - if (stream.fd) + if (stream.fd) { fs.close(stream.fd, () => {}) + } this[ONERROR](er, entry) fullyDone() @@ -415,10 +433,11 @@ class Unpack extends Parser { if (--actions === 0) { fs.close(stream.fd, er => { - if (er) + if (er) { this[ONERROR](er, entry) - else + } else { this[UNPEND]() + } fullyDone() }) } @@ -498,7 +517,7 @@ class Unpack extends Parser { [UNSUPPORTED] (entry) { entry.unsupported = true this.warn('TAR_ENTRY_UNSUPPORTED', - `unsupported entry type: ${entry.type}`, {entry}) + `unsupported entry type: ${entry.type}`, { entry }) entry.resume() } @@ -540,8 +559,9 @@ class Unpack extends Parser { [CHECKFS] (entry) { this[PEND]() const paths = [entry.path] - if (entry.linkpath) + if (entry.linkpath) { paths.push(entry.linkpath) + } this.reservations.reserve(paths, done => this[CHECKFS2](entry, done)) } @@ -556,10 +576,11 @@ class Unpack extends Parser { // entry, it'll just fail to unpack, but a symlink to a directory, using an // 8.3 shortname or certain unicode attacks, can evade detection and lead // to arbitrary writes to anywhere on the system. - if (entry.type === 'SymbolicLink') + if (entry.type === 'SymbolicLink') { dropCache(this.dirCache) - else if (entry.type !== 'Directory') + } else if (entry.type !== 'Directory') { pruneCache(this.dirCache, entry.absolute) + } } [CHECKFS2] (entry, fullyDone) { @@ -606,8 +627,9 @@ class Unpack extends Parser { done() return } - if (lstatEr || this[ISREUSABLE](entry, st)) + if (lstatEr || this[ISREUSABLE](entry, st)) { return this[MAKEFS](null, entry, done) + } if (st.isDirectory()) { if (entry.type === 'Directory') { @@ -615,8 +637,9 @@ class Unpack extends Parser { entry.mode && (st.mode & 0o7777) !== entry.mode const afterChmod = er => this[MAKEFS](er, entry, done) - if (!needChmod) + if (!needChmod) { return afterChmod() + } return fs.chmod(entry.absolute, entry.mode, afterChmod) } // Not a dir entry, have to remove it. @@ -634,18 +657,20 @@ class Unpack extends Parser { // not a dir, and not reusable // don't remove if the cwd, we want that error - if (entry.absolute === this.cwd) + if (entry.absolute === this.cwd) { return this[MAKEFS](null, entry, done) + } unlinkFile(entry.absolute, er => this[MAKEFS](er, entry, done)) }) } - if (this[CHECKED_CWD]) + if (this[CHECKED_CWD]) { start() - else + } else { checkCwd() + } } [MAKEFS] (er, entry, done) { @@ -676,9 +701,9 @@ class Unpack extends Parser { [LINK] (entry, linkpath, link, done) { // XXX: get the type ('symlink' or 'junction') for windows fs[link](linkpath, entry.absolute, er => { - if (er) + if (er) { this[ONERROR](er, entry) - else { + } else { this[UNPEND]() entry.resume() } @@ -704,8 +729,9 @@ class UnpackSync extends Unpack { if (!this[CHECKED_CWD]) { const er = this[MKDIR](this.cwd, this.dmode) - if (er) + if (er) { return this[ONERROR](er, entry) + } this[CHECKED_CWD] = true } @@ -715,17 +741,20 @@ class UnpackSync extends Unpack { const parent = normPath(path.dirname(entry.absolute)) if (parent !== this.cwd) { const mkParent = this[MKDIR](parent, this.dmode) - if (mkParent) + if (mkParent) { return this[ONERROR](mkParent, entry) + } } } const [lstatEr, st] = callSync(() => fs.lstatSync(entry.absolute)) - if (st && (this.keep || this.newer && st.mtime > entry.mtime)) + if (st && (this.keep || this.newer && st.mtime > entry.mtime)) { return this[SKIP](entry) + } - if (lstatEr || this[ISREUSABLE](entry, st)) + if (lstatEr || this[ISREUSABLE](entry, st)) { return this[MAKEFS](null, entry) + } if (st.isDirectory()) { if (entry.type === 'Directory') { @@ -759,8 +788,9 @@ class UnpackSync extends Unpack { } catch (e) { closeError = e } - if (er || closeError) + if (er || closeError) { this[ONERROR](er || closeError, entry) + } done() } diff --git a/lib/update.js b/lib/update.js index a5784b73..ded977dc 100644 --- a/lib/update.js +++ b/lib/update.js @@ -9,14 +9,17 @@ const r = require('./replace.js') module.exports = (opt_, files, cb) => { const opt = hlo(opt_) - if (!opt.file) + if (!opt.file) { throw new TypeError('file is required') + } - if (opt.gzip) + if (opt.gzip) { throw new TypeError('cannot append to compressed archives') + } - if (!files || !Array.isArray(files) || !files.length) + if (!files || !Array.isArray(files) || !files.length) { throw new TypeError('no files or directories specified') + } files = Array.from(files) @@ -27,8 +30,9 @@ module.exports = (opt_, files, cb) => { const mtimeFilter = opt => { const filter = opt.filter - if (!opt.mtimeCache) + if (!opt.mtimeCache) { opt.mtimeCache = new Map() + } opt.filter = filter ? (path, stat) => filter(path, stat) && !(opt.mtimeCache.get(path) > stat.mtime) diff --git a/lib/warn-mixin.js b/lib/warn-mixin.js index aeebb531..a9406396 100644 --- a/lib/warn-mixin.js +++ b/lib/warn-mixin.js @@ -1,10 +1,12 @@ 'use strict' module.exports = Base => class extends Base { warn (code, message, data = {}) { - if (this.file) + if (this.file) { data.file = this.file - if (this.cwd) + } + if (this.cwd) { data.cwd = this.cwd + } data.code = message instanceof Error && message.code || code data.tarCode = code if (!this.strict && data.recoverable !== false) { @@ -13,9 +15,10 @@ module.exports = Base => class extends Base { message = message.message } this.emit('warn', data.tarCode, message, data) - } else if (message instanceof Error) + } else if (message instanceof Error) { this.emit('error', Object.assign(message, data)) - else + } else { this.emit('error', Object.assign(new Error(`${code}: ${message}`), data)) + } } } diff --git a/lib/write-entry.js b/lib/write-entry.js index 3702f2ae..cad969ff 100644 --- a/lib/write-entry.js +++ b/lib/write-entry.js @@ -8,8 +8,9 @@ const normPath = require('./normalize-windows-path.js') const stripSlash = require('./strip-trailing-slashes.js') const prefixPath = (path, prefix) => { - if (!prefix) + if (!prefix) { return normPath(path) + } path = normPath(path).replace(/^\.(\/|$)/, '') return stripSlash(prefix) + '/' + path } @@ -44,8 +45,9 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { constructor (p, opt) { opt = opt || {} super(opt) - if (typeof p !== 'string') + if (typeof p !== 'string') { throw new TypeError('path is required') + } this.path = normPath(p) // suppress atime, ctime, uid, gid, uname, gname this.portable = !!opt.portable @@ -72,8 +74,9 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { this.pos = null this.remain = null - if (typeof opt.onwarn === 'function') + if (typeof opt.onwarn === 'function') { this.on('warn', opt.onwarn) + } let pathWarn = false if (!this.preservePaths) { @@ -94,8 +97,9 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { this.absolute = normPath(opt.absolute || path.resolve(this.cwd, p)) - if (this.path === '') + if (this.path === '') { this.path = './' + } if (pathWarn) { this.warn('TAR_ENTRY_INFO', `stripping ${pathWarn} from absolute path`, { @@ -104,22 +108,25 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { }) } - if (this.statCache.has(this.absolute)) + if (this.statCache.has(this.absolute)) { this[ONLSTAT](this.statCache.get(this.absolute)) - else + } else { this[LSTAT]() + } } emit (ev, ...data) { - if (ev === 'error') + if (ev === 'error') { this[HAD_ERROR] = true + } return super.emit(ev, ...data) } [LSTAT] () { fs.lstat(this.absolute, (er, stat) => { - if (er) + if (er) { return this.emit('error', er) + } this[ONLSTAT](stat) }) } @@ -127,8 +134,9 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { [ONLSTAT] (stat) { this.statCache.set(this.absolute, stat) this.stat = stat - if (!stat.isFile()) + if (!stat.isFile()) { stat.size = 0 + } this.type = getType(stat) this.emit('stat', stat) this[PROCESS]() @@ -153,8 +161,9 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { } [HEADER] () { - if (this.type === 'Directory' && this.portable) + if (this.type === 'Directory' && this.portable) { this.noMtime = true + } this.header = new Header({ path: this[PREFIX](this.path), @@ -196,8 +205,9 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { } [DIRECTORY] () { - if (this.path.substr(-1) !== '/') + if (this.path.substr(-1) !== '/') { this.path += '/' + } this.stat.size = 0 this[HEADER]() this.end() @@ -205,8 +215,9 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { [SYMLINK] () { fs.readlink(this.absolute, (er, linkpath) => { - if (er) + if (er) { return this.emit('error', er) + } this[ONREADLINK](linkpath) }) } @@ -230,31 +241,35 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { const linkKey = this.stat.dev + ':' + this.stat.ino if (this.linkCache.has(linkKey)) { const linkpath = this.linkCache.get(linkKey) - if (linkpath.indexOf(this.cwd) === 0) + if (linkpath.indexOf(this.cwd) === 0) { return this[HARDLINK](linkpath) + } } this.linkCache.set(linkKey, this.absolute) } this[HEADER]() - if (this.stat.size === 0) + if (this.stat.size === 0) { return this.end() + } this[OPENFILE]() } [OPENFILE] () { fs.open(this.absolute, 'r', (er, fd) => { - if (er) + if (er) { return this.emit('error', er) + } this[ONOPENFILE](fd) }) } [ONOPENFILE] (fd) { this.fd = fd - if (this[HAD_ERROR]) + if (this[HAD_ERROR]) { return this[CLOSE]() + } this.blockLen = 512 * Math.ceil(this.stat.size / 512) this.blockRemain = this.blockLen @@ -318,10 +333,11 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { this.buf : this.buf.slice(this.offset, this.offset + bytesRead) const flushed = this.write(writeBuf) - if (!flushed) + if (!flushed) { this[AWAITDRAIN](() => this[ONDRAIN]()) - else + } else { this[ONDRAIN]() + } } [AWAITDRAIN] (cb) { @@ -343,8 +359,9 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { [ONDRAIN] () { if (!this.remain) { - if (this.blockRemain) + if (this.blockRemain) { super.write(Buffer.alloc(this.blockRemain)) + } return this[CLOSE](er => er ? this.emit('error', er) : this.end()) } @@ -412,8 +429,9 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass { this.readEntry = readEntry this.type = readEntry.type - if (this.type === 'Directory' && this.portable) + if (this.type === 'Directory' && this.portable) { this.noMtime = true + } this.prefix = opt.prefix || null @@ -429,8 +447,9 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass { this.ctime = this.portable ? null : readEntry.ctime this.linkpath = normPath(readEntry.linkpath) - if (typeof opt.onwarn === 'function') + if (typeof opt.onwarn === 'function') { this.on('warn', opt.onwarn) + } let pathWarn = false if (!this.preservePaths) { @@ -500,15 +519,17 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass { write (data) { const writeLen = data.length - if (writeLen > this.blockRemain) + if (writeLen > this.blockRemain) { throw new Error('writing more to entry than is appropriate') + } this.blockRemain -= writeLen return super.write(data) } end () { - if (this.blockRemain) + if (this.blockRemain) { super.write(Buffer.alloc(this.blockRemain)) + } return super.end() } }) diff --git a/map.js b/map.js index adeceef6..1d7e33ae 100644 --- a/map.js +++ b/map.js @@ -1,4 +1,4 @@ -const {basename} = require('path') +const { basename } = require('path') const map = test => test === 'index.js' || test === 'map.js' ? test diff --git a/scripts/generate-parse-fixtures.js b/scripts/generate-parse-fixtures.js index 0310f835..b46e8bd7 100644 --- a/scripts/generate-parse-fixtures.js +++ b/scripts/generate-parse-fixtures.js @@ -5,8 +5,8 @@ const path = require('path') const tardir = path.resolve(__dirname, '../test/fixtures/tars') const parsedir = path.resolve(__dirname, '../test/fixtures/parse') const maxMetaOpt = [250, null] -const filterOpt = [ true, false ] -const strictOpt = [ true, false ] +const filterOpt = [true, false] +const strictOpt = [true, false] const makeTest = (tarfile, tardata, maxMeta, filter, strict) => { const o = @@ -19,7 +19,7 @@ const makeTest = (tarfile, tardata, maxMeta, filter, strict) => { const p = new Parse({ maxMetaEntrySize: maxMeta, filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict + strict: strict, }) const events = [] @@ -62,8 +62,8 @@ const makeTest = (tarfile, tardata, maxMeta, filter, strict) => { xstarPrefix: entry.header.xstarPrefix, prefixTerminator: entry.header.prefixTerminator, atime: entry.header.atime, - ctime: entry.header.atime - } + ctime: entry.header.atime, + }, }]) entry.resume() } @@ -73,7 +73,7 @@ const makeTest = (tarfile, tardata, maxMeta, filter, strict) => { p.on('warn', (code, message, data) => events.push(['warn', code, message])) p.on('error', er => events.push(['error', { message: er.message, - code: er.code + code: er.code, }])) p.on('end', _ => events.push(['end'])) p.on('nullBlock', _ => events.push(['nullBlock'])) @@ -85,13 +85,12 @@ const makeTest = (tarfile, tardata, maxMeta, filter, strict) => { fs.writeFileSync(eventsfile, JSON.stringify(events, null, 2) + '\n') } - fs.readdirSync(tardir) -.forEach(tar => { - const tarfile = tardir + '/' + tar - const tardata = fs.readFileSync(tarfile) - maxMetaOpt.forEach(maxMeta => - filterOpt.forEach(filter => - strictOpt.forEach(strict => - makeTest(tarfile, tardata, maxMeta, filter, strict)))) -}) + .forEach(tar => { + const tarfile = tardir + '/' + tar + const tardata = fs.readFileSync(tarfile) + maxMetaOpt.forEach(maxMeta => + filterOpt.forEach(filter => + strictOpt.forEach(strict => + makeTest(tarfile, tardata, maxMeta, filter, strict)))) + }) diff --git a/test/create.js b/test/create.js index c30aa286..fdfd78b8 100644 --- a/test/create.js +++ b/test/create.js @@ -13,7 +13,7 @@ const mkdirp = require('mkdirp') const spawn = require('child_process').spawn const Pack = require('../lib/pack.js') const mutateFS = require('mutate-fs') -const {promisify} = require('util') +const { promisify } = require('util') const readtar = (file, cb) => { const child = spawn('tar', ['tf', file]) @@ -62,8 +62,9 @@ t.test('create file', t => { file: file, cwd: __dirname, }, files, er => { - if (er) + if (er) { throw er + } readtar(file, (code, signal, list) => { t.equal(code, 0) t.equal(signal, null) @@ -114,8 +115,9 @@ t.test('create file', t => { file: file, cwd: __dirname, }, files, er => { - if (er) + if (er) { throw er + } readtar(file, (code, signal, list) => { t.equal(code, 0) t.equal(signal, null) @@ -193,16 +195,17 @@ t.test('create tarball out of another tarball', t => { list({ f: out, sync: true, onentry: entry => { - if (entry.path === 'hardlink-2') + if (entry.path === 'hardlink-2') { t.equal(entry.type, 'Link') - else if (entry.path === 'symlink') + } else if (entry.path === 'symlink') { t.equal(entry.type, 'SymbolicLink') - else if (entry.path === 'dir/') + } else if (entry.path === 'dir/') { t.equal(entry.type, 'Directory') - else + } else { t.equal(entry.type, 'File') + } t.equal(entry.path, expect.shift()) - }}) + } }) t.same(expect, []) t.end() } diff --git a/test/extract.js b/test/extract.js index 16a52bd9..ae13739c 100644 --- a/test/extract.js +++ b/test/extract.js @@ -7,7 +7,7 @@ const fs = require('fs') const extractdir = path.resolve(__dirname, 'fixtures/extract') const tars = path.resolve(__dirname, 'fixtures/tars') const mkdirp = require('mkdirp') -const {promisify} = require('util') +const { promisify } = require('util') const rimraf = promisify(require('rimraf')) const mutateFS = require('mutate-fs') @@ -44,8 +44,9 @@ t.test('basic extracting', t => { t.test('async cb', t => { return x({ file: file, cwd: dir }, files, er => { - if (er) + if (er) { throw er + } return check(t) }) }) @@ -87,8 +88,9 @@ t.test('file list and filter', t => { t.test('async cb', t => { return x({ filter: filter, file: file, cwd: dir }, ['🌟.txt', 'Ί.txt'], er => { - if (er) + if (er) { throw er + } return check(t) }) }) @@ -127,8 +129,9 @@ t.test('no file list', t => { t.test('async cb', t => { return x({ file: file, cwd: dir }, er => { - if (er) + if (er) { throw er + } return check(t) }) }) @@ -168,8 +171,9 @@ t.test('read in itty bits', t => { t.test('async cb', t => { return x({ file: file, cwd: dir, maxReadSize: maxReadSize }, er => { - if (er) + if (er) { throw er + } return check(t) }) }) @@ -179,8 +183,8 @@ t.test('read in itty bits', t => { t.test('bad calls', t => { t.throws(_ => x(_ => _)) - t.throws(_ => x({sync: true}, _ => _)) - t.throws(_ => x({sync: true}, [], _ => _)) + t.throws(_ => x({ sync: true }, _ => _)) + t.throws(_ => x({ sync: true }, [], _ => _)) t.end() }) @@ -188,12 +192,12 @@ t.test('no file', t => { const Unpack = require('../lib/unpack.js') t.type(x(), Unpack) t.type(x(['asdf']), Unpack) - t.type(x({sync: true}), Unpack.Sync) + t.type(x({ sync: true }), Unpack.Sync) t.end() }) t.test('nonexistent', t => { - t.throws(_ => x({sync: true, file: 'does not exist' })) + t.throws(_ => x({ sync: true, file: 'does not exist' })) x({ file: 'does not exist' }).catch(_ => t.end()) }) @@ -201,7 +205,7 @@ t.test('read fail', t => { const poop = new Error('poop') t.teardown(mutateFS.fail('read', poop)) - t.throws(_ => x({maxReadSize: 10, sync: true, file: __filename }), poop) + t.throws(_ => x({ maxReadSize: 10, sync: true, file: __filename }), poop) t.end() }) diff --git a/test/fixtures/test.js b/test/fixtures/test.js index e1a34da7..1c2b3ca6 100644 --- a/test/fixtures/test.js +++ b/test/fixtures/test.js @@ -1,5 +1,5 @@ const platform = process.platform === 'win32' ? 'win32' : 'posix' -const {spawn} = require('child_process') +const { spawn } = require('child_process') const c = spawn(process.execPath, [ process.env.npm_execpath, 'run', diff --git a/test/get-write-flag.js b/test/get-write-flag.js index e527fe45..81c2f547 100644 --- a/test/get-write-flag.js +++ b/test/get-write-flag.js @@ -21,8 +21,9 @@ switch (process.argv[2]) { } } const { O_CREAT, O_TRUNC, O_WRONLY } = fs.constants - if (platform !== 'win32') + if (platform !== 'win32') { process.env.__FAKE_PLATFORM__ = 'win32' + } const getFlag = require('../lib/get-write-flag.js') t.equal(getFlag(1), UV_FS_O_FILEMAP | O_TRUNC | O_CREAT | O_WRONLY) t.equal(getFlag(512 * 1024 + 1), 'w') @@ -38,8 +39,9 @@ switch (process.argv[2]) { }, } } - if (platform !== 'win32') + if (platform !== 'win32') { process.env.__FAKE_PLATFORM__ = 'win32' + } const getFlag = require('../lib/get-write-flag.js') t.equal(getFlag(1), 'w') t.equal(getFlag(512 * 1024 + 1), 'w') @@ -47,8 +49,9 @@ switch (process.argv[2]) { } case 'unix': { - if (platform === 'win32') + if (platform === 'win32') { process.env.__FAKE_PLATFORM__ = 'darwin' + } const getFlag = require('../lib/get-write-flag.js') t.equal(getFlag(1), 'w') t.equal(getFlag(512 * 1024 + 1), 'w') diff --git a/test/list.js b/test/list.js index 33c03d7d..26f59d9f 100644 --- a/test/list.js +++ b/test/list.js @@ -48,8 +48,9 @@ t.test('basic', t => { onentry: onentry, maxReadSize: maxReadSize, }, er => { - if (er) + if (er) { throw er + } check(actual, t) t.end() }) diff --git a/test/make-tar.js b/test/make-tar.js index 33de124b..668d2164 100644 --- a/test/make-tar.js +++ b/test/make-tar.js @@ -1,7 +1,8 @@ 'use strict' // a little utility to create virtual tar data -if (module === require.main) +if (module === require.main) { return require('tap').pass('this is fine') +} const Header = require('../lib/header.js') module.exports = chunks => { @@ -16,10 +17,11 @@ module.exports = chunks => { : 512) dataLen += size const buf = Buffer.alloc(size) - if (typeof chunk === 'string') + if (typeof chunk === 'string') { buf.write(chunk) - else + } else { new Header(chunk).encode(buf, 0) + } return buf }), dataLen) } diff --git a/test/normalize-windows-path.js b/test/normalize-windows-path.js index 3081fa0a..e9c705ab 100644 --- a/test/normalize-windows-path.js +++ b/test/normalize-windows-path.js @@ -4,10 +4,11 @@ const realPlatform = process.platform const fakePlatform = realPlatform === 'win32' ? 'posix' : 'win32' t.test('posix', t => { - if (realPlatform === 'win32') + if (realPlatform === 'win32') { process.env.TESTING_TAR_FAKE_PLATFORM = fakePlatform - else + } else { delete process.env.TESTING_TAR_FAKE_PLATFORM + } const normPath = t.mock('../lib/normalize-windows-path.js') t.equal(normPath('/some/path/back\\slashes'), '/some/path/back\\slashes') t.equal(normPath('c:\\foo\\bar'), 'c:\\foo\\bar') @@ -15,10 +16,11 @@ t.test('posix', t => { }) t.test('win32', t => { - if (realPlatform !== 'win32') + if (realPlatform !== 'win32') { process.env.TESTING_TAR_FAKE_PLATFORM = fakePlatform - else + } else { delete process.env.TESTING_TAR_FAKE_PLATFORM + } const normPath = t.mock('../lib/normalize-windows-path.js') t.equal(normPath('/some/path/back\\slashes'), '/some/path/back/slashes') t.equal(normPath('c:\\foo\\bar'), 'c:/foo/bar') diff --git a/test/pack.js b/test/pack.js index 2df29614..8906ae30 100644 --- a/test/pack.js +++ b/test/pack.js @@ -80,8 +80,9 @@ t.test('pack a file', t => { ps.on('data', chunk => sout.push(chunk)) ps.add('one-byte.txt').end() const sync = Buffer.concat(sout) - if (sync.length === 0) + if (sync.length === 0) { throw new Error('no data!') + } t.equal(sync.slice(512).toString(), data.slice(512).toString()) const hs = new Header(sync) @@ -392,12 +393,13 @@ t.test('gzip, also a very deep path', t => { for (var i = 0; i < data.length; i += 512) { const slice = data.slice(i, i + 512) const h = new Header(slice) - if (h.nullBlock) + if (h.nullBlock) { entries.push('null block') - else if (h.cksumValid) + } else if (h.cksumValid) { entries.push([h.type, h.path]) - else if (entries[entries.length - 1][0] === 'File') + } else if (entries[entries.length - 1][0] === 'File') { entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) + } } const expect = [ @@ -471,12 +473,13 @@ t.test('very deep gzip path, sync', t => { for (var i = 0; i < data.length; i += 512) { const slice = data.slice(i, i + 512) const h = new Header(slice) - if (h.nullBlock) + if (h.nullBlock) { entries.push('null block') - else if (h.cksumValid) + } else if (h.cksumValid) { entries.push([h.type, h.path]) - else if (entries[entries.length - 1][0] === 'File') + } else if (entries[entries.length - 1][0] === 'File') { entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) + } } const expect = [ @@ -664,10 +667,12 @@ t.test('ignores mid-queue', t => { const p = new Pack({ cwd: tars, filter: (p, st) => { - if (p === './') + if (p === './') { return true - if (!didFirst) + } + if (!didFirst) { return didFirst = true + } return false }, }) @@ -1116,10 +1121,11 @@ t.test('prefix and hard links', t => { const check = (out, t) => { const data = Buffer.concat(out) expect.forEach((e, i) => { - if (typeof e === 'string') + if (typeof e === 'string') { t.equal(data.slice(i * 512, i * 512 + e.length).toString(), e) - else + } else { t.match(new Header(data.slice(i * 512, (i + 1) * 512)), e) + } }) t.end() } @@ -1134,8 +1140,9 @@ t.test('prefix and hard links', t => { p.on('data', d => out.push(d)) p.on('end', () => check(out, t)) p.write(path) - if (path === '.') + if (path === '.') { path = './' + } p.write(`${path}target`) p.write(`${path}y`) p.write(`${path}z`) diff --git a/test/parse.js b/test/parse.js index 920b0c42..97705e42 100644 --- a/test/parse.js +++ b/test/parse.js @@ -14,8 +14,9 @@ const EE = require('events').EventEmitter t.test('fixture tests', t => { class ByteStream extends MiniPass { write (chunk) { - for (let i = 0; i < chunk.length - 1; i++) + for (let i = 0; i < chunk.length - 1; i++) { super.write(chunk.slice(i, i + 1)) + } return super.write(chunk.slice(chunk.length - 1, chunk.length)) } @@ -26,10 +27,11 @@ t.test('fixture tests', t => { let cursor = 0 p.on('entry', entry => { ok = ok && t.match(['entry', entry], expect[cursor++], entry.path) - if (slow) + if (slow) { setTimeout(_ => entry.resume()) - else + } else { entry.resume() + } }) p.on('ignoredEntry', entry => { ok = ok && t.match(['ignoredEntry', entry], expect[cursor++], @@ -331,21 +333,24 @@ t.test('drain event timings', t => { onentry: entry => { t.equal(entry.path, expect.shift()) currentEntry = entry - if (autoPipe) + if (autoPipe) { setTimeout(_ => entry.pipe(new SlowStream())) + } }, }) data.forEach(d => { - if (!t.equal(p.write(d), false, 'write should return false')) + if (!t.equal(p.write(d), false, 'write should return false')) { return t.end() + } }) let interval const go = _ => { const d = data.shift() - if (d === undefined) + if (d === undefined) { return p.end() + } let paused if (currentEntry) { @@ -366,13 +371,15 @@ t.test('drain event timings', t => { paused = true } - if (!t.equal(p.write(hunks[1]), false, 'write should return false: ' + d)) + if (!t.equal(p.write(hunks[1]), false, 'write should return false: ' + d)) { return t.end() + } p.once('drain', go) - if (paused) + if (paused) { currentEntry.resume() + } } p.once('drain', go) @@ -444,8 +451,9 @@ t.test('consume while consuming', t => { const first = data.slice(0, size) const rest = data.slice(size) p.once('entry', entry => { - for (let pos = 0; pos < rest.length; pos += size) + for (let pos = 0; pos < rest.length; pos += size) { p.write(rest.slice(pos, pos + size)) + } p.end() }) diff --git a/test/path-reservations.js b/test/path-reservations.js index e73f7431..9a1d7a77 100644 --- a/test/path-reservations.js +++ b/test/path-reservations.js @@ -1,14 +1,16 @@ const t = require('tap') // load up the posix and windows versions of the reserver -if (process.platform === 'win32') +if (process.platform === 'win32') { process.env.TESTING_TAR_FAKE_PLATFORM = 'posix' +} const { reserve } = t.mock('../lib/path-reservations.js', { path: require('path').posix, })() delete process.env.TESTING_TAR_FAKE_PLATFORM -if (process.platform !== 'win32') +if (process.platform !== 'win32') { process.env.TESTING_TAR_FAKE_PLATFORM = 'win32' +} const { reserve: winReserve } = t.mock('../lib/path-reservations.js', { path: require('path').win32, })() @@ -105,8 +107,9 @@ t.test('absolute paths and trailing slash', t => { t.equal(calledA2, false, 'called a2 only once') calledA2 = true done() - if (calledR2) + if (calledR2) { t.end() + } } let calledR1 = false let calledR2 = false @@ -121,8 +124,9 @@ t.test('absolute paths and trailing slash', t => { t.equal(calledR2, false, 'called r1 only once') calledR2 = true done() - if (calledA2) + if (calledA2) { t.end() + } } t.ok(reserve(['/p/a/t/h'], a1)) t.notOk(reserve(['/p/a/t/h/'], a2)) diff --git a/test/pax.js b/test/pax.js index 25ea5be9..cef9fc51 100644 --- a/test/pax.js +++ b/test/pax.js @@ -72,7 +72,7 @@ t.test('null pax', t => { t.test('tiny pax', t => { // weird to have a global setting a path. Maybe this should be // an error? - const p = new Pax({path: 'ab'}, true) + const p = new Pax({ path: 'ab' }, true) const actual = p.encode() // console.log(actual.toString('hex').split('').reduce((s,c)=>{if(s[s.length-1].length<64)s[s.length-1]+=c;else s.push(c);return s},[''])) // return Promise.resolve() diff --git a/test/replace.js b/test/replace.js index 80326b72..62c41eb8 100644 --- a/test/replace.js +++ b/test/replace.js @@ -5,7 +5,7 @@ const path = require('path') const fs = require('fs') const mutateFS = require('mutate-fs') const list = require('../lib/list.js') -const {resolve} = require('path') +const { resolve } = require('path') const fixtures = path.resolve(__dirname, 'fixtures') const tars = path.resolve(fixtures, 'tars') @@ -80,8 +80,9 @@ t.test('basic file add to archive (good or truncated)', t => { file: resolve(dir, file), cwd: __dirname, }, fileList, er => { - if (er) + if (er) { throw er + } check(resolve(dir, file), t) }) }) @@ -156,8 +157,9 @@ t.test('add to empty archive', t => { file: resolve(dir, file), cwd: __dirname, }, [path.basename(__filename)], er => { - if (er) + if (er) { throw er + } check(resolve(dir, file), t) }) }) @@ -211,7 +213,7 @@ t.test('cannot append to gzipped archives', async t => { t.test('other throws', t => { t.throws(_ => r({}, ['asdf']), new TypeError('file is required')) - t.throws(_ => r({file: 'asdf'}, []), + t.throws(_ => r({ file: 'asdf' }, []), new TypeError('no files or directories specified')) t.end() }) @@ -322,8 +324,9 @@ t.test('mtime cache', async t => { cwd: __dirname, mtimeCache: mtimeCache = new Map(), }, [path.basename(__filename)], er => { - if (er) + if (er) { throw er + } check(file, t) }) }) @@ -358,7 +361,7 @@ t.test('create tarball out of another tarball', t => { sync: true, onentry: entry => { t.equal(entry.path, expect.shift()) - }}) + } }) t.same(expect, []) t.end() } @@ -381,8 +384,9 @@ t.test('create tarball out of another tarball', t => { f: out, cwd: tars, }, ['@utf8.tar'], er => { - if (er) + if (er) { throw er + } check(out, t) }) }) diff --git a/test/strip-absolute-path.js b/test/strip-absolute-path.js index 98c6ec18..3e871a9f 100644 --- a/test/strip-absolute-path.js +++ b/test/strip-absolute-path.js @@ -12,8 +12,9 @@ t.test('basic', t => { 'c:\\c:\\c:\\c:\\\\d:\\e/f/g': ['c:\\c:\\c:\\c:\\\\d:\\', 'e/f/g'], } - for (const [input, [root, stripped]] of Object.entries(cases)) + for (const [input, [root, stripped]] of Object.entries(cases)) { t.strictSame(stripAbsolutePath(input, cwd), [root, stripped], input) + } t.end() }) @@ -44,8 +45,9 @@ t.test('drive-local paths', t => { '\\\\?\\X:\\y\\z': ['\\\\?\\X:\\', 'y\\z'], } for (const [input, [root, stripped]] of Object.entries(cases)) { - if (!t.strictSame(stripAbsolutePath(input, cwd), [root, stripped], input)) + if (!t.strictSame(stripAbsolutePath(input, cwd), [root, stripped], input)) { break + } } t.end() }) diff --git a/test/unpack.js b/test/unpack.js index b6919924..0b8d7231 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -16,7 +16,7 @@ const fixtures = path.resolve(__dirname, 'fixtures') const tars = path.resolve(fixtures, 'tars') const parses = path.resolve(fixtures, 'parse') const unpackdir = path.resolve(fixtures, 'unpack') -const {promisify} = require('util') +const { promisify } = require('util') const rimraf = promisify(require('rimraf')) const mkdirp = require('mkdirp') const mutateFS = require('mutate-fs') @@ -98,8 +98,9 @@ t.test('basic file unpack tests', t => { const expect = cases[tarfile] Object.keys(expect).forEach(file => { const f = path.resolve(dir, file) - if (isWindows && isLongFile(file)) + if (isWindows && isLongFile(file)) { return + } t.equal(fs.readFileSync(f, 'utf8'), expect[file], file) }) t.end() @@ -639,11 +640,11 @@ t.test('unsupported entries', t => { const c = 'TAR_ENTRY_UNSUPPORTED' const expect = [ [c, 'unsupported entry type: CharacterDevice', { - entry: { path: 'dev/random' }}], + entry: { path: 'dev/random' } }], [c, 'unsupported entry type: BlockDevice', { - entry: { path: 'dev/hd0' }}], + entry: { path: 'dev/hd0' } }], [c, 'unsupported entry type: FIFO', { - entry: { path: 'dev/fifo0' }}], + entry: { path: 'dev/fifo0' } }], ] u.on('close', _ => { t.equal(fs.readdirSync(dir).length, 0) @@ -1019,13 +1020,15 @@ t.test('fail all stats', t => { const mutate = () => { fs.stat = fs.lstat = fs.fstat = (...args) => { // don't fail statting the cwd, or we get different errors - if (normPath(args[0]) === dir) + if (normPath(args[0]) === dir) { return lstat(dir, args.pop()) + } process.nextTick(() => args.pop()(poop)) } fs.statSync = fs.lstatSync = fs.fstatSync = (...args) => { - if (normPath(args[0]) === dir) + if (normPath(args[0]) === dir) { return lstatSync(dir) + } throw poop } } @@ -2008,7 +2011,7 @@ t.test('dont use explicit chmod if noChmod flag set', t => { return t.test('sync', t => { mkdirp.sync(basedir) - const unpack = new Unpack.Sync({ cwd: basedir, noChmod: true}) + const unpack = new Unpack.Sync({ cwd: basedir, noChmod: true }) unpack.end(data) check(t) }) @@ -2620,7 +2623,7 @@ t.test('trying to unpack a non-zlib gzip file should fail', t => { const skip = !/^v([0-9]|1[0-3])\./.test(process.version) ? false : 'node prior to v14 did not raise sync zlib errors properly' t.throws(() => new UnpackSync(opts).end(dataGzip), - expect, 'sync throws', {skip}) + expect, 'sync throws', { skip }) }) t.test('bad archive if no gzip', t => { @@ -2882,7 +2885,7 @@ t.test('close fd when error writing', t => { t.teardown(mutateFS.fail('write', new Error('nope'))) const CLOSES = [] const OPENS = {} - const {open} = require('fs') + const { open } = require('fs') t.teardown(() => fs.open = open) fs.open = (...args) => { const cb = args.pop() @@ -2904,8 +2907,9 @@ t.test('close fd when error writing', t => { onwarn: (code, msg) => WARNINGS.push([code, msg]), }) unpack.on('end', () => { - for (const [path, fd] of Object.entries(OPENS)) + for (const [path, fd] of Object.entries(OPENS)) { t.equal(CLOSES.includes(fd), true, 'closed fd for ' + path) + } t.end() }) unpack.end(data) @@ -2934,7 +2938,7 @@ t.test('close fd when error setting mtime', t => { t.teardown(mutateFS.fail('utimes', new Error('nooooope'))) const CLOSES = [] const OPENS = {} - const {open} = require('fs') + const { open } = require('fs') t.teardown(() => fs.open = open) fs.open = (...args) => { const cb = args.pop() @@ -2956,8 +2960,9 @@ t.test('close fd when error setting mtime', t => { onwarn: (code, msg) => WARNINGS.push([code, msg]), }) unpack.on('end', () => { - for (const [path, fd] of Object.entries(OPENS)) + for (const [path, fd] of Object.entries(OPENS)) { t.equal(CLOSES.includes(fd), true, 'closed fd for ' + path) + } t.end() }) unpack.end(data) diff --git a/test/update.js b/test/update.js index 1e182053..0c8675f3 100644 --- a/test/update.js +++ b/test/update.js @@ -5,7 +5,7 @@ const path = require('path') const fs = require('fs') const mutateFS = require('mutate-fs') -const {resolve} = require('path') +const { resolve } = require('path') const fixtures = path.resolve(__dirname, 'fixtures') const tars = path.resolve(fixtures, 'tars') const zlib = require('zlib') @@ -79,8 +79,9 @@ t.test('basic file add to archive (good or truncated)', t => { file: resolve(dir, file), cwd: __dirname, }, fileList, er => { - if (er) + if (er) { throw er + } check(resolve(dir, file), t) }) }) @@ -155,8 +156,9 @@ t.test('add to empty archive', t => { file: resolve(dir, file), cwd: __dirname, }, [path.basename(__filename)], er => { - if (er) + if (er) { throw er + } check(resolve(dir, file), t) }) }) @@ -213,7 +215,7 @@ t.test('cannot append to gzipped archives', t => { t.test('other throws', t => { t.throws(_ => u({}, ['asdf']), new TypeError('file is required')) - t.throws(_ => u({file: 'asdf'}, []), + t.throws(_ => u({ file: 'asdf' }, []), new TypeError('no files or directories specified')) t.end() }) @@ -306,8 +308,9 @@ t.test('do not add older file', t => { t.test('async cb', t => { u({ file, cwd: dir }, ['1024-bytes.txt'], er => { - if (er) + if (er) { throw er + } check(t) }) }) @@ -359,8 +362,9 @@ t.test('do add newer file', t => { const dir = setup(t) const file = resolve(dir, 'body-byte-counts.tar') u({ file, cwd: dir }, ['1024-bytes.txt'], er => { - if (er) + if (er) { throw er + } check(file, t) }) }) diff --git a/test/write-entry.js b/test/write-entry.js index b6cd1c3f..4cad6969 100644 --- a/test/write-entry.js +++ b/test/write-entry.js @@ -4,13 +4,14 @@ const mkdirp = require('mkdirp') // make our tests verify that windows link targets get turned into / paths const fs = require('fs') -const {readlink, readlinkSync} = fs +const { readlink, readlinkSync } = fs fs.readlink = (path, cb) => { readlink(path, (er, path) => { - if (er) + if (er) { return cb(er) - else + } else { cb(null, path.replace(/\//g, '\\')) + } }) } fs.readlinkSync = path => readlinkSync(path).replace(/\//g, '\\') @@ -568,8 +569,9 @@ t.test('read fail', t => { } // pretend everything is a file, then read something that isn't t.teardown(mutateFS.statMutate((er, st) => { - if (er) + if (er) { return [er, st] + } st.isFile = () => true st.size = 123 })) @@ -600,8 +602,9 @@ t.test('read invalid EOF', t => { t.test('read overflow expectation', t => { t.teardown(mutateFS.statMutate((er, st) => { - if (st) + if (st) { st.size = 3 + } })) const f = '512-bytes.txt' const expect = { @@ -698,8 +701,9 @@ t.test('win32 <|>? in paths', { t.test('uid doesnt match, dont set uname', t => { t.teardown(mutateFS.statMutate((er, st) => { - if (st) + if (st) { st.uid -= 1 + } })) const ws = new WriteEntry('long-path/r', { cwd: files, @@ -1246,12 +1250,13 @@ t.test('prefix and hard links', t => { const check = (out, t) => { const data = Buffer.concat(out) expect.forEach((e, i) => { - if (typeof e === 'string') + if (typeof e === 'string') { t.equal(data.slice(i * 512, i * 512 + e.length).toString(), e) - else if (e instanceof RegExp) + } else if (e instanceof RegExp) { t.match(data.slice(i * 512, (i + 1) * 512).toString(), e) - else + } else { t.match(new Header(data.slice(i * 512, (i + 1) * 512)), e) + } }) } @@ -1273,8 +1278,9 @@ t.test('prefix and hard links', t => { }) await entry(path) - if (path === '.') + if (path === '.') { path = './' + } await entry(`${path}target`) await entry(`${path}y`) await entry(`${path}${long}`) @@ -1418,12 +1424,13 @@ t.test('prefix and hard links from tar entries', t => { const check = (out, t) => { const data = Buffer.concat(out) expect.forEach((e, i) => { - if (typeof e === 'string') + if (typeof e === 'string') { t.equal(data.slice(i * 512, i * 512 + e.length).toString(), e) - else if (e instanceof RegExp) + } else if (e instanceof RegExp) { t.match(data.slice(i * 512, (i + 1) * 512).toString(), e) - else + } else { t.match(new Header(data.slice(i * 512, (i + 1) * 512)), e) + } }) } @@ -1512,10 +1519,11 @@ t.test('hard links and no prefix', t => { const check = (out, t) => { const data = Buffer.concat(out) expect.forEach((e, i) => { - if (typeof e === 'string') + if (typeof e === 'string') { t.equal(data.slice(i * 512, i * 512 + e.length).toString(), e) - else + } else { t.match(new Header(data.slice(i * 512, (i + 1) * 512)), e) + } }) } @@ -1535,8 +1543,9 @@ t.test('hard links and no prefix', t => { }) await entry(path) - if (path === '.') + if (path === '.') { path = './' + } await entry(`${path}target`) await entry(`${path}y`) await entry(`${path}z`) @@ -1655,12 +1664,13 @@ t.test('hard links from tar entries and no prefix', t => { const check = (out, t) => { const data = Buffer.concat(out) expect.forEach((e, i) => { - if (typeof e === 'string') + if (typeof e === 'string') { t.equal(data.slice(i * 512, i * 512 + e.length).toString(), e) - else if (e instanceof RegExp) + } else if (e instanceof RegExp) { t.match(data.slice(i * 512, (i + 1) * 512).toString(), e) - else + } else { t.match(new Header(data.slice(i * 512, (i + 1) * 512)), e) + } }) } @@ -1690,7 +1700,7 @@ t.test('hard links from tar entries and no prefix', t => { }) t.test('myuid set by getuid() if available, otherwise 0', t => { - const {getuid} = process + const { getuid } = process process.getuid = null const noUid = new WriteEntry(__filename) t.equal(noUid.myuid, 0, 'set to zero if no getuid function') From e1c5e5881f225fdd996ceb183081aff1871b114f Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Thu, 21 Apr 2022 21:26:36 -0700 Subject: [PATCH 03/96] chore(deps): tap@16.0.1 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 267f7f2f..29ca8762 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "events-to-array": "^1.1.2", "mutate-fs": "^2.1.1", "rimraf": "^2.7.1", - "tap": "^15.0.9", + "tap": "^16.0.1", "tar-fs": "^1.16.3", "tar-stream": "^1.6.2" }, @@ -50,7 +50,7 @@ ], "tap": { "coverage-map": "map.js", - "check-coverage": true + "timeout": 0 }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", From 07bff079122e82419cbd336489ad1107274e5617 Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Tue, 20 Sep 2022 13:48:57 -0700 Subject: [PATCH 04/96] chore: @npmcli/template-oss@4.3.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29ca8762..d86f6d64 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.4.2", + "@npmcli/template-oss": "4.3.2", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", "events-to-array": "^1.1.2", From d5580e7927a6ab21a561d8ab8a9b8025648dadc0 Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Tue, 20 Sep 2022 13:56:19 -0700 Subject: [PATCH 05/96] chore: postinstall for dependabot template-oss PR --- .eslintrc.js | 2 + .github/dependabot.yml | 2 +- .github/matchers/tap.json | 32 ++++ .github/workflows/audit.yml | 32 ++-- .github/workflows/ci-release.yml | 153 +++++++++++++++++ .github/workflows/ci.yml | 85 ++++++---- .github/workflows/codeql-analysis.yml | 28 ++- .github/workflows/post-dependabot.yml | 88 +++++++--- .github/workflows/pull-request.yml | 44 +++-- .github/workflows/release-please.yml | 26 --- .github/workflows/release.yml | 234 ++++++++++++++++++++++++++ .gitignore | 26 +-- .release-please-manifest.json | 3 + CODE_OF_CONDUCT.md | 7 + package.json | 22 ++- release-please-config.json | 36 ++++ 16 files changed, 676 insertions(+), 144 deletions(-) create mode 100644 .github/matchers/tap.json create mode 100644 .github/workflows/ci-release.yml delete mode 100644 .github/workflows/release-please.yml create mode 100644 .github/workflows/release.yml create mode 100644 .release-please-manifest.json create mode 100644 CODE_OF_CONDUCT.md create mode 100644 release-please-config.json diff --git a/.eslintrc.js b/.eslintrc.js index 0e8ad007..5db9f815 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,5 +1,7 @@ /* This file is automatically added by @npmcli/template-oss. Do not edit. */ +'use strict' + const { readdirSync: readdir } = require('fs') const localConfigs = readdir(__dirname) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 96d8eafb..8da2a452 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,7 +4,7 @@ version: 2 updates: - package-ecosystem: npm - directory: "/" + directory: / schedule: interval: daily allow: diff --git a/.github/matchers/tap.json b/.github/matchers/tap.json new file mode 100644 index 00000000..2c81ea98 --- /dev/null +++ b/.github/matchers/tap.json @@ -0,0 +1,32 @@ +{ + "//@npmcli/template-oss": "This file is automatically added by @npmcli/template-oss. Do not edit.", + "problemMatcher": [ + { + "owner": "tap", + "pattern": [ + { + "regexp": "^\\s*not ok \\d+ - (.*)", + "message": 1 + }, + { + "regexp": "^\\s*---" + }, + { + "regexp": "^\\s*at:" + }, + { + "regexp": "^\\s*line:\\s*(\\d+)", + "line": 1 + }, + { + "regexp": "^\\s*column:\\s*(\\d+)", + "column": 1 + }, + { + "regexp": "^\\s*file:\\s*(.*)", + "file": 1 + } + ] + } + ] +} diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 1e35e279..4cd5b7c3 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -5,23 +5,33 @@ name: Audit on: workflow_dispatch: schedule: - # "At 01:00 on Monday" https://crontab.guru/#0_1_*_*_1 - - cron: "0 1 * * 1" + # "At 08:00 UTC (01:00 PT) on Monday" https://crontab.guru/#0_8_*_*_1 + - cron: "0 8 * * 1" jobs: audit: + name: Audit Dependencies + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | - git config --global user.email "ops+robot@npmjs.com" - git config --global user.name "npm team" - - uses: actions/setup-node@v3 + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 16.x - - name: Update npm to latest + - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund --package-lock - - run: npm audit + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund --package-lock + - name: Run Audit + run: npm audit diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml new file mode 100644 index 00000000..79ab608f --- /dev/null +++ b/.github/workflows/ci-release.yml @@ -0,0 +1,153 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: CI - Release + +on: + workflow_call: + inputs: + ref: + required: true + type: string + check-sha: + required: true + type: string + +jobs: + lint-all: + name: Lint All + if: github.repository_owner == 'npm' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Create Check + uses: LouisBrunner/checks-action@v1.3.1 + id: check + + with: + token: ${{ secrets.GITHUB_TOKEN }} + status: in_progress + name: Lint All + sha: ${{ inputs.check-sha }} + # XXX: this does not work when using the default GITHUB_TOKEN. + # Instead we post the main job url to the PR as a comment which + # will link to all the other checks. To work around this we would + # need to create a GitHub that would create on-demand tokens. + # https://github.com/LouisBrunner/checks-action/issues/18 + # details_url: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref }} + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 16.x + - name: Install npm@latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Lint + run: npm run lint --ignore-scripts + - name: Post Lint + run: npm run postlint --ignore-scripts + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ job.status }} + check_id: ${{ steps.check.outputs.check_id }} + + test-all: + name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd + node-version: + - 10.0.0 + - 10.x + - 12.x + - 14.x + - 16.x + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Create Check + uses: LouisBrunner/checks-action@v1.3.1 + id: check + + with: + token: ${{ secrets.GITHUB_TOKEN }} + status: in_progress + name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + sha: ${{ inputs.check-sha }} + # XXX: this does not work when using the default GITHUB_TOKEN. + # Instead we post the main job url to the PR as a comment which + # will link to all the other checks. To work around this we would + # need to create a GitHub that would create on-demand tokens. + # https://github.com/LouisBrunner/checks-action/issues/18 + # details_url: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref }} + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + - name: Update Windows npm + # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows + if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) + run: | + curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz + tar xf npm-7.5.4.tgz + cd package + node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz + cd .. + rmdir /s /q package + - name: Install npm@7 + if: startsWith(matrix.node-version, '10.') + run: npm i --prefer-online --no-fund --no-audit -g npm@7 + - name: Install npm@latest + if: ${{ !startsWith(matrix.node-version, '10.') }} + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" + - name: Test + run: npm test --ignore-scripts -ws -iwr --if-present + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ job.status }} + check_id: ${{ steps.check.outputs.check_id }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8014892..8bbea9a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,65 +5,82 @@ name: CI on: workflow_dispatch: pull_request: - branches: - - '*' push: branches: - main - latest schedule: - # "At 02:00 on Monday" https://crontab.guru/#0_2_*_*_1 - - cron: "0 2 * * 1" + # "At 09:00 UTC (02:00 PT) on Monday" https://crontab.guru/#0_9_*_*_1 + - cron: "0 9 * * 1" jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | - git config --global user.email "ops+robot@npmjs.com" - git config --global user.name "npm team" - - uses: actions/setup-node@v3 + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 16.x - - name: Update npm to latest + - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Lint + run: npm run lint --ignore-scripts + - name: Post Lint + run: npm run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 10.0.0 - 10.x - 12.x - 14.x - 16.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | - git config --global user.email "ops+robot@npmjs.com" - git config --global user.name "npm team" - - uses: actions/setup-node@v3 + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) + - name: Update Windows npm # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) run: | @@ -73,13 +90,17 @@ jobs: node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz cd .. rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 + - name: Install npm@7 if: startsWith(matrix.node-version, '10.') run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest + - name: Install npm@latest if: ${{ !startsWith(matrix.node-version, '10.') }} run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm test --ignore-scripts + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" + - name: Test + run: npm test --ignore-scripts -iwr diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2fbb6309..66b9498a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,6 +1,6 @@ # This file is automatically added by @npmcli/template-oss. Do not edit. -name: "CodeQL" +name: CodeQL on: push: @@ -8,13 +8,12 @@ on: - main - latest pull_request: - # The branches below must be a subset of the branches above branches: - main - latest schedule: - # "At 03:00 on Monday" https://crontab.guru/#0_3_*_*_1 - - cron: "0 3 * * 1" + # "At 10:00 UTC (03:00 PT) on Monday" https://crontab.guru/#0_10_*_*_1 + - cron: "0 10 * * 1" jobs: analyze: @@ -24,21 +23,16 @@ jobs: actions: read contents: read security-events: write - - strategy: - fail-fast: false - matrix: - language: [ javascript ] - steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | - git config --global user.email "ops+robot@npmjs.com" - git config --global user.name "npm team" + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: - languages: ${{ matrix.language }} + languages: javascript - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index 94f5a8fd..ebe73426 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -1,43 +1,91 @@ # This file is automatically added by @npmcli/template-oss. Do not edit. -name: Post Dependabot Actions +name: Post Dependabot on: pull_request -# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions permissions: contents: write jobs: - template-oss-apply: + template-oss: + name: template-oss + if: github.repository_owner == 'npm' && github.actor == 'dependabot[bot]' runs-on: ubuntu-latest - if: github.actor == 'dependabot[bot]' + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head_ref }} + - name: Setup Git User run: | - git config --global user.email "ops+robot@npmjs.com" - git config --global user.name "npm team" - - uses: actions/setup-node@v3 + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 16.x - - name: Update npm to latest + - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - name: Dependabot metadata + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Fetch Dependabot Metadata id: metadata - uses: dependabot/fetch-metadata@v1.1.1 + uses: dependabot/fetch-metadata@v1 with: - github-token: "${{ secrets.GITHUB_TOKEN }}" - - name: npm install and commit + github-token: ${{ secrets.GITHUB_TOKEN }} + + # Dependabot can update multiple directories so we output which directory + # it is acting on so we can run the command for the correct root or workspace + - name: Get Dependabot Directory if: contains(steps.metadata.outputs.dependency-names, '@npmcli/template-oss') + id: flags + run: | + if [[ "${{ steps.metadata.outputs.directory }}" == "/" ]]; then + echo "::set-output name=workspace::-iwr" + else + echo "::set-output name=workspace::-w ${{ steps.metadata.outputs.directory }}" + fi + + - name: Apply Changes + if: steps.flags.outputs.workspace + id: apply + run: | + npm run template-oss-apply ${{ steps.flags.outputs.workspace }} + if [[ `git status --porcelain` ]]; then + echo "::set-output name=changes::true" + fi + + # This step will fail if template-oss has made any workflow updates. It is impossible + # for a workflow to update other workflows. In the case it does fail, we continue + # and then try to apply only a portion of the changes in the next step + - name: Push All Changes + if: steps.apply.outputs.changes + id: push + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git commit -am "chore: postinstall for dependabot template-oss PR" + git push + + - name: Push All Changes Except Workflows + if: steps.push.outcome == 'failure' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - gh pr checkout ${{ github.event.pull_request.number }} - npm install --ignore-scripts --no-audit --no-fund - npm run template-oss-apply - git add . + git reset HEAD~ + git checkout HEAD -- .github/workflows/ + git clean -fd .github/workflows/ git commit -am "chore: postinstall for dependabot template-oss PR" git push - npm run lint + + - name: Check Changes + if: steps.apply.outputs.changes + run: | + npm exec --offline ${{ steps.flags.outputs.workspace }} -- template-oss-check diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index d2bc7dab..2ad40088 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -1,6 +1,6 @@ # This file is automatically added by @npmcli/template-oss. Do not edit. -name: Pull Request Linting +name: Pull Request on: pull_request: @@ -11,28 +11,38 @@ on: - synchronize jobs: - check: - name: Check PR Title or Commits + commitlint: + name: Lint Commits + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 with: fetch-depth: 0 - - name: Setup git user + - name: Setup Git User run: | - git config --global user.email "ops+robot@npmjs.com" - git config --global user.name "npm team" - - uses: actions/setup-node@v3 + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 16.x - - name: Update npm to latest + - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - name: Install deps - run: npm i -D @commitlint/cli @commitlint/config-conventional - - name: Check commits OR PR title - env: - PR_TITLE: ${{ github.event.pull_request.title }} + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Run Commitlint on Commits + id: commit + continue-on-error: true run: | - npx --offline commitlint -V --from origin/main --to ${{ github.event.pull_request.head.sha }} \ - || echo $PR_TITLE | npx --offline commitlint -V + npx --offline commitlint -V --from origin/${{ github.base_ref }} --to ${{ github.event.pull_request.head.sha }} + - name: Run Commitlint on PR Title + if: steps.commit.outcome == 'failure' + run: | + echo ${{ github.event.pull_request.title }} | npx --offline commitlint -V diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml deleted file mode 100644 index ab3a9105..00000000 --- a/.github/workflows/release-please.yml +++ /dev/null @@ -1,26 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -name: Release Please - -on: - push: - branches: - - main - - latest - -jobs: - release-please: - runs-on: ubuntu-latest - steps: - - uses: google-github-actions/release-please-action@v3 - id: release - with: - release-type: node - changelog-types: > - [ - {"type":"feat","section":"Features","hidden":false}, - {"type":"fix","section":"Bug Fixes","hidden":false}, - {"type":"docs","section":"Documentation","hidden":false}, - {"type":"deps","section":"Dependencies","hidden":false}, - {"type":"chore","hidden":true} - ] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..544e3aae --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,234 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Release + +on: + push: + branches: + - main + - latest + +permissions: + contents: write + pull-requests: write + checks: write + +jobs: + release: + outputs: + pr: ${{ steps.release.outputs.pr }} + releases: ${{ steps.release.outputs.releases }} + release-flags: ${{ steps.release.outputs.release-flags }} + branch: ${{ steps.release.outputs.pr-branch }} + pr-number: ${{ steps.release.outputs.pr-number }} + comment-id: ${{ steps.pr-comment.outputs.result }} + check-id: ${{ steps.check.outputs.check_id }} + name: Release + if: github.repository_owner == 'npm' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 16.x + - name: Install npm@latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Release Please + id: release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + npx --offline template-oss-release-please ${{ github.ref_name }} + - name: Post Pull Request Comment + if: steps.release.outputs.pr-number + uses: actions/github-script@v6 + id: pr-comment + env: + PR_NUMBER: ${{ steps.release.outputs.pr-number }} + with: + script: | + const repo = { owner: context.repo.owner, repo: context.repo.repo } + const issue = { ...repo, issue_number: process.env.PR_NUMBER } + + const { data: workflow } = await github.rest.actions.getWorkflowRun({ ...repo, run_id: context.runId }) + + let body = '## Release Manager\n\n' + + const comments = await github.paginate(github.rest.issues.listComments, issue) + let commentId = comments?.find(c => c.user.login === 'github-actions[bot]' && c.body.startsWith(body))?.id + + body += `- Release workflow run: ${workflow.html_url}` + if (commentId) { + await github.rest.issues.updateComment({ ...repo, comment_id: commentId, body }) + } else { + const { data: comment } = await github.rest.issues.createComment({ ...issue, body }) + commentId = comment?.id + } + + return commentId + - name: Create Check + uses: LouisBrunner/checks-action@v1.3.1 + id: check + if: steps.release.outputs.pr-number + with: + token: ${{ secrets.GITHUB_TOKEN }} + status: in_progress + name: Release + sha: ${{ steps.release.outputs.pr-sha }} + # XXX: this does not work when using the default GITHUB_TOKEN. + # Instead we post the main job url to the PR as a comment which + # will link to all the other checks. To work around this we would + # need to create a GitHub that would create on-demand tokens. + # https://github.com/LouisBrunner/checks-action/issues/18 + # details_url: + + update: + needs: release + outputs: + sha: ${{ steps.commit.outputs.sha }} + check-id: ${{ steps.check.outputs.check_id }} + name: Update - Release + if: github.repository_owner == 'npm' && needs.release.outputs.pr + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: ${{ needs.release.outputs.branch }} + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 16.x + - name: Install npm@latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Run Post Pull Request Actions + env: + RELEASE_PR_NUMBER: ${{ needs.release.outputs.pr-number }} + RELEASE_COMMENT_ID: ${{ needs.release.outputs.comment-id }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + npm run rp-pull-request --ignore-scripts -ws -iwr --if-present + - name: Commit + id: commit + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git commit --all --amend --no-edit || true + git push --force-with-lease + echo "::set-output name=sha::$(git rev-parse HEAD)" + - name: Create Check + uses: LouisBrunner/checks-action@v1.3.1 + id: check + + with: + token: ${{ secrets.GITHUB_TOKEN }} + status: in_progress + name: Release + sha: ${{ steps.commit.outputs.sha }} + # XXX: this does not work when using the default GITHUB_TOKEN. + # Instead we post the main job url to the PR as a comment which + # will link to all the other checks. To work around this we would + # need to create a GitHub that would create on-demand tokens. + # https://github.com/LouisBrunner/checks-action/issues/18 + # details_url: + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ job.status }} + check_id: ${{ needs.release.outputs.check-id }} + + ci: + name: CI - Release + needs: [ release, update ] + if: needs.release.outputs.pr + uses: ./.github/workflows/ci-release.yml + with: + ref: ${{ needs.release.outputs.branch }} + check-sha: ${{ needs.update.outputs.sha }} + + post-ci: + needs: [ release, update, ci ] + name: Post CI - Release + if: github.repository_owner == 'npm' && needs.release.outputs.pr && always() + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Get Needs Result + id: needs-result + run: | + result="" + if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then + result="failure" + elif [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then + result="cancelled" + else + result="success" + fi + echo "::set-output name=result::$result" + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ steps.needs-result.outputs.result }} + check_id: ${{ needs.update.outputs.check-id }} + + post-release: + needs: release + name: Post Release - Release + if: github.repository_owner == 'npm' && needs.release.outputs.releases + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 16.x + - name: Install npm@latest + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund + - name: Run Post Release Actions + env: + RELEASES: ${{ needs.release.outputs.releases }} + run: | + npm run rp-release --ignore-scripts --if-present ${{ join(fromJSON(needs.release.outputs.release-flags), ' ') }} diff --git a/.gitignore b/.gitignore index 6066eaa0..dfcc3c51 100644 --- a/.gitignore +++ b/.gitignore @@ -4,22 +4,26 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.commitlintrc.js !/.eslintrc.js +!/.eslintrc.local.* !/.github/ !/.gitignore !/.npmrc -!/SECURITY.md -!/index.js +!/.release-please-manifest.json +!/bin/ +!/CHANGELOG* +!/CODE_OF_CONDUCT.md +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/release-please-config.json +!/scripts/ +!/SECURITY.md +!/tap-snapshots/ +!/test/ +!index.js diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..11b173ab --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "6.1.11" +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..167043c2 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,7 @@ +<!-- This file is automatically added by @npmcli/template-oss. Do not edit. --> + +All interactions in this repo are covered by the [npm Code of +Conduct](https://docs.npmjs.com/policies/conduct) + +The npm cli team may, at its own discretion, moderate, remove, or edit +any interactions such as pull requests, issues, and comments. diff --git a/package.json b/package.json index d86f6d64..dafd41ff 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,6 @@ "lint": "eslint \"**/*.js\"", "postlint": "template-oss-check", "lintfix": "npm run lint -- --fix", - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", "snap": "tap", "test": "tap", "posttest": "npm run lint" @@ -45,20 +42,27 @@ "node": ">=10" }, "files": [ - "index.js", - "lib/" + "bin/", + "lib/", + "index.js" ], "tap": { "coverage-map": "map.js", - "timeout": 0 + "timeout": 0, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.4.2", + "version": "4.3.2", "engines": ">=10", "distPaths": [ - "index.js", - "lib/" + "index.js" + ], + "allowPaths": [ + "index.js" ], "ciVersions": [ "10.0.0", diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 00000000..73d1e353 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,36 @@ +{ + "exclude-packages-from-root": true, + "group-pull-request-title-pattern": "chore: release ${version}", + "pull-request-title-pattern": "chore: release${component} ${version}", + "changelog-sections": [ + { + "type": "feat", + "section": "Features", + "hidden": false + }, + { + "type": "fix", + "section": "Bug Fixes", + "hidden": false + }, + { + "type": "docs", + "section": "Documentation", + "hidden": false + }, + { + "type": "deps", + "section": "Dependencies", + "hidden": false + }, + { + "type": "chore", + "hidden": true + } + ], + "packages": { + ".": { + "package-name": "" + } + } +} From d768311d5dc2cc237eff69c3c2c13aad653c0588 Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Tue, 20 Sep 2022 14:15:08 -0700 Subject: [PATCH 06/96] chore: ignore some lint rules for tests --- .eslintrc.local.js | 8 ++++++++ package.json | 2 +- scripts/template-oss/_step-git.yml | 14 ++++++++++++++ scripts/template-oss/index.js | 0 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 scripts/template-oss/_step-git.yml create mode 100644 scripts/template-oss/index.js diff --git a/.eslintrc.local.js b/.eslintrc.local.js index da0d239c..b820d970 100644 --- a/.eslintrc.local.js +++ b/.eslintrc.local.js @@ -4,5 +4,13 @@ module.exports = { 'no-shadow': 0, 'no-unused-expressions': 0, 'no-sequences': 0, + 'no-empty': 0, }, + overrides: [{ + files: ['test/**'], + rules: { + 'promise/catch-or-return': 0, + 'promise/always-return': 0, + }, + }], } diff --git a/package.json b/package.json index dafd41ff..110756e2 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "yallist": "^4.0.0" }, "devDependencies": { - "@npmcli/eslint-config": "^3.0.1", + "@npmcli/eslint-config": "^3.1.0", "@npmcli/template-oss": "4.3.2", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", diff --git a/scripts/template-oss/_step-git.yml b/scripts/template-oss/_step-git.yml new file mode 100644 index 00000000..19c7f6b1 --- /dev/null +++ b/scripts/template-oss/_step-git.yml @@ -0,0 +1,14 @@ +- name: Support Long Pathsg + run: git config --system core.longpaths true +- name: Checkout + uses: actions/checkout@v3 + {{#if jobCheckout}} + with: + {{#each jobCheckout}} + {{ @key }}: {{ this }} + {{/each}} + {{/if}} +- name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" \ No newline at end of file diff --git a/scripts/template-oss/index.js b/scripts/template-oss/index.js new file mode 100644 index 00000000..e69de29b From 81982f10ae4449a511e72f067899148fb986efcf Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Tue, 20 Sep 2022 14:16:15 -0700 Subject: [PATCH 07/96] chore: support git longpaths in ci --- .github/workflows/audit.yml | 2 ++ .github/workflows/ci-release.yml | 4 ++++ .github/workflows/ci.yml | 4 ++++ .github/workflows/codeql-analysis.yml | 2 ++ .github/workflows/post-dependabot.yml | 2 ++ .github/workflows/pull-request.yml | 2 ++ .github/workflows/release.yml | 6 ++++++ package.json | 1 + scripts/template-oss/_step-git.yml | 2 +- scripts/template-oss/index.js | 0 10 files changed, 24 insertions(+), 1 deletion(-) delete mode 100644 scripts/template-oss/index.js diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 4cd5b7c3..f555afd4 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -17,6 +17,8 @@ jobs: run: shell: bash steps: + - name: Support Long Pathsg + run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 - name: Setup Git User diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 79ab608f..a5df5141 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -36,6 +36,8 @@ jobs: # need to create a GitHub that would create on-demand tokens. # https://github.com/LouisBrunner/checks-action/issues/18 # details_url: + - name: Support Long Pathsg + run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 with: @@ -108,6 +110,8 @@ jobs: # need to create a GitHub that would create on-demand tokens. # https://github.com/LouisBrunner/checks-action/issues/18 # details_url: + - name: Support Long Pathsg + run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8bbea9a0..5b5d6a57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,8 @@ jobs: run: shell: bash steps: + - name: Support Long Pathsg + run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 - name: Setup Git User @@ -70,6 +72,8 @@ jobs: run: shell: ${{ matrix.platform.shell }} steps: + - name: Support Long Pathsg + run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 - name: Setup Git User diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 66b9498a..cf22d882 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,6 +24,8 @@ jobs: contents: read security-events: write steps: + - name: Support Long Pathsg + run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 - name: Setup Git User diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index ebe73426..efd51c42 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -16,6 +16,8 @@ jobs: run: shell: bash steps: + - name: Support Long Pathsg + run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 with: diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 2ad40088..e56d80ab 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -19,6 +19,8 @@ jobs: run: shell: bash steps: + - name: Support Long Pathsg + run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 544e3aae..06379b10 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,6 +30,8 @@ jobs: run: shell: bash steps: + - name: Support Long Pathsg + run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 - name: Setup Git User @@ -107,6 +109,8 @@ jobs: run: shell: bash steps: + - name: Support Long Pathsg + run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 with: @@ -211,6 +215,8 @@ jobs: run: shell: bash steps: + - name: Support Long Pathsg + run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 - name: Setup Git User diff --git a/package.json b/package.json index 110756e2..62e6fb5e 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.3.2", + "content": "scripts/template-oss", "engines": ">=10", "distPaths": [ "index.js" diff --git a/scripts/template-oss/_step-git.yml b/scripts/template-oss/_step-git.yml index 19c7f6b1..08bf4fa8 100644 --- a/scripts/template-oss/_step-git.yml +++ b/scripts/template-oss/_step-git.yml @@ -11,4 +11,4 @@ - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" \ No newline at end of file + git config --global user.name "npm CLI robot" diff --git a/scripts/template-oss/index.js b/scripts/template-oss/index.js deleted file mode 100644 index e69de29b..00000000 From 8d1819967dc9bd8fe6f1b512743dde962ec0f607 Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Tue, 20 Sep 2022 14:34:47 -0700 Subject: [PATCH 08/96] chore: set taprc for windows --- .github/workflows/audit.yml | 3 ++- .github/workflows/ci-release.yml | 8 ++++++-- .github/workflows/ci.yml | 8 ++++++-- .github/workflows/codeql-analysis.yml | 3 ++- .github/workflows/post-dependabot.yml | 3 ++- .github/workflows/pull-request.yml | 3 ++- .github/workflows/release.yml | 9 ++++++--- scripts/template-oss/_step-git.yml | 3 ++- scripts/template-oss/_step-test.yml | 6 ++++++ test/fixtures/.taprc.win32 | 4 ++++ test/fixtures/taprc.js | 11 +++++++++++ 11 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 scripts/template-oss/_step-test.yml create mode 100644 test/fixtures/.taprc.win32 create mode 100644 test/fixtures/taprc.js diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index f555afd4..7ecff0a0 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -17,7 +17,8 @@ jobs: run: shell: bash steps: - - name: Support Long Pathsg + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index a5df5141..60c20519 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -36,7 +36,8 @@ jobs: # need to create a GitHub that would create on-demand tokens. # https://github.com/LouisBrunner/checks-action/issues/18 # details_url: - - name: Support Long Pathsg + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 @@ -110,7 +111,8 @@ jobs: # need to create a GitHub that would create on-demand tokens. # https://github.com/LouisBrunner/checks-action/issues/18 # details_url: - - name: Support Long Pathsg + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 @@ -146,6 +148,8 @@ jobs: run: npm i --ignore-scripts --no-audit --no-fund - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Set Tap RC + run: node ./test/fixtures/taprc.js - name: Test run: npm test --ignore-scripts -ws -iwr --if-present - name: Conclude Check diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b5d6a57..42dbfdc5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,8 @@ jobs: run: shell: bash steps: - - name: Support Long Pathsg + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 @@ -72,7 +73,8 @@ jobs: run: shell: ${{ matrix.platform.shell }} steps: - - name: Support Long Pathsg + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 @@ -106,5 +108,7 @@ jobs: run: npm i --ignore-scripts --no-audit --no-fund - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Set Tap RC + run: node ./test/fixtures/taprc.js - name: Test run: npm test --ignore-scripts -iwr diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index cf22d882..cf9dc41c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,8 @@ jobs: contents: read security-events: write steps: - - name: Support Long Pathsg + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index efd51c42..8aeda5af 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -16,7 +16,8 @@ jobs: run: shell: bash steps: - - name: Support Long Pathsg + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index e56d80ab..f47cbafc 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -19,7 +19,8 @@ jobs: run: shell: bash steps: - - name: Support Long Pathsg + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 06379b10..a710c6e4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,8 @@ jobs: run: shell: bash steps: - - name: Support Long Pathsg + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 @@ -109,7 +110,8 @@ jobs: run: shell: bash steps: - - name: Support Long Pathsg + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 @@ -215,7 +217,8 @@ jobs: run: shell: bash steps: - - name: Support Long Pathsg + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 diff --git a/scripts/template-oss/_step-git.yml b/scripts/template-oss/_step-git.yml index 08bf4fa8..1f42494d 100644 --- a/scripts/template-oss/_step-git.yml +++ b/scripts/template-oss/_step-git.yml @@ -1,4 +1,5 @@ -- name: Support Long Pathsg +- name: Support Long Paths + if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true - name: Checkout uses: actions/checkout@v3 diff --git a/scripts/template-oss/_step-test.yml b/scripts/template-oss/_step-test.yml new file mode 100644 index 00000000..2f7197db --- /dev/null +++ b/scripts/template-oss/_step-test.yml @@ -0,0 +1,6 @@ +- name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" +- name: Set Tap RC + run: node ./test/fixtures/taprc.js +- name: Test + run: {{ rootNpmPath }} test --ignore-scripts {{~#if jobRunFlags}} {{ jobRunFlags }}{{/if}} diff --git a/test/fixtures/.taprc.win32 b/test/fixtures/.taprc.win32 new file mode 100644 index 00000000..208f12af --- /dev/null +++ b/test/fixtures/.taprc.win32 @@ -0,0 +1,4 @@ +lines: 98 +branches: 98 +statements: 98 +functions: 98 diff --git a/test/fixtures/taprc.js b/test/fixtures/taprc.js new file mode 100644 index 00000000..d0b78b14 --- /dev/null +++ b/test/fixtures/taprc.js @@ -0,0 +1,11 @@ +const fs = require('fs') +const path = require('path') + +if (process.platform === 'win32') { + fs.writeFileSync(path.resolve(__dirname, '..', '..', '.taprc'), [ + 'lines: 98', + 'branches: 98', + 'statements: 98', + 'functions: 98', + ].join('\n')) +} From 0b1b8f13180673653dae80545932da298362a158 Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Tue, 20 Sep 2022 14:37:47 -0700 Subject: [PATCH 09/96] chore(ci): test in node 18 --- .github/workflows/audit.yml | 2 +- .github/workflows/ci-release.yml | 3 ++- .github/workflows/ci.yml | 3 ++- .github/workflows/post-dependabot.yml | 2 +- .github/workflows/pull-request.yml | 2 +- .github/workflows/release.yml | 6 +++--- .gitignore | 2 +- package.json | 5 +++-- 8 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 7ecff0a0..9fd285d8 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -29,7 +29,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - name: npm Version diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 60c20519..2e7785e5 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -50,7 +50,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - name: npm Version @@ -91,6 +91,7 @@ jobs: - 12.x - 14.x - 16.x + - 18.x runs-on: ${{ matrix.platform.os }} defaults: run: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 42dbfdc5..23285d8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - name: npm Version @@ -68,6 +68,7 @@ jobs: - 12.x - 14.x - 16.x + - 18.x runs-on: ${{ matrix.platform.os }} defaults: run: diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index 8aeda5af..c865a929 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -30,7 +30,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - name: npm Version diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index f47cbafc..a194b619 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -33,7 +33,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - name: npm Version diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a710c6e4..6e282516 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,7 +42,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - name: npm Version @@ -125,7 +125,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - name: npm Version @@ -229,7 +229,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x - name: Install npm@latest run: npm i --prefer-online --no-fund --no-audit -g npm@latest - name: npm Version diff --git a/.gitignore b/.gitignore index dfcc3c51..effd9b9a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ !/CHANGELOG* !/CODE_OF_CONDUCT.md !/docs/ +!/index.js !/lib/ !/LICENSE* !/map.js @@ -26,4 +27,3 @@ !/SECURITY.md !/tap-snapshots/ !/test/ -!index.js diff --git a/package.json b/package.json index 62e6fb5e..bd1cc0e7 100644 --- a/package.json +++ b/package.json @@ -63,14 +63,15 @@ "index.js" ], "allowPaths": [ - "index.js" + "/index.js" ], "ciVersions": [ "10.0.0", "10.x", "12.x", "14.x", - "16.x" + "16.x", + "18.x" ] } } From 26a496e5fa74eeaa0c3539511560fc181ef56557 Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Tue, 20 Sep 2022 15:02:05 -0700 Subject: [PATCH 10/96] chore: only test in 10.x for node 10 --- .github/workflows/ci-release.yml | 1 - .github/workflows/ci.yml | 1 - package.json | 1 - 3 files changed, 3 deletions(-) diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 2e7785e5..9d72b533 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -86,7 +86,6 @@ jobs: os: windows-latest shell: cmd node-version: - - 10.0.0 - 10.x - 12.x - 14.x diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23285d8a..a9b2e067 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,7 +63,6 @@ jobs: os: windows-latest shell: cmd node-version: - - 10.0.0 - 10.x - 12.x - 14.x diff --git a/package.json b/package.json index bd1cc0e7..17a0e75c 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,6 @@ "/index.js" ], "ciVersions": [ - "10.0.0", "10.x", "12.x", "14.x", From a9e0d6f7d93670b76b2a31a6a9740809997d3ac5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Sep 2022 22:25:58 +0000 Subject: [PATCH 11/96] chore: bump tar-fs from 1.16.3 to 2.1.1 Bumps [tar-fs](https://github.com/mafintosh/tar-fs) from 1.16.3 to 2.1.1. - [Release notes](https://github.com/mafintosh/tar-fs/releases) - [Commits](https://github.com/mafintosh/tar-fs/compare/v1.16.3...v2.1.1) --- updated-dependencies: - dependency-name: tar-fs dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 17a0e75c..cb56f81a 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "mutate-fs": "^2.1.1", "rimraf": "^2.7.1", "tap": "^16.0.1", - "tar-fs": "^1.16.3", + "tar-fs": "^2.1.1", "tar-stream": "^1.6.2" }, "license": "ISC", From 1801244fdac045bbc470fd91e2c4fa849e38b94a Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Wed, 21 Sep 2022 12:50:10 -0700 Subject: [PATCH 12/96] chore: removed unused run-script flags in ci --- .github/workflows/ci-release.yml | 2 +- .github/workflows/ci.yml | 2 +- scripts/template-oss/_step-test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 9d72b533..711a3053 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -151,7 +151,7 @@ jobs: - name: Set Tap RC run: node ./test/fixtures/taprc.js - name: Test - run: npm test --ignore-scripts -ws -iwr --if-present + run: npm test --ignore-scripts - name: Conclude Check uses: LouisBrunner/checks-action@v1.3.1 if: always() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9b2e067..49caa572 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -111,4 +111,4 @@ jobs: - name: Set Tap RC run: node ./test/fixtures/taprc.js - name: Test - run: npm test --ignore-scripts -iwr + run: npm test --ignore-scripts diff --git a/scripts/template-oss/_step-test.yml b/scripts/template-oss/_step-test.yml index 2f7197db..ff34d24d 100644 --- a/scripts/template-oss/_step-test.yml +++ b/scripts/template-oss/_step-test.yml @@ -3,4 +3,4 @@ - name: Set Tap RC run: node ./test/fixtures/taprc.js - name: Test - run: {{ rootNpmPath }} test --ignore-scripts {{~#if jobRunFlags}} {{ jobRunFlags }}{{/if}} + run: {{ rootNpmPath }} test --ignore-scripts From acb6648c3d07f23ec83286aeecdc755d88fd4dde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Sep 2022 00:35:31 +0000 Subject: [PATCH 13/96] chore: bump tar-stream from 1.6.2 to 2.2.0 Bumps [tar-stream](https://github.com/mafintosh/tar-stream) from 1.6.2 to 2.2.0. - [Release notes](https://github.com/mafintosh/tar-stream/releases) - [Commits](https://github.com/mafintosh/tar-stream/compare/v1.6.2...v2.2.0) --- updated-dependencies: - dependency-name: tar-stream dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cb56f81a..e0d47ffe 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "rimraf": "^2.7.1", "tap": "^16.0.1", "tar-fs": "^2.1.1", - "tar-stream": "^1.6.2" + "tar-stream": "^2.2.0" }, "license": "ISC", "engines": { From cfddd427ae402a56c12088e8560e5d950217b7fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Sep 2022 00:35:42 +0000 Subject: [PATCH 14/96] chore: bump rimraf from 2.7.1 to 3.0.2 Bumps [rimraf](https://github.com/isaacs/rimraf) from 2.7.1 to 3.0.2. - [Release notes](https://github.com/isaacs/rimraf/releases) - [Changelog](https://github.com/isaacs/rimraf/blob/main/CHANGELOG.md) - [Commits](https://github.com/isaacs/rimraf/compare/v2.7.1...v3.0.2) --- updated-dependencies: - dependency-name: rimraf dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0d47ffe..fbcced35 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "end-of-stream": "^1.4.3", "events-to-array": "^1.1.2", "mutate-fs": "^2.1.1", - "rimraf": "^2.7.1", + "rimraf": "^3.0.2", "tap": "^16.0.1", "tar-fs": "^2.1.1", "tar-stream": "^2.2.0" From 118a6c8a3a9552426644c8e594f70c3a3d40a268 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Sep 2022 20:03:33 +0000 Subject: [PATCH 15/96] chore: bump @npmcli/template-oss from 4.3.2 to 4.4.4 Bumps [@npmcli/template-oss](https://github.com/npm/template-oss) from 4.3.2 to 4.4.4. - [Release notes](https://github.com/npm/template-oss/releases) - [Changelog](https://github.com/npm/template-oss/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/template-oss/compare/v4.3.2...v4.4.4) --- updated-dependencies: - dependency-name: @npmcli/template-oss dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fbcced35..005418a6 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.4", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", "events-to-array": "^1.1.2", From 9d71c5673683d6309c75e6a85e78fa285dbe9a2d Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Thu, 29 Sep 2022 20:36:27 -0700 Subject: [PATCH 16/96] chore: postinstall for dependabot template-oss PR --- .github/workflows/ci.yml | 50 +++++++++++++++++++++++++++ .github/workflows/post-dependabot.yml | 42 ++++++++++++++++++---- package.json | 2 +- 3 files changed, 87 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49caa572..c5413231 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,56 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Support Long Paths + if: matrix.platform.os == 'windows-latest' + run: git config --system core.longpaths true + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + - name: Update Windows npm + # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows + if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) + run: | + curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz + tar xf npm-7.5.4.tgz + cd package + node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz + cd .. + rmdir /s /q package + - name: Install npm@7 + if: startsWith(matrix.node-version, '10.') + run: npm i --prefer-online --no-fund --no-audit -g npm@7 + - name: Install npm@latest + if: ${{ !startsWith(matrix.node-version, '10.') }} + run: npm i --prefer-online --no-fund --no-audit -g npm@latest + - name: npm Version + run: npm -v + - name: Install Dependencies + run: npm i --ignore-scripts --no-audit --no-fund --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index c865a929..0742349e 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -22,7 +22,7 @@ jobs: - name: Checkout uses: actions/checkout@v3 with: - ref: ${{ github.event.pull_request.head_ref }} + ref: ${{ github.ref_name }} - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" @@ -49,10 +49,13 @@ jobs: if: contains(steps.metadata.outputs.dependency-names, '@npmcli/template-oss') id: flags run: | - if [[ "${{ steps.metadata.outputs.directory }}" == "/" ]]; then + dependabot_dir="${{ steps.metadata.outputs.directory }}" + if [[ "$dependabot_dir" == "/" ]]; then echo "::set-output name=workspace::-iwr" else - echo "::set-output name=workspace::-w ${{ steps.metadata.outputs.directory }}" + # strip leading slash from directory so it works as a + # a path to the workspace flag + echo "::set-output name=workspace::-w ${dependabot_dir#/}" fi - name: Apply Changes @@ -63,6 +66,15 @@ jobs: if [[ `git status --porcelain` ]]; then echo "::set-output name=changes::true" fi + # This only sets the conventional commit prefix. This workflow can't reliably determine + # what the breaking change is though. If a BREAKING CHANGE message is required then + # this PR check will fail and the commit will be amended with stafftools + if [[ "${{ steps.dependabot-metadata.outputs.update-type }}" == "version-update:semver-major" ]]; then + prefix='feat!' + else + prefix='chore!' + fi + echo "::set-output name=message::$prefix: postinstall for dependabot template-oss PR" # This step will fail if template-oss has made any workflow updates. It is impossible # for a workflow to update other workflows. In the case it does fail, we continue @@ -74,21 +86,39 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - git commit -am "chore: postinstall for dependabot template-oss PR" + git commit -am "${{ steps.apply.outputs.message }}" git push + # If the previous step failed, then reset the commit and remove any workflow changes + # and attempt to commit and push again. This is helpful because we will have a commit + # with the correct prefix that we can then --amend with @npmcli/stafftools later. - name: Push All Changes Except Workflows - if: steps.push.outcome == 'failure' + if: steps.apply.outputs.changes && steps.push-all.outcome == 'failure' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | git reset HEAD~ git checkout HEAD -- .github/workflows/ git clean -fd .github/workflows/ - git commit -am "chore: postinstall for dependabot template-oss PR" + git commit -am "${{ steps.apply.outputs.message }}" git push + # Check if all the necessary template-oss changes were applied. Since we continued + # on errors in one of the previous steps, this check will fail if our follow up + # only applied a portion of the changes and we need to followup manually. + # + # Note that this used to run `lint` and `postlint` but that will fail this action + # if we've also shipped any linting changes separate from template-oss. We do + # linting in another action, so we want to fail this one only if there are + # template-oss changes that could not be applied. - name: Check Changes if: steps.apply.outputs.changes run: | npm exec --offline ${{ steps.flags.outputs.workspace }} -- template-oss-check + + - name: Fail on Breaking Change + if: steps.apply.outputs.changes && startsWith(steps.apply.outputs.message, 'feat!') + run: | + echo "This PR has a breaking change. Run 'npx -p @npmcli/stafftools gh template-oss-fix'" + echo "for more information on how to fix this with a BREAKING CHANGE footer." + exit 1 diff --git a/package.json b/package.json index 005418a6..bae4b5e2 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.4", "content": "scripts/template-oss", "engines": ">=10", "distPaths": [ From 14e43f76ed3979405cf52b2051774b5bad17f2f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Oct 2022 20:02:01 +0000 Subject: [PATCH 17/96] chore: bump @npmcli/template-oss from 4.4.4 to 4.5.1 Bumps [@npmcli/template-oss](https://github.com/npm/template-oss) from 4.4.4 to 4.5.1. - [Release notes](https://github.com/npm/template-oss/releases) - [Changelog](https://github.com/npm/template-oss/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/template-oss/compare/v4.4.4...v4.5.1) --- updated-dependencies: - dependency-name: @npmcli/template-oss dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bae4b5e2..372e9cb9 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.4.4", + "@npmcli/template-oss": "4.5.1", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", "events-to-array": "^1.1.2", From fc207a8a744f783062e96169e1b2c360476e285d Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Mon, 10 Oct 2022 11:36:54 -0700 Subject: [PATCH 18/96] chore: postinstall for dependabot template-oss PR --- .github/workflows/ci-release.yml | 4 ++-- .github/workflows/ci.yml | 13 +++++++---- .github/workflows/post-dependabot.yml | 2 +- .github/workflows/release.yml | 3 ++- package.json | 2 +- scripts/template-oss/_step-node.yml | 31 +++++++++++++++++++++++++++ 6 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 scripts/template-oss/_step-node.yml diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 711a3053..5bcc50f2 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -137,10 +137,10 @@ jobs: cd .. rmdir /s /q package - name: Install npm@7 - if: startsWith(matrix.node-version, '10.') + if: startsWith(matrix.node-version, '10.') || startsWith(matrix.node-version, '12.') run: npm i --prefer-online --no-fund --no-audit -g npm@7 - name: Install npm@latest - if: ${{ !startsWith(matrix.node-version, '10.') }} + if: ${{ !startsWith(matrix.node-version, '10.') && !startsWith(matrix.node-version, '12.') }} run: npm i --prefer-online --no-fund --no-audit -g npm@latest - name: npm Version run: npm -v diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5413231..c9d81e47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,11 @@ jobs: os: ubuntu-latest shell: bash node-version: + - 10.0.0 + - 12.0.0 + - 14.0.0 + - 16.0.0 + - 18.0.0 runs-on: ${{ matrix.platform.os }} defaults: run: @@ -54,10 +59,10 @@ jobs: cd .. rmdir /s /q package - name: Install npm@7 - if: startsWith(matrix.node-version, '10.') + if: startsWith(matrix.node-version, '10.') || startsWith(matrix.node-version, '12.') run: npm i --prefer-online --no-fund --no-audit -g npm@7 - name: Install npm@latest - if: ${{ !startsWith(matrix.node-version, '10.') }} + if: ${{ !startsWith(matrix.node-version, '10.') && !startsWith(matrix.node-version, '12.') }} run: npm i --prefer-online --no-fund --no-audit -g npm@latest - name: npm Version run: npm -v @@ -147,10 +152,10 @@ jobs: cd .. rmdir /s /q package - name: Install npm@7 - if: startsWith(matrix.node-version, '10.') + if: startsWith(matrix.node-version, '10.') || startsWith(matrix.node-version, '12.') run: npm i --prefer-online --no-fund --no-audit -g npm@7 - name: Install npm@latest - if: ${{ !startsWith(matrix.node-version, '10.') }} + if: ${{ !startsWith(matrix.node-version, '10.') && !startsWith(matrix.node-version, '12.') }} run: npm i --prefer-online --no-fund --no-audit -g npm@latest - name: npm Version run: npm -v diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index 0742349e..d002c0ee 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -22,7 +22,7 @@ jobs: - name: Checkout uses: actions/checkout@v3 with: - ref: ${{ github.ref_name }} + ref: ${{ github.event.pull_request.head.ref }} - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6e282516..9b0839fb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -138,7 +138,8 @@ jobs: RELEASE_COMMENT_ID: ${{ needs.release.outputs.comment-id }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - npm run rp-pull-request --ignore-scripts -ws -iwr --if-present + npm exec --offline -- template-oss-release-manager + npm run rp-pull-request --ignore-scripts --if-present - name: Commit id: commit env: diff --git a/package.json b/package.json index 372e9cb9..dcd90dc6 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.4.4", + "version": "4.5.1", "content": "scripts/template-oss", "engines": ">=10", "distPaths": [ diff --git a/scripts/template-oss/_step-node.yml b/scripts/template-oss/_step-node.yml new file mode 100644 index 00000000..f15e8698 --- /dev/null +++ b/scripts/template-oss/_step-node.yml @@ -0,0 +1,31 @@ +- name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: {{#if jobIsMatrix}}$\{{ matrix.node-version }}{{else}}{{ last ciVersions }}{{/if}} + {{#if lockfile}} + cache: npm + {{/if}} +{{#if updateNpm}} +{{#if jobIsMatrix}} +- name: Update Windows npm + # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows + if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) + run: | + curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz + tar xf npm-7.5.4.tgz + cd package + node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz + cd .. + rmdir /s /q package +- name: Install npm@7 + if: startsWith(matrix.node-version, '10.') || startsWith(matrix.node-version, '12.') + run: npm i --prefer-online --no-fund --no-audit -g npm@7 +- name: Install npm@latest + if: $\{{ !startsWith(matrix.node-version, '10.') && !startsWith(matrix.node-version, '12.') }} +{{else}} +- name: Install npm@latest +{{/if}} + run: npm i --prefer-online --no-fund --no-audit -g npm@latest +- name: npm Version + run: npm -v +{{/if}} From 08cc1562bd1a80394f41eaf5c1c11d92176f8446 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Oct 2022 20:03:26 +0000 Subject: [PATCH 19/96] chore: bump @npmcli/eslint-config from 3.1.0 to 4.0.0 Bumps [@npmcli/eslint-config](https://github.com/npm/eslint-config) from 3.1.0 to 4.0.0. - [Release notes](https://github.com/npm/eslint-config/releases) - [Changelog](https://github.com/npm/eslint-config/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/eslint-config/compare/v3.1.0...v4.0.0) --- updated-dependencies: - dependency-name: "@npmcli/eslint-config" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dcd90dc6..8c95f439 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "yallist": "^4.0.0" }, "devDependencies": { - "@npmcli/eslint-config": "^3.1.0", + "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.5.1", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", From 39c60adaed54340c746c7ca68ff9e209ebe62110 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 20:02:40 +0000 Subject: [PATCH 20/96] chore: bump @npmcli/template-oss from 4.5.1 to 4.6.1 Bumps [@npmcli/template-oss](https://github.com/npm/template-oss) from 4.5.1 to 4.6.1. - [Release notes](https://github.com/npm/template-oss/releases) - [Changelog](https://github.com/npm/template-oss/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/template-oss/compare/v4.5.1...v4.6.1) --- updated-dependencies: - dependency-name: @npmcli/template-oss dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c95f439..86d55388 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.5.1", + "@npmcli/template-oss": "4.6.1", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", "events-to-array": "^1.1.2", From 2a49e7aaedc4138c6b94104bdaf8de56d86d7876 Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Mon, 17 Oct 2022 14:06:22 -0700 Subject: [PATCH 21/96] chore: postinstall for dependabot template-oss PR --- .github/workflows/ci-release.yml | 80 +++++++++++++++++++---- .github/workflows/post-dependabot.yml | 4 +- .github/workflows/release.yml | 93 ++++++++++++++++++++++----- package.json | 2 +- 4 files changed, 149 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 5bcc50f2..e47465e7 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -21,6 +21,39 @@ jobs: run: shell: bash steps: + - name: Get Workflow Job + uses: actions/github-script@v6 + + id: check-output + env: + JOB_NAME: "Lint All" + MATRIX_NAME: "" + with: + script: | + const { owner, repo } = context.repo + + const { data } = await github.rest.actions.listJobsForWorkflowRun({ + owner, + repo, + run_id: context.runId, + per_page: 100 + }) + + const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME + const job = data.jobs.find(j => j.name.endsWith(jobName)) + const jobUrl = job?.html_url + + const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ inputs.check-sha }}` + + let summary = `This check is assosciated with ${shaUrl}\n\n` + + if (jobUrl) { + summary += `For run logs, click here: ${jobUrl}` + } else { + summary += `Run logs could not be found for a job with name: "${jobName}"` + } + + return { summary } - name: Create Check uses: LouisBrunner/checks-action@v1.3.1 id: check @@ -30,12 +63,7 @@ jobs: status: in_progress name: Lint All sha: ${{ inputs.check-sha }} - # XXX: this does not work when using the default GITHUB_TOKEN. - # Instead we post the main job url to the PR as a comment which - # will link to all the other checks. To work around this we would - # need to create a GitHub that would create on-demand tokens. - # https://github.com/LouisBrunner/checks-action/issues/18 - # details_url: + output: ${{ steps.check-output.outputs.result }} - name: Support Long Paths if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true @@ -96,6 +124,39 @@ jobs: run: shell: ${{ matrix.platform.shell }} steps: + - name: Get Workflow Job + uses: actions/github-script@v6 + + id: check-output + env: + JOB_NAME: "Test All" + MATRIX_NAME: " - ${{ matrix.platform.name }} - ${{ matrix.node-version }}" + with: + script: | + const { owner, repo } = context.repo + + const { data } = await github.rest.actions.listJobsForWorkflowRun({ + owner, + repo, + run_id: context.runId, + per_page: 100 + }) + + const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME + const job = data.jobs.find(j => j.name.endsWith(jobName)) + const jobUrl = job?.html_url + + const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ inputs.check-sha }}` + + let summary = `This check is assosciated with ${shaUrl}\n\n` + + if (jobUrl) { + summary += `For run logs, click here: ${jobUrl}` + } else { + summary += `Run logs could not be found for a job with name: "${jobName}"` + } + + return { summary } - name: Create Check uses: LouisBrunner/checks-action@v1.3.1 id: check @@ -105,12 +166,7 @@ jobs: status: in_progress name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }} sha: ${{ inputs.check-sha }} - # XXX: this does not work when using the default GITHUB_TOKEN. - # Instead we post the main job url to the PR as a comment which - # will link to all the other checks. To work around this we would - # need to create a GitHub that would create on-demand tokens. - # https://github.com/LouisBrunner/checks-action/issues/18 - # details_url: + output: ${{ steps.check-output.outputs.result }} - name: Support Long Paths if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index d002c0ee..8f512727 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -69,7 +69,7 @@ jobs: # This only sets the conventional commit prefix. This workflow can't reliably determine # what the breaking change is though. If a BREAKING CHANGE message is required then # this PR check will fail and the commit will be amended with stafftools - if [[ "${{ steps.dependabot-metadata.outputs.update-type }}" == "version-update:semver-major" ]]; then + if [[ "${{ steps.metadata.outputs.update-type }}" == "version-update:semver-major" ]]; then prefix='feat!' else prefix='chore!' @@ -93,7 +93,7 @@ jobs: # and attempt to commit and push again. This is helpful because we will have a commit # with the correct prefix that we can then --amend with @npmcli/stafftools later. - name: Push All Changes Except Workflows - if: steps.apply.outputs.changes && steps.push-all.outcome == 'failure' + if: steps.apply.outputs.changes && steps.push.outcome == 'failure' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9b0839fb..63b65eb7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,6 +3,7 @@ name: Release on: + workflow_dispatch: push: branches: - main @@ -54,17 +55,19 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - npx --offline template-oss-release-please ${{ github.ref_name }} + npx --offline template-oss-release-please ${{ github.ref_name }} ${{ github.event_name }} - name: Post Pull Request Comment if: steps.release.outputs.pr-number uses: actions/github-script@v6 id: pr-comment env: PR_NUMBER: ${{ steps.release.outputs.pr-number }} + REF_NAME: ${{ github.ref_name }} with: script: | + const { REF_NAME, PR_NUMBER } = process.env const repo = { owner: context.repo.owner, repo: context.repo.repo } - const issue = { ...repo, issue_number: process.env.PR_NUMBER } + const issue = { ...repo, issue_number: PR_NUMBER } const { data: workflow } = await github.rest.actions.getWorkflowRun({ ...repo, run_id: context.runId }) @@ -73,7 +76,11 @@ jobs: const comments = await github.paginate(github.rest.issues.listComments, issue) let commentId = comments?.find(c => c.user.login === 'github-actions[bot]' && c.body.startsWith(body))?.id - body += `- Release workflow run: ${workflow.html_url}` + body += `Release workflow run: ${workflow.html_url}\n\n#### Force CI to Rerun for This Release\n\n` + body += `This PR will be updated and CI will run for every non-\`chore:\` commit that is pushed to \`main\`. ` + body += `To force CI to rerun, run this command:\n\n` + body += `\`\`\`\ngh workflow run release.yml -r ${REF_NAME}\n\`\`\`` + if (commentId) { await github.rest.issues.updateComment({ ...repo, comment_id: commentId, body }) } else { @@ -82,6 +89,39 @@ jobs: } return commentId + - name: Get Workflow Job + uses: actions/github-script@v6 + if: steps.release.outputs.pr-number + id: check-output + env: + JOB_NAME: "Release" + MATRIX_NAME: "" + with: + script: | + const { owner, repo } = context.repo + + const { data } = await github.rest.actions.listJobsForWorkflowRun({ + owner, + repo, + run_id: context.runId, + per_page: 100 + }) + + const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME + const job = data.jobs.find(j => j.name.endsWith(jobName)) + const jobUrl = job?.html_url + + const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ steps.release.outputs.pr-sha }}` + + let summary = `This check is assosciated with ${shaUrl}\n\n` + + if (jobUrl) { + summary += `For run logs, click here: ${jobUrl}` + } else { + summary += `Run logs could not be found for a job with name: "${jobName}"` + } + + return { summary } - name: Create Check uses: LouisBrunner/checks-action@v1.3.1 id: check @@ -91,12 +131,7 @@ jobs: status: in_progress name: Release sha: ${{ steps.release.outputs.pr-sha }} - # XXX: this does not work when using the default GITHUB_TOKEN. - # Instead we post the main job url to the PR as a comment which - # will link to all the other checks. To work around this we would - # need to create a GitHub that would create on-demand tokens. - # https://github.com/LouisBrunner/checks-action/issues/18 - # details_url: + output: ${{ steps.check-output.outputs.result }} update: needs: release @@ -148,6 +183,39 @@ jobs: git commit --all --amend --no-edit || true git push --force-with-lease echo "::set-output name=sha::$(git rev-parse HEAD)" + - name: Get Workflow Job + uses: actions/github-script@v6 + + id: check-output + env: + JOB_NAME: "Update - Release" + MATRIX_NAME: "" + with: + script: | + const { owner, repo } = context.repo + + const { data } = await github.rest.actions.listJobsForWorkflowRun({ + owner, + repo, + run_id: context.runId, + per_page: 100 + }) + + const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME + const job = data.jobs.find(j => j.name.endsWith(jobName)) + const jobUrl = job?.html_url + + const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ steps.commit.outputs.sha }}` + + let summary = `This check is assosciated with ${shaUrl}\n\n` + + if (jobUrl) { + summary += `For run logs, click here: ${jobUrl}` + } else { + summary += `Run logs could not be found for a job with name: "${jobName}"` + } + + return { summary } - name: Create Check uses: LouisBrunner/checks-action@v1.3.1 id: check @@ -157,12 +225,7 @@ jobs: status: in_progress name: Release sha: ${{ steps.commit.outputs.sha }} - # XXX: this does not work when using the default GITHUB_TOKEN. - # Instead we post the main job url to the PR as a comment which - # will link to all the other checks. To work around this we would - # need to create a GitHub that would create on-demand tokens. - # https://github.com/LouisBrunner/checks-action/issues/18 - # details_url: + output: ${{ steps.check-output.outputs.result }} - name: Conclude Check uses: LouisBrunner/checks-action@v1.3.1 if: always() diff --git a/package.json b/package.json index 86d55388..e3533f17 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.5.1", + "version": "4.6.1", "content": "scripts/template-oss", "engines": ">=10", "distPaths": [ From c78c108abd93c4cd88373f7f6733f7c04f7f8a7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Oct 2022 20:01:56 +0000 Subject: [PATCH 22/96] chore: bump @npmcli/template-oss from 4.6.1 to 4.6.2 Bumps [@npmcli/template-oss](https://github.com/npm/template-oss) from 4.6.1 to 4.6.2. - [Release notes](https://github.com/npm/template-oss/releases) - [Changelog](https://github.com/npm/template-oss/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/template-oss/compare/v4.6.1...v4.6.2) --- updated-dependencies: - dependency-name: @npmcli/template-oss dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e3533f17..c572efe9 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.6.1", + "@npmcli/template-oss": "4.6.2", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", "events-to-array": "^1.1.2", From d9edb344a1c799abfb5bc82e0f134865911160ab Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Tue, 18 Oct 2022 23:22:47 -0700 Subject: [PATCH 23/96] chore: postinstall for dependabot template-oss PR --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c572efe9..bc52e5df 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.6.1", + "version": "4.6.2", "content": "scripts/template-oss", "engines": ">=10", "distPaths": [ From b003c64f624332e24e19b30dc011069bb6708680 Mon Sep 17 00:00:00 2001 From: CommanderRoot <CommanderRoot@users.noreply.github.com> Date: Thu, 27 Oct 2022 03:28:33 +0200 Subject: [PATCH 24/96] fix: replace deprecated String.prototype.substr() (#314) .substr() is deprecated so we replace it with .slice() which works similarily but isn't deprecated Signed-off-by: Tobias Speicher <rootcommander@gmail.com> Co-authored-by: Luke Karrys <luke@lukekarrys.com> --- lib/create.js | 4 ++-- lib/header.js | 6 +++--- lib/pax.js | 2 +- lib/replace.js | 4 ++-- lib/strip-absolute-path.js | 2 +- lib/unpack.js | 4 ++-- lib/write-entry.js | 2 +- test/unpack.js | 2 +- test/write-entry.js | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/create.js b/lib/create.js index e5c4383f..9c860d4e 100644 --- a/lib/create.js +++ b/lib/create.js @@ -70,7 +70,7 @@ const addFilesSync = (p, files) => { files.forEach(file => { if (file.charAt(0) === '@') { t({ - file: path.resolve(p.cwd, file.substr(1)), + file: path.resolve(p.cwd, file.slice(1)), sync: true, noResume: true, onentry: entry => p.add(entry), @@ -87,7 +87,7 @@ const addFilesAsync = (p, files) => { const file = files.shift() if (file.charAt(0) === '@') { return t({ - file: path.resolve(p.cwd, file.substr(1)), + file: path.resolve(p.cwd, file.slice(1)), noResume: true, onentry: entry => p.add(entry), }).then(_ => addFilesAsync(p, files)) diff --git a/lib/header.js b/lib/header.js index 194550dd..411d5e45 100644 --- a/lib/header.js +++ b/lib/header.js @@ -68,7 +68,7 @@ class Header { if (this[TYPE] === '') { this[TYPE] = '0' } - if (this[TYPE] === '0' && this.path.substr(-1) === '/') { + if (this[TYPE] === '0' && this.path.slice(-1) === '/') { this[TYPE] = '5' } @@ -232,7 +232,7 @@ const splitPrefix = (p, prefixSize) => { } else if (Buffer.byteLength(pp) > pathSize && Buffer.byteLength(prefix) <= prefixSize) { // prefix fits in prefix, but path doesn't fit in path - ret = [pp.substr(0, pathSize - 1), prefix, true] + ret = [pp.slice(0, pathSize - 1), prefix, true] } else { // make path take a bit from prefix pp = pathModule.join(pathModule.basename(prefix), pp) @@ -242,7 +242,7 @@ const splitPrefix = (p, prefixSize) => { // at this point, found no resolution, just truncate if (!ret) { - ret = [p.substr(0, pathSize - 1), '', true] + ret = [p.slice(0, pathSize - 1), '', true] } } return ret diff --git a/lib/pax.js b/lib/pax.js index a505c1ab..4a7ca853 100644 --- a/lib/pax.js +++ b/lib/pax.js @@ -132,7 +132,7 @@ const parseKVLine = (set, line) => { return set } - line = line.substr((n + ' ').length) + line = line.slice((n + ' ').length) const kv = line.split('=') const k = kv.shift().replace(/^SCHILY\.(dev|ino|nlink)/, '$1') if (!k) { diff --git a/lib/replace.js b/lib/replace.js index 60d07375..c6e619be 100644 --- a/lib/replace.js +++ b/lib/replace.js @@ -217,7 +217,7 @@ const addFilesSync = (p, files) => { files.forEach(file => { if (file.charAt(0) === '@') { t({ - file: path.resolve(p.cwd, file.substr(1)), + file: path.resolve(p.cwd, file.slice(1)), sync: true, noResume: true, onentry: entry => p.add(entry), @@ -234,7 +234,7 @@ const addFilesAsync = (p, files) => { const file = files.shift() if (file.charAt(0) === '@') { return t({ - file: path.resolve(p.cwd, file.substr(1)), + file: path.resolve(p.cwd, file.slice(1)), noResume: true, onentry: entry => p.add(entry), }).then(_ => addFilesAsync(p, files)) diff --git a/lib/strip-absolute-path.js b/lib/strip-absolute-path.js index 1aa2d2ae..185e2dea 100644 --- a/lib/strip-absolute-path.js +++ b/lib/strip-absolute-path.js @@ -16,7 +16,7 @@ module.exports = path => { // but strip the //?/C:/ off of //?/C:/path const root = path.charAt(0) === '/' && path.slice(0, 4) !== '//?/' ? '/' : parsed.root - path = path.substr(root.length) + path = path.slice(root.length) r += root parsed = parse(path) } diff --git a/lib/unpack.js b/lib/unpack.js index 458f593d..6d9132c2 100644 --- a/lib/unpack.js +++ b/lib/unpack.js @@ -311,9 +311,9 @@ class Unpack extends Parser { // only encode : chars that aren't drive letter indicators if (this.win32) { const { root: aRoot } = path.win32.parse(entry.absolute) - entry.absolute = aRoot + wc.encode(entry.absolute.substr(aRoot.length)) + entry.absolute = aRoot + wc.encode(entry.absolute.slice(aRoot.length)) const { root: pRoot } = path.win32.parse(entry.path) - entry.path = pRoot + wc.encode(entry.path.substr(pRoot.length)) + entry.path = pRoot + wc.encode(entry.path.slice(pRoot.length)) } return true diff --git a/lib/write-entry.js b/lib/write-entry.js index cad969ff..3b5540f7 100644 --- a/lib/write-entry.js +++ b/lib/write-entry.js @@ -205,7 +205,7 @@ const WriteEntry = warner(class WriteEntry extends MiniPass { } [DIRECTORY] () { - if (this.path.substr(-1) !== '/') { + if (this.path.slice(-1) !== '/') { this.path += '/' } this.stat.size = 0 diff --git a/test/unpack.js b/test/unpack.js index 0b8d7231..b23aab3d 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -800,7 +800,7 @@ t.test('absolute paths', t => { t.ok(path.isAbsolute(extraAbsolute)) t.ok(path.isAbsolute(absolute)) const parsed = path.parse(absolute) - const relative = absolute.substr(parsed.root.length) + const relative = absolute.slice(parsed.root.length) t.notOk(path.isAbsolute(relative)) const data = makeTar([ diff --git a/test/write-entry.js b/test/write-entry.js index 4cad6969..b72e53a1 100644 --- a/test/write-entry.js +++ b/test/write-entry.js @@ -691,7 +691,7 @@ t.test('win32 <|>? in paths', { wc.on('data', c => out.push(c)) wc.on('end', _ => { const data = Buffer.concat(out).toString() - t.equal(data.substr(0, 4), '<|>?') + t.equal(data.slice(0, 4), '<|>?') t.end() }) From 24045dcefb1febc0d201566598ec9a378abe372d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Oct 2022 20:02:16 +0000 Subject: [PATCH 25/96] chore: bump @npmcli/template-oss from 4.6.2 to 4.7.1 Bumps [@npmcli/template-oss](https://github.com/npm/template-oss) from 4.6.2 to 4.7.1. - [Release notes](https://github.com/npm/template-oss/releases) - [Changelog](https://github.com/npm/template-oss/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/template-oss/compare/v4.6.2...v4.7.1) --- updated-dependencies: - dependency-name: @npmcli/template-oss dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bc52e5df..2c0ad61e 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.6.2", + "@npmcli/template-oss": "4.7.1", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", "events-to-array": "^1.1.2", From 1e3fadfedf9ea35da5dc7d70926a6864de6381cc Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Wed, 26 Oct 2022 18:23:12 -0700 Subject: [PATCH 26/96] chore: postinstall for dependabot template-oss PR --- .github/workflows/ci-release.yml | 18 ++++++++++++------ .github/workflows/post-dependabot.yml | 2 +- .github/workflows/release.yml | 13 +++++++------ package.json | 2 +- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index e47465e7..7a704fd3 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -3,6 +3,12 @@ name: CI - Release on: + workflow_dispatch: + inputs: + ref: + required: true + type: string + default: main workflow_call: inputs: ref: @@ -23,7 +29,7 @@ jobs: steps: - name: Get Workflow Job uses: actions/github-script@v6 - + if: inputs.check-sha id: check-output env: JOB_NAME: "Lint All" @@ -57,7 +63,7 @@ jobs: - name: Create Check uses: LouisBrunner/checks-action@v1.3.1 id: check - + if: inputs.check-sha with: token: ${{ secrets.GITHUB_TOKEN }} status: in_progress @@ -91,7 +97,7 @@ jobs: run: npm run postlint --ignore-scripts - name: Conclude Check uses: LouisBrunner/checks-action@v1.3.1 - if: always() + if: steps.check.outputs.check_id && always() with: token: ${{ secrets.GITHUB_TOKEN }} conclusion: ${{ job.status }} @@ -126,7 +132,7 @@ jobs: steps: - name: Get Workflow Job uses: actions/github-script@v6 - + if: inputs.check-sha id: check-output env: JOB_NAME: "Test All" @@ -160,7 +166,7 @@ jobs: - name: Create Check uses: LouisBrunner/checks-action@v1.3.1 id: check - + if: inputs.check-sha with: token: ${{ secrets.GITHUB_TOKEN }} status: in_progress @@ -210,7 +216,7 @@ jobs: run: npm test --ignore-scripts - name: Conclude Check uses: LouisBrunner/checks-action@v1.3.1 - if: always() + if: steps.check.outputs.check_id && always() with: token: ${{ secrets.GITHUB_TOKEN }} conclusion: ${{ job.status }} diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index 8f512727..3bc9f1f9 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -72,7 +72,7 @@ jobs: if [[ "${{ steps.metadata.outputs.update-type }}" == "version-update:semver-major" ]]; then prefix='feat!' else - prefix='chore!' + prefix='chore' fi echo "::set-output name=message::$prefix: postinstall for dependabot template-oss PR" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 63b65eb7..37bf6ab6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,6 +8,7 @@ on: branches: - main - latest + - release/v* permissions: contents: write @@ -91,7 +92,7 @@ jobs: return commentId - name: Get Workflow Job uses: actions/github-script@v6 - if: steps.release.outputs.pr-number + if: steps.release.outputs.pr-sha id: check-output env: JOB_NAME: "Release" @@ -125,7 +126,7 @@ jobs: - name: Create Check uses: LouisBrunner/checks-action@v1.3.1 id: check - if: steps.release.outputs.pr-number + if: steps.release.outputs.pr-sha with: token: ${{ secrets.GITHUB_TOKEN }} status: in_progress @@ -185,7 +186,7 @@ jobs: echo "::set-output name=sha::$(git rev-parse HEAD)" - name: Get Workflow Job uses: actions/github-script@v6 - + if: steps.commit.outputs.sha id: check-output env: JOB_NAME: "Update - Release" @@ -219,7 +220,7 @@ jobs: - name: Create Check uses: LouisBrunner/checks-action@v1.3.1 id: check - + if: steps.commit.outputs.sha with: token: ${{ secrets.GITHUB_TOKEN }} status: in_progress @@ -228,7 +229,7 @@ jobs: output: ${{ steps.check-output.outputs.result }} - name: Conclude Check uses: LouisBrunner/checks-action@v1.3.1 - if: always() + if: needs.release.outputs.check-id && always() with: token: ${{ secrets.GITHUB_TOKEN }} conclusion: ${{ job.status }} @@ -266,7 +267,7 @@ jobs: echo "::set-output name=result::$result" - name: Conclude Check uses: LouisBrunner/checks-action@v1.3.1 - if: always() + if: needs.update.outputs.check-id && always() with: token: ${{ secrets.GITHUB_TOKEN }} conclusion: ${{ steps.needs-result.outputs.result }} diff --git a/package.json b/package.json index 2c0ad61e..792e7c25 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.6.2", + "version": "4.7.1", "content": "scripts/template-oss", "engines": ">=10", "distPaths": [ From 57493ee66ece50d62114e02914282fc37be3a91a Mon Sep 17 00:00:00 2001 From: Mark David Avery <mark@webark.cc> Date: Wed, 5 Oct 2022 15:53:54 -0700 Subject: [PATCH 27/96] fix: ensuring close event is emited after stream has ended For node 18 combaitibility fixes #321 --- lib/parse.js | 10 +++++++++- lib/unpack.js | 1 - package.json | 4 +--- test/extract.js | 28 ++++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/lib/parse.js b/lib/parse.js index 16023f08..4b85915c 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -28,6 +28,7 @@ const maxMetaEntrySize = 1024 * 1024 const Entry = require('./read-entry.js') const Pax = require('./pax.js') const zlib = require('minizlib') +const { nextTick } = require('process') const gzipHeader = Buffer.from([0x1f, 0x8b]) const STATE = Symbol('state') @@ -59,6 +60,7 @@ const DONE = Symbol('onDone') const SAW_VALID_ENTRY = Symbol('sawValidEntry') const SAW_NULL_BLOCK = Symbol('sawNullBlock') const SAW_EOF = Symbol('sawEOF') +const CLOSESTREAM = Symbol('closeStream') const noop = _ => true @@ -89,7 +91,6 @@ module.exports = warner(class Parser extends EE { this.emit('prefinish') this.emit('finish') this.emit('end') - this.emit('close') }) } @@ -114,6 +115,9 @@ module.exports = warner(class Parser extends EE { this[ABORTED] = false this[SAW_NULL_BLOCK] = false this[SAW_EOF] = false + + this.on('end', () => this[CLOSESTREAM]()) + if (typeof opt.onwarn === 'function') { this.on('warn', opt.onwarn) } @@ -217,6 +221,10 @@ module.exports = warner(class Parser extends EE { } } + [CLOSESTREAM] () { + nextTick(() => this.emit('close')) + } + [PROCESSENTRY] (entry) { let go = true diff --git a/lib/unpack.js b/lib/unpack.js index 6d9132c2..e341ad0c 100644 --- a/lib/unpack.js +++ b/lib/unpack.js @@ -234,7 +234,6 @@ class Unpack extends Parser { this.emit('prefinish') this.emit('finish') this.emit('end') - this.emit('close') } } diff --git a/package.json b/package.json index 792e7c25..5ae1b923 100644 --- a/package.json +++ b/package.json @@ -33,9 +33,7 @@ "events-to-array": "^1.1.2", "mutate-fs": "^2.1.1", "rimraf": "^3.0.2", - "tap": "^16.0.1", - "tar-fs": "^2.1.1", - "tar-stream": "^2.2.0" + "tap": "^16.0.1" }, "license": "ISC", "engines": { diff --git a/test/extract.js b/test/extract.js index ae13739c..5bbffeec 100644 --- a/test/extract.js +++ b/test/extract.js @@ -10,6 +10,8 @@ const mkdirp = require('mkdirp') const { promisify } = require('util') const rimraf = promisify(require('rimraf')) const mutateFS = require('mutate-fs') +const pipeline = promisify(require('stream').pipeline) +const https = require('https') t.teardown(_ => rimraf(extractdir)) @@ -54,6 +56,32 @@ t.test('basic extracting', t => { t.end() }) +t.test('ensure an open stream is not prematuraly closed', t => { + const dir = path.resolve(extractdir, 'basic-with-stream') + + t.beforeEach(async () => { + await rimraf(dir) + await mkdirp(dir) + }) + + const check = async t => { + fs.lstatSync(dir + '/node-tar-main/LICENSE') + await rimraf(dir) + t.end() + } + + t.test('async promisey', t => { + https.get('https://codeload.github.com/npm/node-tar/tar.gz/main', (stream) => { + return pipeline( + stream, + x({ cwd: dir }, ['node-tar-main/LICENSE']) + ).then(_ => check(t)) + }) + }) + + t.end() +}) + t.test('file list and filter', t => { const file = path.resolve(tars, 'utf8.tar') const dir = path.resolve(extractdir, 'filter') From eaea26d7d8dbd5b2c8236b64df0f56ae5704cf2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Oct 2022 20:03:10 +0000 Subject: [PATCH 28/96] chore: bump @npmcli/template-oss from 4.7.1 to 4.8.0 Bumps [@npmcli/template-oss](https://github.com/npm/template-oss) from 4.7.1 to 4.8.0. - [Release notes](https://github.com/npm/template-oss/releases) - [Changelog](https://github.com/npm/template-oss/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/template-oss/compare/v4.7.1...v4.8.0) --- updated-dependencies: - dependency-name: @npmcli/template-oss dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5ae1b923..c75610eb 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.7.1", + "@npmcli/template-oss": "4.8.0", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", "events-to-array": "^1.1.2", From 79378ef9d044d0e992582f5a4768d90e4e2c1e3b Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Fri, 28 Oct 2022 16:56:43 -0700 Subject: [PATCH 29/96] chore: postinstall for dependabot template-oss PR --- .github/workflows/audit.yml | 6 ++-- .github/workflows/ci.yml | 55 ------------------------------------- package.json | 2 +- 3 files changed, 5 insertions(+), 58 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 9fd285d8..a4d035a7 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -36,5 +36,7 @@ jobs: run: npm -v - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund --package-lock - - name: Run Audit - run: npm audit + - name: Run Production Audit + run: npm audit --omit=dev + - name: Run Full Audit + run: npm audit --audit-level=none diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9d81e47..17ccceba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,61 +14,6 @@ on: - cron: "0 9 * * 1" jobs: - engines: - name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} - if: github.repository_owner == 'npm' - strategy: - fail-fast: false - matrix: - platform: - - name: Linux - os: ubuntu-latest - shell: bash - node-version: - - 10.0.0 - - 12.0.0 - - 14.0.0 - - 16.0.0 - - 18.0.0 - runs-on: ${{ matrix.platform.os }} - defaults: - run: - shell: ${{ matrix.platform.shell }} - steps: - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - name: Update Windows npm - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Install npm@7 - if: startsWith(matrix.node-version, '10.') || startsWith(matrix.node-version, '12.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Install npm@latest - if: ${{ !startsWith(matrix.node-version, '10.') && !startsWith(matrix.node-version, '12.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --ignore-scripts --no-audit --no-fund --engines-strict - lint: name: Lint if: github.repository_owner == 'npm' diff --git a/package.json b/package.json index c75610eb..526e3adc 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.7.1", + "version": "4.8.0", "content": "scripts/template-oss", "engines": ">=10", "distPaths": [ From 2e45b112bdb6e88d32fa09b3eab2482637493b6c Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Thu, 27 Oct 2022 09:06:53 -0700 Subject: [PATCH 30/96] chore: use a local instead of remote file for test I was able to replicate the same behavior from #332 by piping a readable stream with a `highWaterMark` of 1 to extract. I confirmed this test still failed without the fixes from #332 and now passes. --- package.json | 1 + test/extract.js | 57 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 526e3adc..033d914e 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "end-of-stream": "^1.4.3", "events-to-array": "^1.1.2", "mutate-fs": "^2.1.1", + "nock": "^13.2.9", "rimraf": "^3.0.2", "tap": "^16.0.1" }, diff --git a/test/extract.js b/test/extract.js index 5bbffeec..e6c21d81 100644 --- a/test/extract.js +++ b/test/extract.js @@ -1,6 +1,7 @@ 'use strict' const t = require('tap') +const nock = require('nock') const x = require('../lib/extract.js') const path = require('path') const fs = require('fs') @@ -11,7 +12,17 @@ const { promisify } = require('util') const rimraf = promisify(require('rimraf')) const mutateFS = require('mutate-fs') const pipeline = promisify(require('stream').pipeline) -const https = require('https') +const http = require('http') + +const tnock = (t, host, opts) => { + nock.disableNetConnect() + const server = nock(host, opts) + t.teardown(function () { + nock.enableNetConnect() + server.done() + }) + return server +} t.teardown(_ => rimraf(extractdir)) @@ -57,6 +68,9 @@ t.test('basic extracting', t => { }) t.test('ensure an open stream is not prematuraly closed', t => { + t.plan(1) + + const file = path.resolve(tars, 'long-paths.tar') const dir = path.resolve(extractdir, 'basic-with-stream') t.beforeEach(async () => { @@ -65,16 +79,51 @@ t.test('ensure an open stream is not prematuraly closed', t => { }) const check = async t => { - fs.lstatSync(dir + '/node-tar-main/LICENSE') + t.ok(fs.lstatSync(dir + '/long-path')) + await rimraf(dir) + t.end() + } + + t.test('async promisey', t => { + const stream = fs.createReadStream(file, { + highWaterMark: 1, + }) + pipeline( + stream, + x({ cwd: dir }) + ).then(_ => check(t)) + }) + + t.end() +}) + +t.test('ensure an open stream is not prematuraly closed http', t => { + t.plan(1) + + const file = path.resolve(tars, 'long-paths.tar') + const dir = path.resolve(extractdir, 'basic-with-stream-http') + + t.beforeEach(async () => { + await rimraf(dir) + await mkdirp(dir) + }) + + const check = async t => { + t.ok(fs.lstatSync(dir + '/long-path')) await rimraf(dir) t.end() } t.test('async promisey', t => { - https.get('https://codeload.github.com/npm/node-tar/tar.gz/main', (stream) => { + tnock(t, 'http://codeload.github.com/') + .get('/npm/node-tar/tar.gz/main') + .delay(250) + .reply(200, () => fs.createReadStream(file)) + + http.get('http://codeload.github.com/npm/node-tar/tar.gz/main', (stream) => { return pipeline( stream, - x({ cwd: dir }, ['node-tar-main/LICENSE']) + x({ cwd: dir }) ).then(_ => check(t)) }) }) From ac1026a69f9e0f5043a3f52c6f49c42b43b2066a Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Sat, 29 Oct 2022 11:38:40 -0700 Subject: [PATCH 31/96] chore: dry up template-oss config --- .github/workflows/ci-release.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- scripts/template-oss/_step-git.yml | 13 +------------ scripts/template-oss/_step-test.yml | 5 +---- 4 files changed, 6 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 7a704fd3..b062c0a0 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -208,10 +208,10 @@ jobs: run: npm -v - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Set Tap RC run: node ./test/fixtures/taprc.js + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: npm test --ignore-scripts - name: Conclude Check diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 17ccceba..dc3cf2e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,9 +106,9 @@ jobs: run: npm -v - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Set Tap RC run: node ./test/fixtures/taprc.js + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: npm test --ignore-scripts diff --git a/scripts/template-oss/_step-git.yml b/scripts/template-oss/_step-git.yml index 1f42494d..329bf5bb 100644 --- a/scripts/template-oss/_step-git.yml +++ b/scripts/template-oss/_step-git.yml @@ -1,15 +1,4 @@ - name: Support Long Paths if: matrix.platform.os == 'windows-latest' run: git config --system core.longpaths true -- name: Checkout - uses: actions/checkout@v3 - {{#if jobCheckout}} - with: - {{#each jobCheckout}} - {{ @key }}: {{ this }} - {{/each}} - {{/if}} -- name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" +{{> defaultStepGit }} diff --git a/scripts/template-oss/_step-test.yml b/scripts/template-oss/_step-test.yml index ff34d24d..84b6d549 100644 --- a/scripts/template-oss/_step-test.yml +++ b/scripts/template-oss/_step-test.yml @@ -1,6 +1,3 @@ -- name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Set Tap RC run: node ./test/fixtures/taprc.js -- name: Test - run: {{ rootNpmPath }} test --ignore-scripts +{{> defaultStepTest }} From 001eafbfe77b10aa41c06081d7d3c9a3a7913240 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 31 Oct 2022 23:37:17 +0000 Subject: [PATCH 32/96] chore: release 6.1.12 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 11b173ab..1997844d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "6.1.11" + ".": "6.1.12" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9373401b..7456e423 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [6.1.12](https://github.com/npm/node-tar/compare/v6.1.11...v6.1.12) (2022-10-31) + +### Bug Fixes + +* [`57493ee`](https://github.com/npm/node-tar/commit/57493ee66ece50d62114e02914282fc37be3a91a) [#332](https://github.com/npm/node-tar/pull/332) ensuring close event is emited after stream has ended (@webark) +* [`b003c64`](https://github.com/npm/node-tar/commit/b003c64f624332e24e19b30dc011069bb6708680) [#314](https://github.com/npm/node-tar/pull/314) replace deprecated String.prototype.substr() (#314) (@CommanderRoot, @lukekarrys) + +### Documentation + +* [`f129929`](https://github.com/npm/node-tar/commit/f12992932f171ea248b27fad95e7d489a56d31ed) [#313](https://github.com/npm/node-tar/pull/313) remove dead link to benchmarks (#313) (@yetzt) +* [`c1faa9f`](https://github.com/npm/node-tar/commit/c1faa9f44001dfb0bc7638b2850eb6058bd56a4a) add examples/explanation of using tar.t (@isaacs) + ## 6.0 - Drop support for node 6 and 8 diff --git a/package.json b/package.json index 033d914e..3a02105c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "6.1.11", + "version": "6.1.12", "repository": { "type": "git", "url": "https://github.com/npm/node-tar.git" From 72f6e3915a80ee0b4c6e759412b1c460f156f62c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Nov 2022 20:02:23 +0000 Subject: [PATCH 33/96] chore: bump @npmcli/template-oss from 4.8.0 to 4.10.0 Bumps [@npmcli/template-oss](https://github.com/npm/template-oss) from 4.8.0 to 4.10.0. - [Release notes](https://github.com/npm/template-oss/releases) - [Changelog](https://github.com/npm/template-oss/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/template-oss/compare/v4.8.0...v4.10.0) --- updated-dependencies: - dependency-name: @npmcli/template-oss dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3a02105c..473ad775 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.8.0", + "@npmcli/template-oss": "4.10.0", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", "events-to-array": "^1.1.2", From 329caed7d218f1784592f98380ff5a76968141ec Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Sat, 12 Nov 2022 14:29:49 -0700 Subject: [PATCH 34/96] chore: postinstall for dependabot template-oss PR --- .github/workflows/release.yml | 6 +++--- SECURITY.md | 13 ++++++++++++- package.json | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 37bf6ab6..e95ae8c6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,9 +77,9 @@ jobs: const comments = await github.paginate(github.rest.issues.listComments, issue) let commentId = comments?.find(c => c.user.login === 'github-actions[bot]' && c.body.startsWith(body))?.id - body += `Release workflow run: ${workflow.html_url}\n\n#### Force CI to Rerun for This Release\n\n` + body += `Release workflow run: ${workflow.html_url}\n\n#### Force CI to Update This Release\n\n` body += `This PR will be updated and CI will run for every non-\`chore:\` commit that is pushed to \`main\`. ` - body += `To force CI to rerun, run this command:\n\n` + body += `To force CI to update this PR, run this command:\n\n` body += `\`\`\`\ngh workflow run release.yml -r ${REF_NAME}\n\`\`\`` if (commentId) { @@ -174,7 +174,7 @@ jobs: RELEASE_COMMENT_ID: ${{ needs.release.outputs.comment-id }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - npm exec --offline -- template-oss-release-manager + npm exec --offline -- template-oss-release-manager --lockfile=false npm run rp-pull-request --ignore-scripts --if-present - name: Commit id: commit diff --git a/SECURITY.md b/SECURITY.md index a93106d0..4e7c26c6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,3 +1,14 @@ <!-- This file is automatically added by @npmcli/template-oss. Do not edit. --> -Please send vulnerability reports through [hackerone](https://hackerone.com/github). +GitHub takes the security of our software products and services seriously, including the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub). + +If you believe you have found a security vulnerability in this GitHub-owned open source repository, you can report it to us in one of two ways. + +If the vulnerability you have found is *not* [in scope for the GitHub Bug Bounty Program](https://bounty.github.com/#scope) or if you do not wish to be considered for a bounty reward, please report the issue to us directly using [private vulnerability reporting](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability). + +If the vulnerability you have found is [in scope for the GitHub Bug Bounty Program](https://bounty.github.com/#scope) and you would like for your finding to be considered for a bounty reward, please submit the vulnerability to us through [HackerOne](https://hackerone.com/github) in order to be eligible to receive a bounty award. + +**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** + +Thanks for helping make GitHub safe for everyone. + diff --git a/package.json b/package.json index 473ad775..4993a689 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.8.0", + "version": "4.10.0", "content": "scripts/template-oss", "engines": ">=10", "distPaths": [ From 5dcfcb37fd5f7189be7ce63ef85ae3fbbc47da89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Nov 2022 21:44:15 +0000 Subject: [PATCH 35/96] chore: bump events-to-array from 1.1.2 to 2.0.3 Bumps [events-to-array](https://github.com/isaacs/events-to-array) from 1.1.2 to 2.0.3. - [Release notes](https://github.com/isaacs/events-to-array/releases) - [Commits](https://github.com/isaacs/events-to-array/compare/v1.1.2...v2.0.3) --- updated-dependencies: - dependency-name: events-to-array dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4993a689..9b055e74 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@npmcli/template-oss": "4.10.0", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", - "events-to-array": "^1.1.2", + "events-to-array": "^2.0.3", "mutate-fs": "^2.1.1", "nock": "^13.2.9", "rimraf": "^3.0.2", From cc4e0ddfe523a0bce383846a67442c637a65d486 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Nov 2022 20:02:25 +0000 Subject: [PATCH 36/96] deps: bump minipass from 3.3.6 to 4.0.0 Bumps [minipass](https://github.com/isaacs/minipass) from 3.3.6 to 4.0.0. - [Release notes](https://github.com/isaacs/minipass/releases) - [Commits](https://github.com/isaacs/minipass/compare/v3.3.6...v4.0.0) --- updated-dependencies: - dependency-name: minipass dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9b055e74..35981614 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", + "minipass": "^4.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" From a044a87c6c7fb3ace4ea9bf903c63f0f15965398 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 7 Dec 2022 13:32:30 -0700 Subject: [PATCH 37/96] chore: release 6.1.13 (#344) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 6 ++++++ package.json | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1997844d..a0488a9b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "6.1.12" + ".": "6.1.13" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 7456e423..9ee82011 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [6.1.13](https://github.com/npm/node-tar/compare/v6.1.12...v6.1.13) (2022-12-07) + +### Dependencies + +* [`cc4e0dd`](https://github.com/npm/node-tar/commit/cc4e0ddfe523a0bce383846a67442c637a65d486) [#343](https://github.com/npm/node-tar/pull/343) bump minipass from 3.3.6 to 4.0.0 + ## [6.1.12](https://github.com/npm/node-tar/compare/v6.1.11...v6.1.12) (2022-10-31) ### Bug Fixes diff --git a/package.json b/package.json index 35981614..e6d6b933 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "6.1.12", + "version": "6.1.13", "repository": { "type": "git", "url": "https://github.com/npm/node-tar.git" From 5f316363790f925d01a5809718b2958d0f3c0661 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Dec 2022 20:01:33 +0000 Subject: [PATCH 38/96] chore: bump @npmcli/template-oss from 4.10.0 to 4.11.0 Bumps [@npmcli/template-oss](https://github.com/npm/template-oss) from 4.10.0 to 4.11.0. - [Release notes](https://github.com/npm/template-oss/releases) - [Changelog](https://github.com/npm/template-oss/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/template-oss/compare/v4.10.0...v4.11.0) --- updated-dependencies: - dependency-name: @npmcli/template-oss dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e6d6b933..84c3058d 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.10.0", + "@npmcli/template-oss": "4.11.0", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", "events-to-array": "^2.0.3", From 82bb3286a299903465a941bd70252843cf308a1e Mon Sep 17 00:00:00 2001 From: Luke Karrys <luke@lukekarrys.com> Date: Sat, 10 Dec 2022 12:30:38 -0700 Subject: [PATCH 39/96] chore: postinstall for dependabot template-oss PR --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 84c3058d..f9ab71a8 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.10.0", + "version": "4.11.0", "content": "scripts/template-oss", "engines": ">=10", "distPaths": [ From 75d3081ccf91853e13b7e0e28a077347b5a1fe3e Mon Sep 17 00:00:00 2001 From: jcesarmobile <jcesarmobile@gmail.com> Date: Tue, 11 Apr 2023 15:51:39 +0200 Subject: [PATCH 40/96] fix: update repository url in package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f9ab71a8..221410af 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "version": "6.1.13", "repository": { "type": "git", - "url": "https://github.com/npm/node-tar.git" + "url": "https://github.com/isaacs/node-tar.git" }, "scripts": { "genparse": "node scripts/generate-parse-fixtures.js", From 4cbdd674bfb2bda2769b94410650fd803e2f55ef Mon Sep 17 00:00:00 2001 From: Gar <gar+gh@danger.computer> Date: Tue, 2 May 2023 14:58:44 -0700 Subject: [PATCH 41/96] deps: minipass@5.0.0 PR-URL: https://github.com/isaacs/node-tar/pull/381 Credit: @wraithgar Close: #381 Reviewed-by: @isaacs --- lib/pack.js | 4 ++-- lib/read-entry.js | 4 ++-- lib/write-entry.js | 6 +++--- package.json | 2 +- test/pack.js | 6 +++--- test/parse.js | 6 +++--- test/unpack.js | 6 +++--- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/pack.js b/lib/pack.js index a3f4ff22..938ece8e 100644 --- a/lib/pack.js +++ b/lib/pack.js @@ -22,7 +22,7 @@ class PackJob { } } -const MiniPass = require('minipass') +const { Minipass } = require('minipass') const zlib = require('minizlib') const ReadEntry = require('./read-entry.js') const WriteEntry = require('./write-entry.js') @@ -56,7 +56,7 @@ const path = require('path') const warner = require('./warn-mixin.js') const normPath = require('./normalize-windows-path.js') -const Pack = warner(class Pack extends MiniPass { +const Pack = warner(class Pack extends Minipass { constructor (opt) { super(opt) opt = opt || Object.create(null) diff --git a/lib/read-entry.js b/lib/read-entry.js index 7f44bebf..6186266e 100644 --- a/lib/read-entry.js +++ b/lib/read-entry.js @@ -1,9 +1,9 @@ 'use strict' -const MiniPass = require('minipass') +const { Minipass } = require('minipass') const normPath = require('./normalize-windows-path.js') const SLURP = Symbol('slurp') -module.exports = class ReadEntry extends MiniPass { +module.exports = class ReadEntry extends Minipass { constructor (header, ex, gex) { super() // read entries always start life paused. this is to avoid the diff --git a/lib/write-entry.js b/lib/write-entry.js index 3b5540f7..7d2f3eb1 100644 --- a/lib/write-entry.js +++ b/lib/write-entry.js @@ -1,5 +1,5 @@ 'use strict' -const MiniPass = require('minipass') +const { Minipass } = require('minipass') const Pax = require('./pax.js') const Header = require('./header.js') const fs = require('fs') @@ -41,7 +41,7 @@ const stripAbsolutePath = require('./strip-absolute-path.js') const modeFix = require('./mode-fix.js') -const WriteEntry = warner(class WriteEntry extends MiniPass { +const WriteEntry = warner(class WriteEntry extends Minipass { constructor (p, opt) { opt = opt || {} super(opt) @@ -417,7 +417,7 @@ class WriteEntrySync extends WriteEntry { } } -const WriteEntryTar = warner(class WriteEntryTar extends MiniPass { +const WriteEntryTar = warner(class WriteEntryTar extends Minipass { constructor (readEntry, opt) { opt = opt || {} super(opt) diff --git a/package.json b/package.json index 221410af..f80a297a 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" diff --git a/test/pack.js b/test/pack.js index 8906ae30..28dbbf01 100644 --- a/test/pack.js +++ b/test/pack.js @@ -12,7 +12,7 @@ const Header = require('../lib/header.js') const zlib = require('zlib') const miniz = require('minizlib') const mutateFS = require('mutate-fs') -const MiniPass = require('minipass') +const { Minipass } = require('minipass') process.env.USER = 'isaacs' const EE = require('events').EventEmitter const rimraf = require('rimraf') @@ -563,8 +563,8 @@ t.test('readdir fail', t => { t.test('pipe into a slow reader', t => { const out = [] - const mp = new MiniPass() - const mp2 = new MiniPass() + const mp = new Minipass() + const mp2 = new Minipass() const p = new Pack({ cwd: files }).add('long-path').end() p.pause() p.pipe(mp).pipe(mp2) diff --git a/test/parse.js b/test/parse.js index 97705e42..3066f7e8 100644 --- a/test/parse.js +++ b/test/parse.js @@ -7,12 +7,12 @@ const fs = require('fs') const path = require('path') const tardir = path.resolve(__dirname, 'fixtures/tars') const zlib = require('zlib') -const MiniPass = require('minipass') +const { Minipass } = require('minipass') const Header = require('../lib/header.js') const EE = require('events').EventEmitter t.test('fixture tests', t => { - class ByteStream extends MiniPass { + class ByteStream extends Minipass { write (chunk) { for (let i = 0; i < chunk.length - 1; i++) { super.write(chunk.slice(i, i + 1)) @@ -604,7 +604,7 @@ t.test('end while consuming', t => { 'package/node_modules/b/package.json', ] - const mp = new MiniPass() + const mp = new Minipass() const p = new Parse({ onentry: entry => { actual.push(entry.path) diff --git a/test/unpack.js b/test/unpack.js index b23aab3d..2d75c946 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -5,7 +5,7 @@ process.umask(0o022) const Unpack = require('../lib/unpack.js') const UnpackSync = Unpack.Sync const t = require('tap') -const MiniPass = require('minipass') +const { Minipass } = require('minipass') const makeTar = require('./make-tar.js') const Header = require('../lib/header.js') @@ -2252,7 +2252,7 @@ t.test('transform', t => { } } - class Bracer extends MiniPass { + class Bracer extends Minipass { write (data) { const d = data.toString().split('').map(c => '[' + c + ']').join('') return super.write(d) @@ -2324,7 +2324,7 @@ t.test('transform error', t => { const poop = new Error('poop') const txFn = () => { - const tx = new MiniPass() + const tx = new Minipass() tx.write = () => tx.emit('error', poop) tx.resume() return tx From 4aaffc862f4e991f7965ecf6527072c4423ecb49 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Tue, 2 May 2023 15:45:50 -0700 Subject: [PATCH 42/96] 6.1.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f80a297a..943c8b4d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "6.1.13", + "version": "6.1.14", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From 8cd81396b8a0fa0399e22a7adf474ad74088540d Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Fri, 12 May 2023 14:37:36 -0700 Subject: [PATCH 43/96] move mutateFS reset out of t.teardown Not sure why this was failing on my system, but this fixes it. --- test/unpack.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unpack.js b/test/unpack.js index 2d75c946..399ae0e6 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -514,7 +514,8 @@ t.test('symlink in dir path', { t.test('clobber through symlink with busted unlink', t => { const poop = new Error('poop') - t.teardown(mutateFS.fail('unlink', poop)) + // for some reason, resetting fs.unlink in the teardown was breaking + const reset = mutateFS.fail('unlink', poop) const warnings = [] const u = new Unpack({ cwd: dir, @@ -523,6 +524,7 @@ t.test('symlink in dir path', { }) u.on('close', _ => { t.same(warnings, [['TAR_ENTRY_ERROR', 'poop', poop]]) + reset() t.end() }) u.end(data) From 24efc74543e7a36bc3db62e3b2c8a21cc568279b Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Fri, 12 May 2023 14:43:44 -0700 Subject: [PATCH 44/96] remove parallelism causing test/pack.js to be flaky --- test/pack.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/pack.js b/test/pack.js index 28dbbf01..46246ab1 100644 --- a/test/pack.js +++ b/test/pack.js @@ -1135,6 +1135,7 @@ t.test('prefix and hard links', t => { cwd: dir + '/in', prefix: 'out/x', noDirRecurse: true, + jobs: 1, }) const out = [] p.on('data', d => out.push(d)) From 4501bdbe59fb56dbc0de6e7e220340aaaef9394d Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Tue, 16 May 2023 10:33:22 -0700 Subject: [PATCH 45/96] Normalize unicode internally using NFD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the path reservation system, which defends against unicode path name collisions (the subject of a handful of past CVE issues), was using NFKD normalization internally to determine of two paths would be likely to reference the same file on disk. This has the weird effect of normalizing things like `℀` into simple decomposed character strings, for example `a/c`. These can contain slashes and double-dot sections, which means that the path reservations may end up reserving more (or different) paths than intended. Thankfully, tar was already *extracting* properly, even if the path reservations collided, and these collisions resulted in tar being *more* aggressive than it should be in restricting parallel extraction, rather than less. That's a good direction to err in, for security, but also, made tar less efficient than it could be in some edge cases. Using NFD normalization, unicode characters are not decomposed in compatibility mode, but still result in matching path reservation keys as intended. This does not cause any change in observed behavior, other than allowing some files to be extracted in parallel where it is provably safe to do so. Credit: discovered by @Sim4n6. This did not result in a juicy security vulnerability, but it sure looked like one at first. They were extremely patient, thorough, and persistent in trying to pin this down to a POC and CVE. There is very little reward or visibility when a security researcher finds a bug that doesn't result in a security disclosure, but the attempt often results in improvements to the project. --- lib/normalize-unicode.js | 2 +- lib/path-reservations.js | 2 +- lib/unpack.js | 2 +- .../test/normalize-unicode.js.test.cjs | 30 +++++++++++++++++++ test/normalize-unicode.js | 27 +++++++++++++++++ 5 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 tap-snapshots/test/normalize-unicode.js.test.cjs diff --git a/lib/normalize-unicode.js b/lib/normalize-unicode.js index 43dc406e..79e285ab 100644 --- a/lib/normalize-unicode.js +++ b/lib/normalize-unicode.js @@ -6,7 +6,7 @@ const normalizeCache = Object.create(null) const { hasOwnProperty } = Object.prototype module.exports = s => { if (!hasOwnProperty.call(normalizeCache, s)) { - normalizeCache[s] = s.normalize('NFKD') + normalizeCache[s] = s.normalize('NFD') } return normalizeCache[s] } diff --git a/lib/path-reservations.js b/lib/path-reservations.js index ef380cab..8d349d58 100644 --- a/lib/path-reservations.js +++ b/lib/path-reservations.js @@ -123,7 +123,7 @@ module.exports = () => { // effectively removing all parallelization on windows. paths = isWindows ? ['win32 parallelization disabled'] : paths.map(p => { // don't need normPath, because we skip this entirely for windows - return normalize(stripSlashes(join(p))).toLowerCase() + return stripSlashes(join(normalize(p))).toLowerCase() }) const dirs = new Set( diff --git a/lib/unpack.js b/lib/unpack.js index e341ad0c..fa46611c 100644 --- a/lib/unpack.js +++ b/lib/unpack.js @@ -105,7 +105,7 @@ const uint32 = (a, b, c) => // Note that on windows, we always drop the entire cache whenever a // symbolic link is encountered, because 8.3 filenames are impossible // to reason about, and collisions are hazards rather than just failures. -const cacheKeyNormalize = path => normalize(stripSlash(normPath(path))) +const cacheKeyNormalize = path => stripSlash(normPath(normalize(path))) .toLowerCase() const pruneCache = (cache, abs) => { diff --git a/tap-snapshots/test/normalize-unicode.js.test.cjs b/tap-snapshots/test/normalize-unicode.js.test.cjs new file mode 100644 index 00000000..3163313d --- /dev/null +++ b/tap-snapshots/test/normalize-unicode.js.test.cjs @@ -0,0 +1,30 @@ +/* IMPORTANT + * This snapshot file is auto-generated, but designed for humans. + * It should be checked into source control and tracked carefully. + * Re-generate by setting TAP_SNAPSHOT=1 and running tests. + * Make sure to inspect the output below. Do not ignore changes! + */ +'use strict' +exports[`test/normalize-unicode.js TAP normalize with strip slashes "1/4foo.txt" > normalized 1`] = ` +1/4foo.txt +` + +exports[`test/normalize-unicode.js TAP normalize with strip slashes "\\\\a\\\\b\\\\c\\\\d\\\\" > normalized 1`] = ` +/a/b/c/d +` + +exports[`test/normalize-unicode.js TAP normalize with strip slashes "Âŧfoo.txt" > normalized 1`] = ` +Âŧfoo.txt +` + +exports[`test/normalize-unicode.js TAP normalize with strip slashes "īš¨aaaaīš¨ddddīš¨" > normalized 1`] = ` +īš¨aaaaīš¨ddddīš¨ +` + +exports[`test/normalize-unicode.js TAP normalize with strip slashes "īŧŧbbbīŧŧeeeīŧŧ" > normalized 1`] = ` +īŧŧbbbīŧŧeeeīŧŧ +` + +exports[`test/normalize-unicode.js TAP normalize with strip slashes "īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ" > normalized 1`] = ` +īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ +` diff --git a/test/normalize-unicode.js b/test/normalize-unicode.js index 485d087f..0d34f38c 100644 --- a/test/normalize-unicode.js +++ b/test/normalize-unicode.js @@ -1,5 +1,8 @@ +process.env.TESTING_TAR_FAKE_PLATFORM = 'win32' const t = require('tap') const normalize = require('../lib/normalize-unicode.js') +const stripSlash = require('../lib/strip-trailing-slashes.js') +const normPath = require('../lib/normalize-windows-path.js') // cafeˁ const cafe1 = Buffer.from([0x63, 0x61, 0x66, 0xc3, 0xa9]).toString() @@ -10,3 +13,27 @@ const cafe2 = Buffer.from([0x63, 0x61, 0x66, 0x65, 0xcc, 0x81]).toString() t.equal(normalize(cafe1), normalize(cafe2), 'matching unicodes') t.equal(normalize(cafe1), normalize(cafe2), 'cached') t.equal(normalize('foo'), 'foo', 'non-unicode string') + +t.test('normalize with strip slashes', t => { + const paths = [ + '\\a\\b\\c\\d\\', + 'īš¨aaaaīš¨ddddīš¨', + 'īŧŧbbbīŧŧeeeīŧŧ', + 'īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ', + 'Âŧfoo.txt', + '1/4foo.txt', + ] + + t.plan(paths.length) + + for (const path of paths) { + t.test(JSON.stringify(path), t => { + const a = normalize(stripSlash(normPath(path))) + const b = stripSlash(normPath(normalize(path))) + t.matchSnapshot(a, 'normalized') + t.equal(a, b, 'order should not matter') + t.end() + }) + } + t.end() +}) From 3302cf7330052982ad7d7e9f85e823fa1bb945a4 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Tue, 16 May 2023 22:38:24 -0700 Subject: [PATCH 46/96] 6.1.15 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 943c8b4d..f59f54ae 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "6.1.14", + "version": "6.1.15", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From 8c5af15e43a769fd24aa7f1c84d93e54824d19d2 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Thu, 18 May 2023 14:50:01 -0700 Subject: [PATCH 47/96] silence dependabot --- .github/dependabot.yml | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 8da2a452..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,17 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -version: 2 - -updates: - - package-ecosystem: npm - directory: / - schedule: - interval: daily - allow: - - dependency-type: direct - versioning-strategy: increase-if-necessary - commit-message: - prefix: deps - prefix-development: chore - labels: - - "Dependencies" From c9fc57cbb81487846efa7b88edaf4babccef2f1f Mon Sep 17 00:00:00 2001 From: Jamie Magee <jamie.magee@gmail.com> Date: Mon, 12 Jun 2023 21:55:47 -0700 Subject: [PATCH 48/96] feat: add initial support for brotli --- lib/pack.js | 9 +++ lib/parse.js | 18 +++++ lib/replace.js | 2 +- lib/update.js | 2 +- test/extract.js | 27 +++++++ test/fixtures/example.tbr | Bin 0 -> 201 bytes test/pack.js | 165 ++++++++++++++++++++++++++++++++++++++ test/parse.js | 24 ++++++ test/replace.js | 25 ++++++ test/update.js | 26 ++++++ 10 files changed, 296 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/example.tbr diff --git a/lib/pack.js b/lib/pack.js index 938ece8e..81bc10f3 100644 --- a/lib/pack.js +++ b/lib/pack.js @@ -91,6 +91,15 @@ const Pack = warner(class Pack extends Minipass { this.zip.on('end', _ => super.end()) this.zip.on('drain', _ => this[ONDRAIN]()) this.on('resume', _ => this.zip.resume()) + } else if (opt.brotli) { + if (typeof opt.brotli !== 'object') { + opt.brotli = {} + } + this.zip = new zlib.BrotliCompress(opt.brotli) + this.zip.on('data', chunk => super.write(chunk)) + this.zip.on('end', _ => super.end()) + this.zip.on('drain', _ => this[ONDRAIN]()) + this.on('resume', _ => this.zip.resume()) } else { this.on('drain', this[ONDRAIN]) } diff --git a/lib/parse.js b/lib/parse.js index 4b85915c..8b8c8cee 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -97,6 +97,9 @@ module.exports = warner(class Parser extends EE { this.strict = !!opt.strict this.maxMetaEntrySize = opt.maxMetaEntrySize || maxMetaEntrySize this.filter = typeof opt.filter === 'function' ? opt.filter : noop + // Unlike gzip, brotli doesn't have any magic bytes to identify it + // Users need to explicitly tell us they're extracting a brotli file + this.brotli = opt.brotli // have to set this so that streams are ok piping into it this.writable = true @@ -356,6 +359,21 @@ module.exports = warner(class Parser extends EE { this[BUFFER] = chunk return true } + if (this[UNZIP] === null && this.brotli) { + const ended = this[ENDED] + this[ENDED] = false + this[UNZIP] = new zlib.BrotliDecompress() + this[UNZIP].on('data', chunk => this[CONSUMECHUNK](chunk)) + this[UNZIP].on('error', er => this.abort(er)) + this[UNZIP].on('end', _ => { + this[ENDED] = true + this[CONSUMECHUNK]() + }) + this[WRITING] = true + const ret = this[UNZIP][ended ? 'end' : 'write'](chunk) + this[WRITING] = false + return ret + } for (let i = 0; this[UNZIP] === null && i < gzipHeader.length; i++) { if (chunk[i] !== gzipHeader[i]) { this[UNZIP] = false diff --git a/lib/replace.js b/lib/replace.js index c6e619be..8db6800b 100644 --- a/lib/replace.js +++ b/lib/replace.js @@ -23,7 +23,7 @@ module.exports = (opt_, files, cb) => { throw new TypeError('file is required') } - if (opt.gzip) { + if (opt.gzip || opt.brotli || opt.file.endsWith('.br') || opt.file.endsWith('.tbr')) { throw new TypeError('cannot append to compressed archives') } diff --git a/lib/update.js b/lib/update.js index ded977dc..4d328543 100644 --- a/lib/update.js +++ b/lib/update.js @@ -13,7 +13,7 @@ module.exports = (opt_, files, cb) => { throw new TypeError('file is required') } - if (opt.gzip) { + if (opt.gzip || opt.brotli || opt.file.endsWith('.br') || opt.file.endsWith('.tbr')) { throw new TypeError('cannot append to compressed archives') } diff --git a/test/extract.js b/test/extract.js index e6c21d81..b79b91cc 100644 --- a/test/extract.js +++ b/test/extract.js @@ -310,3 +310,30 @@ t.test('sync gzip error edge case test', async t => { t.end() }) + +t.test('brotli', async t => { + const file = path.resolve(__dirname, 'fixtures/example.tbr') + const dir = path.resolve(__dirname, 'brotli') + + t.beforeEach(async () => { + await mkdirp(dir) + }) + + t.afterEach(async () => { + await rimraf(dir) + }) + + t.test('fails if brotli', async t => { + const expect = new Error("TAR_BAD_ARCHIVE: Unrecognized archive format") + t.throws(_ => x({ sync: true, file: file }), expect) + }) + + t.test('succeeds', t => { + x({ sync: true, file: file, C: dir, brotli: true }) + + t.same(fs.readdirSync(dir + '/x').sort(), + ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']) + t.end() + }) +}) + diff --git a/test/fixtures/example.tbr b/test/fixtures/example.tbr new file mode 100644 index 0000000000000000000000000000000000000000..01fbefa13baf72f9b6f7e124e15433d3a00529f3 GIT binary patch literal 201 zcmV;)05<<0|4$%})L~5=M^bIEYK(dz+pgRGr9eP}B)NJC^B-=e6;PUm2`8S|8~~hA zz&7UZHTI1qctqU1muQS=EJeEQ1C6D)-C(F8M}bO$@KDTo$+VaF>#P*6M&kb!q2h(_ z-{%cynfe9%^kHC`bdoK=IHj!VNhSEG(Lt|UzYv9okhLQKAc0+>XY3#r><)Tj2hqZA zEL<dC2-zoq9apSo=vh064ZDk;vV&+~x6pIjL0qtVBd7~N2)m7-M;Y=30J)Dww*#O9 DQc+=3 literal 0 HcmV?d00001 diff --git a/test/pack.js b/test/pack.js index 46246ab1..74158d7f 100644 --- a/test/pack.js +++ b/test/pack.js @@ -375,6 +375,13 @@ t.test('if gzip is truthy, make it an object', t => { t.end() }) +t.test('if brotli is truthy, make it an object', t => { + const opt = { brotli: true } + new Pack(opt) + t.type(opt.brotli, 'object') + t.end() +}) + t.test('gzip, also a very deep path', t => { const out = [] @@ -454,6 +461,85 @@ t.test('gzip, also a very deep path', t => { }) }) +t.test('brotli, also a very deep path', t => { + const out = [] + + new Pack({ + cwd: files, + brotli: { flush: 1 }, + }) + .add('dir') + .add('long-path') + .on('data', c => out.push(c)) + .end() + .on('end', _ => { + const zipped = Buffer.concat(out) + const data = zlib.brotliDecompressSync(zipped) + const entries = [] + for (var i = 0; i < data.length; i += 512) { + const slice = data.slice(i, i + 512) + const h = new Header(slice) + if (h.nullBlock) { + entries.push('null block') + } else if (h.cksumValid) { + entries.push([h.type, h.path]) + } else if (entries[entries.length - 1][0] === 'File') { + entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) + } + } + + const expect = [ + ['Directory', 'dir/'], + ['Directory', 'long-path/'], + ['File', 'dir/x'], + ['Directory', 'long-path/r/'], + ['Directory', 'long-path/r/e/'], + ['Directory', 'long-path/r/e/a/'], + ['Directory', 'long-path/r/e/a/l/'], + ['Directory', 'long-path/r/e/a/l/l/'], + ['Directory', 'long-path/r/e/a/l/l/y/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', 'short\n'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], + ['ExtendedHeader', 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222'], + ['ExtendedHeader', 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + ['ExtendedHeader', 'PaxHeader/Ί.txt'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', 'Ί'], + 'null block', + 'null block', + ] + + let ok = true + entries.forEach((entry, i) => { + ok = ok && + t.equal(entry[0], expect[i][0]) && + t.equal(entry[1], expect[i][1]) && + (!entry[2] || t.equal(entry[2], expect[i][2])) + }) + + // t.match(entries, expect) + t.end() + }) +}) + t.test('very deep gzip path, sync', t => { const pack = new PackSync({ cwd: files, @@ -533,6 +619,85 @@ t.test('very deep gzip path, sync', t => { t.end() }) +t.test('very deep brotli path, sync', t => { + const pack = new PackSync({ + cwd: files, + brotli: true, + }).add('dir') + .add('long-path') + .end() + + // these do nothing! + pack.pause() + pack.resume() + + const zipped = pack.read() + t.type(zipped, Buffer) + const data = zlib.brotliDecompressSync(zipped) + const entries = [] + for (var i = 0; i < data.length; i += 512) { + const slice = data.slice(i, i + 512) + const h = new Header(slice) + if (h.nullBlock) { + entries.push('null block') + } else if (h.cksumValid) { + entries.push([h.type, h.path]) + } else if (entries[entries.length - 1][0] === 'File') { + entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) + } + } + + const expect = [ + ['Directory', 'dir/'], + ['File', 'dir/x'], + ['Directory', 'long-path/'], + ['Directory', 'long-path/r/'], + ['Directory', 'long-path/r/e/'], + ['Directory', 'long-path/r/e/a/'], + ['Directory', 'long-path/r/e/a/l/'], + ['Directory', 'long-path/r/e/a/l/l/'], + ['Directory', 'long-path/r/e/a/l/l/y/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', 'short\n'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], + ['ExtendedHeader', 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222'], + ['ExtendedHeader', 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + ['ExtendedHeader', 'PaxHeader/Ί.txt'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', 'Ί'], + 'null block', + 'null block', + ] + + let ok = true + entries.forEach((entry, i) => { + ok = ok && + t.equal(entry[0], expect[i][0]) && + t.equal(entry[1], expect[i][1]) && + (!entry[2] || t.equal(entry[2], expect[i][2])) + }) + + // t.match(entries, expect) + t.end() +}) + t.test('write after end', t => { const p = new Pack() p.end() diff --git a/test/parse.js b/test/parse.js index 3066f7e8..0113e7b4 100644 --- a/test/parse.js +++ b/test/parse.js @@ -125,6 +125,30 @@ t.test('fixture tests', t => { bs.end(zlib.gzipSync(tardata)) }) + t.test('compress with brotli all at once', t => { + const p = new Parse({ + maxMetaEntrySize: maxMeta, + filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, + strict: strict, + brotli: {} + }) + trackEvents(t, expect, p) + p.end(zlib.brotliCompressSync(tardata)) + }) + + t.test('compress with brotli byte at a time', t => { + const bs = new ByteStream() + const bp = new Parse({ + maxMetaEntrySize: maxMeta, + filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, + strict: strict, + brotli: {}, + }) + trackEvents(t, expect, bp) + bs.pipe(bp) + bs.end(zlib.brotliCompressSync(tardata)) + }) + t.test('async chunks', t => { const p = new Parse({ maxMetaEntrySize: maxMeta, diff --git a/test/replace.js b/test/replace.js index 62c41eb8..75c97027 100644 --- a/test/replace.js +++ b/test/replace.js @@ -23,6 +23,7 @@ const fixtureDef = { 'zero.tar': Buffer.from(''), 'empty.tar': Buffer.alloc(512), 'compressed.tgz': zlib.gzipSync(data), + 'compressed.tbr': zlib.brotliCompressSync(data), } t.test('basic file add to archive (good or truncated)', t => { @@ -211,6 +212,30 @@ t.test('cannot append to gzipped archives', async t => { }, [path.basename(__filename)], er => t.match(er, expect)) }) +t.test('cannot append to brotli compressed archives', async t => { + const dir = t.testdir({ + 'compressed.tbr': fixtureDef['compressed.tbr'], + }) + const file = resolve(dir, 'compressed.tbr') + + const expect = new Error('cannot append to compressed archives') + const expectT = new TypeError('cannot append to compressed archives') + + t.throws(_ => r({ + file, + cwd: __dirname, + brotli: true, + }, [path.basename(__filename)]), expectT) + + t.throws(_ => r({ + file, + cwd: __dirname, + sync: true, + }, [path.basename(__filename)]), expect) + + t.end() +}) + t.test('other throws', t => { t.throws(_ => r({}, ['asdf']), new TypeError('file is required')) t.throws(_ => r({ file: 'asdf' }, []), diff --git a/test/update.js b/test/update.js index 0c8675f3..ff74c6e5 100644 --- a/test/update.js +++ b/test/update.js @@ -9,6 +9,7 @@ const { resolve } = require('path') const fixtures = path.resolve(__dirname, 'fixtures') const tars = path.resolve(fixtures, 'tars') const zlib = require('zlib') +const r = require("../lib/replace"); const spawn = require('child_process').spawn @@ -22,6 +23,7 @@ const fixtureDef = { 'zero.tar': Buffer.from(''), 'empty.tar': Buffer.alloc(512), 'compressed.tgz': zlib.gzipSync(data), + 'compressed.tbr': zlib.brotliCompressSync(data), } t.test('basic file add to archive (good or truncated)', t => { @@ -213,6 +215,30 @@ t.test('cannot append to gzipped archives', t => { }) }) +t.test('cannot append to brotli archives', t => { + const dir = t.testdir({ + 'compressed.tbr': fixtureDef['compressed.tbr'], + }) + const file = resolve(dir, 'compressed.tbr') + + const expect = new Error('cannot append to compressed archives') + const expectT = new TypeError('cannot append to compressed archives') + + t.throws(_ => u({ + file, + cwd: __dirname, + brotli: true, + }, [path.basename(__filename)]), expectT) + + t.throws(_ => u({ + file, + cwd: __dirname, + sync: true, + }, [path.basename(__filename)]), expect) + + t.end() +}) + t.test('other throws', t => { t.throws(_ => u({}, ['asdf']), new TypeError('file is required')) t.throws(_ => u({ file: 'asdf' }, []), From eeba22238736ed0832488efb3c515ada98073424 Mon Sep 17 00:00:00 2001 From: Jamie Magee <jamie.magee@gmail.com> Date: Mon, 19 Jun 2023 21:14:00 -0700 Subject: [PATCH 49/96] chore: lint fixes --- test/extract.js | 3 +- test/pack.js | 292 ++++++++++++++++++++++++------------------------ test/parse.js | 2 +- test/update.js | 1 - 4 files changed, 147 insertions(+), 151 deletions(-) diff --git a/test/extract.js b/test/extract.js index b79b91cc..e580db97 100644 --- a/test/extract.js +++ b/test/extract.js @@ -332,8 +332,7 @@ t.test('brotli', async t => { x({ sync: true, file: file, C: dir, brotli: true }) t.same(fs.readdirSync(dir + '/x').sort(), - ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']) + ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']) t.end() }) }) - diff --git a/test/pack.js b/test/pack.js index 74158d7f..99c733d3 100644 --- a/test/pack.js +++ b/test/pack.js @@ -376,10 +376,10 @@ t.test('if gzip is truthy, make it an object', t => { }) t.test('if brotli is truthy, make it an object', t => { - const opt = { brotli: true } - new Pack(opt) - t.type(opt.brotli, 'object') - t.end() + const opt = { brotli: true } + new Pack(opt) + t.type(opt.brotli, 'object') + t.end() }) t.test('gzip, also a very deep path', t => { @@ -462,82 +462,81 @@ t.test('gzip, also a very deep path', t => { }) t.test('brotli, also a very deep path', t => { - const out = [] + const out = [] - new Pack({ - cwd: files, - brotli: { flush: 1 }, - }) - .add('dir') - .add('long-path') - .on('data', c => out.push(c)) - .end() - .on('end', _ => { - const zipped = Buffer.concat(out) - const data = zlib.brotliDecompressSync(zipped) - const entries = [] - for (var i = 0; i < data.length; i += 512) { - const slice = data.slice(i, i + 512) - const h = new Header(slice) - if (h.nullBlock) { - entries.push('null block') - } else if (h.cksumValid) { - entries.push([h.type, h.path]) - } else if (entries[entries.length - 1][0] === 'File') { - entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) - } - } - - const expect = [ - ['Directory', 'dir/'], - ['Directory', 'long-path/'], - ['File', 'dir/x'], - ['Directory', 'long-path/r/'], - ['Directory', 'long-path/r/e/'], - ['Directory', 'long-path/r/e/a/'], - ['Directory', 'long-path/r/e/a/l/'], - ['Directory', 'long-path/r/e/a/l/l/'], - ['Directory', 'long-path/r/e/a/l/l/y/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', 'short\n'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], - ['ExtendedHeader', 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222'], - ['ExtendedHeader', 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], - ['ExtendedHeader', 'PaxHeader/Ί.txt'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', 'Ί'], - 'null block', - 'null block', - ] - - let ok = true - entries.forEach((entry, i) => { - ok = ok && + new Pack({ + cwd: files, + brotli: { flush: 1 }, + }) + .add('dir') + .add('long-path') + .on('data', c => out.push(c)) + .end() + .on('end', _ => { + const zipped = Buffer.concat(out) + const data = zlib.brotliDecompressSync(zipped) + const entries = [] + for (var i = 0; i < data.length; i += 512) { + const slice = data.slice(i, i + 512) + const h = new Header(slice) + if (h.nullBlock) { + entries.push('null block') + } else if (h.cksumValid) { + entries.push([h.type, h.path]) + } else if (entries[entries.length - 1][0] === 'File') { + entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) + } + } + + const expect = [ + ['Directory', 'dir/'], + ['Directory', 'long-path/'], + ['File', 'dir/x'], + ['Directory', 'long-path/r/'], + ['Directory', 'long-path/r/e/'], + ['Directory', 'long-path/r/e/a/'], + ['Directory', 'long-path/r/e/a/l/'], + ['Directory', 'long-path/r/e/a/l/l/'], + ['Directory', 'long-path/r/e/a/l/l/y/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', 'short\n'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], + ['ExtendedHeader', 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222'], + ['ExtendedHeader', 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + ['ExtendedHeader', 'PaxHeader/Ί.txt'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', 'Ί'], + 'null block', + 'null block', + ] + + let ok = true + entries.forEach((entry, i) => { + ok = ok && t.equal(entry[0], expect[i][0]) && t.equal(entry[1], expect[i][1]) && (!entry[2] || t.equal(entry[2], expect[i][2])) - }) + }) - // t.match(entries, expect) - t.end() - }) + t.end() + }) }) t.test('very deep gzip path, sync', t => { @@ -620,82 +619,81 @@ t.test('very deep gzip path, sync', t => { }) t.test('very deep brotli path, sync', t => { - const pack = new PackSync({ - cwd: files, - brotli: true, - }).add('dir') - .add('long-path') - .end() - - // these do nothing! - pack.pause() - pack.resume() - - const zipped = pack.read() - t.type(zipped, Buffer) - const data = zlib.brotliDecompressSync(zipped) - const entries = [] - for (var i = 0; i < data.length; i += 512) { - const slice = data.slice(i, i + 512) - const h = new Header(slice) - if (h.nullBlock) { - entries.push('null block') - } else if (h.cksumValid) { - entries.push([h.type, h.path]) - } else if (entries[entries.length - 1][0] === 'File') { - entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) - } + const pack = new PackSync({ + cwd: files, + brotli: true, + }).add('dir') + .add('long-path') + .end() + + // these do nothing! + pack.pause() + pack.resume() + + const zipped = pack.read() + t.type(zipped, Buffer) + const data = zlib.brotliDecompressSync(zipped) + const entries = [] + for (var i = 0; i < data.length; i += 512) { + const slice = data.slice(i, i + 512) + const h = new Header(slice) + if (h.nullBlock) { + entries.push('null block') + } else if (h.cksumValid) { + entries.push([h.type, h.path]) + } else if (entries[entries.length - 1][0] === 'File') { + entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) } + } - const expect = [ - ['Directory', 'dir/'], - ['File', 'dir/x'], - ['Directory', 'long-path/'], - ['Directory', 'long-path/r/'], - ['Directory', 'long-path/r/e/'], - ['Directory', 'long-path/r/e/a/'], - ['Directory', 'long-path/r/e/a/l/'], - ['Directory', 'long-path/r/e/a/l/l/'], - ['Directory', 'long-path/r/e/a/l/l/y/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', 'short\n'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], - ['ExtendedHeader', 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222'], - ['ExtendedHeader', 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], - ['ExtendedHeader', 'PaxHeader/Ί.txt'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', 'Ί'], - 'null block', - 'null block', - ] + const expect = [ + ['Directory', 'dir/'], + ['File', 'dir/x'], + ['Directory', 'long-path/'], + ['Directory', 'long-path/r/'], + ['Directory', 'long-path/r/e/'], + ['Directory', 'long-path/r/e/a/'], + ['Directory', 'long-path/r/e/a/l/'], + ['Directory', 'long-path/r/e/a/l/l/'], + ['Directory', 'long-path/r/e/a/l/l/y/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/'], + ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', 'short\n'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], + ['ExtendedHeader', 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222'], + ['ExtendedHeader', 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + ['ExtendedHeader', 'PaxHeader/Ί.txt'], + ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', 'Ί'], + 'null block', + 'null block', + ] - let ok = true - entries.forEach((entry, i) => { - ok = ok && - t.equal(entry[0], expect[i][0]) && - t.equal(entry[1], expect[i][1]) && - (!entry[2] || t.equal(entry[2], expect[i][2])) - }) + let ok = true + entries.forEach((entry, i) => { + ok = ok && + t.equal(entry[0], expect[i][0]) && + t.equal(entry[1], expect[i][1]) && + (!entry[2] || t.equal(entry[2], expect[i][2])) + }) - // t.match(entries, expect) - t.end() + t.end() }) t.test('write after end', t => { diff --git a/test/parse.js b/test/parse.js index 0113e7b4..dd74b2c7 100644 --- a/test/parse.js +++ b/test/parse.js @@ -130,7 +130,7 @@ t.test('fixture tests', t => { maxMetaEntrySize: maxMeta, filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, strict: strict, - brotli: {} + brotli: {}, }) trackEvents(t, expect, p) p.end(zlib.brotliCompressSync(tardata)) diff --git a/test/update.js b/test/update.js index ff74c6e5..7034a165 100644 --- a/test/update.js +++ b/test/update.js @@ -9,7 +9,6 @@ const { resolve } = require('path') const fixtures = path.resolve(__dirname, 'fixtures') const tars = path.resolve(fixtures, 'tars') const zlib = require('zlib') -const r = require("../lib/replace"); const spawn = require('child_process').spawn From 336fa8f27c44bec70d46a6482096af24c668ee16 Mon Sep 17 00:00:00 2001 From: Jamie Magee <jamie.magee@gmail.com> Date: Mon, 19 Jun 2023 21:14:39 -0700 Subject: [PATCH 50/96] refactor: dry and other pr comments PR-URL: https://github.com/isaacs/node-tar/pull/391 Credit: @JamieMagee Close: #391 Reviewed-by: @isaacs --- lib/pack.js | 30 ++++++++++++++++-------------- lib/parse.js | 22 ++++------------------ test/extract.js | 21 +++++++++++++++++---- test/pack.js | 6 ++++++ test/parse.js | 22 ++++++++++++++++++++++ 5 files changed, 65 insertions(+), 36 deletions(-) diff --git a/lib/pack.js b/lib/pack.js index 81bc10f3..789a2a71 100644 --- a/lib/pack.js +++ b/lib/pack.js @@ -79,23 +79,25 @@ const Pack = warner(class Pack extends Minipass { this.portable = !!opt.portable this.zip = null - if (opt.gzip) { - if (typeof opt.gzip !== 'object') { - opt.gzip = {} + if (opt.gzip || opt.brotli) { + if (opt.gzip && opt.brotli) { + throw new TypeError('gzip and brotli are mutually exclusive') } - if (this.portable) { - opt.gzip.portable = true + if (opt.gzip) { + if (typeof opt.gzip !== 'object') { + opt.gzip = {} + } + if (this.portable) { + opt.gzip.portable = true + } + this.zip = new zlib.Gzip(opt.gzip) } - this.zip = new zlib.Gzip(opt.gzip) - this.zip.on('data', chunk => super.write(chunk)) - this.zip.on('end', _ => super.end()) - this.zip.on('drain', _ => this[ONDRAIN]()) - this.on('resume', _ => this.zip.resume()) - } else if (opt.brotli) { - if (typeof opt.brotli !== 'object') { - opt.brotli = {} + if (opt.brotli) { + if (typeof opt.brotli !== 'object') { + opt.brotli = {} + } + this.zip = new zlib.BrotliCompress(opt.brotli) } - this.zip = new zlib.BrotliCompress(opt.brotli) this.zip.on('data', chunk => super.write(chunk)) this.zip.on('end', _ => super.end()) this.zip.on('drain', _ => this[ONDRAIN]()) diff --git a/lib/parse.js b/lib/parse.js index 8b8c8cee..6906d059 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -99,7 +99,8 @@ module.exports = warner(class Parser extends EE { this.filter = typeof opt.filter === 'function' ? opt.filter : noop // Unlike gzip, brotli doesn't have any magic bytes to identify it // Users need to explicitly tell us they're extracting a brotli file - this.brotli = opt.brotli + // Or we infer from the file extension + this.brotli = opt.brotli || (opt.file && (opt.file.endsWith('.tar.br') || opt.file.endsWith('.tbr'))) // have to set this so that streams are ok piping into it this.writable = true @@ -359,30 +360,15 @@ module.exports = warner(class Parser extends EE { this[BUFFER] = chunk return true } - if (this[UNZIP] === null && this.brotli) { - const ended = this[ENDED] - this[ENDED] = false - this[UNZIP] = new zlib.BrotliDecompress() - this[UNZIP].on('data', chunk => this[CONSUMECHUNK](chunk)) - this[UNZIP].on('error', er => this.abort(er)) - this[UNZIP].on('end', _ => { - this[ENDED] = true - this[CONSUMECHUNK]() - }) - this[WRITING] = true - const ret = this[UNZIP][ended ? 'end' : 'write'](chunk) - this[WRITING] = false - return ret - } for (let i = 0; this[UNZIP] === null && i < gzipHeader.length; i++) { if (chunk[i] !== gzipHeader[i]) { this[UNZIP] = false } } - if (this[UNZIP] === null) { + if (this[UNZIP] === null || (this[UNZIP] === false && this.brotli)) { const ended = this[ENDED] this[ENDED] = false - this[UNZIP] = new zlib.Unzip() + this[UNZIP] = this.brotli ? new zlib.BrotliDecompress() : new zlib.Unzip() this[UNZIP].on('data', chunk => this[CONSUMECHUNK](chunk)) this[UNZIP].on('error', er => this.abort(er)) this[UNZIP].on('end', _ => { diff --git a/test/extract.js b/test/extract.js index e580db97..c11d0afc 100644 --- a/test/extract.js +++ b/test/extract.js @@ -323,12 +323,25 @@ t.test('brotli', async t => { await rimraf(dir) }) - t.test('fails if brotli', async t => { - const expect = new Error("TAR_BAD_ARCHIVE: Unrecognized archive format") - t.throws(_ => x({ sync: true, file: file }), expect) + t.test('fails if unknown file extension', async t => { + const filename = path.resolve(__dirname, 'brotli/example.unknown') + const f = fs.openSync(filename, 'a') + fs.closeSync(f) + + const expect = new Error('TAR_BAD_ARCHIVE: Unrecognized archive format') + + t.throws(_ => x({ sync: true, file: filename }), expect) + }) + + t.test('succeeds based on file extension', t => { + x({ sync: true, file: file, C: dir }) + + t.same(fs.readdirSync(dir + '/x').sort(), + ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']) + t.end() }) - t.test('succeeds', t => { + t.test('succeeds when passed explicit option', t => { x({ sync: true, file: file, C: dir, brotli: true }) t.same(fs.readdirSync(dir + '/x').sort(), diff --git a/test/pack.js b/test/pack.js index 99c733d3..a4f8bfbe 100644 --- a/test/pack.js +++ b/test/pack.js @@ -382,6 +382,12 @@ t.test('if brotli is truthy, make it an object', t => { t.end() }) +t.test('throws if both gzip and brotli are truthy', t => { + const opt = { gzip: true, brotli: true } + t.throws(_ => new Pack(opt), new TypeError('gzip and brotli are mutually exclusive')) + t.end() +}) + t.test('gzip, also a very deep path', t => { const out = [] diff --git a/test/parse.js b/test/parse.js index dd74b2c7..dff01f3c 100644 --- a/test/parse.js +++ b/test/parse.js @@ -125,6 +125,28 @@ t.test('fixture tests', t => { bs.end(zlib.gzipSync(tardata)) }) + t.test('compress with brotli based on filename .tar.br', t => { + const p = new Parse({ + maxMetaEntrySize: maxMeta, + filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, + strict: strict, + file: 'example.tar.br', + }) + trackEvents(t, expect, p) + p.end(zlib.brotliCompressSync(tardata)) + }) + + t.test('compress with brotli based on filename .tbr', t => { + const p = new Parse({ + maxMetaEntrySize: maxMeta, + filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, + strict: strict, + file: 'example.tbr', + }) + trackEvents(t, expect, p) + p.end(zlib.brotliCompressSync(tardata)) + }) + t.test('compress with brotli all at once', t => { const p = new Parse({ maxMetaEntrySize: maxMeta, From db6f53928650a04b340ecdc01db2d49937e5d63c Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Mon, 4 Sep 2023 22:18:19 -0700 Subject: [PATCH 51/96] file inference improvements for .tbr and .tgz When unpacking, only infer brotli compression from the filename if the first 512 bytes are an invalid tar header (or the stream is less than 512 bytes) While Brotli doesn't give us magic header bytes like gzip, we can be reasonably sure that a .tbr file starting with 512 bytes of valid tar data is almost certainly not a brotli compressed archive. And a .tbr file starting with the magic gzip bytes is almost certainly a gzip archive, and not brotli, despite what the filename says. In all cases, if explicit boolean or object values appear in the options for either gzip or brotli, we respect that, and ignore the filename. --- lib/pack.js | 1 + lib/parse.js | 45 ++++++++++++++++++++++++++++++++++++++++--- test/parse.js | 53 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 94 insertions(+), 5 deletions(-) diff --git a/lib/pack.js b/lib/pack.js index 789a2a71..d533a068 100644 --- a/lib/pack.js +++ b/lib/pack.js @@ -79,6 +79,7 @@ const Pack = warner(class Pack extends Minipass { this.portable = !!opt.portable this.zip = null + if (opt.gzip || opt.brotli) { if (opt.gzip && opt.brotli) { throw new TypeError('gzip and brotli are mutually exclusive') diff --git a/lib/parse.js b/lib/parse.js index 6906d059..94e53042 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -100,7 +100,13 @@ module.exports = warner(class Parser extends EE { // Unlike gzip, brotli doesn't have any magic bytes to identify it // Users need to explicitly tell us they're extracting a brotli file // Or we infer from the file extension - this.brotli = opt.brotli || (opt.file && (opt.file.endsWith('.tar.br') || opt.file.endsWith('.tbr'))) + const isTBR = (opt.file && ( + opt.file.endsWith('.tar.br') || opt.file.endsWith('.tbr'))) + // if it's a tbr file it MIGHT be brotli, but we don't know until + // we look at it and verify it's not a valid tar file. + this.brotli = !opt.gzip && opt.brotli !== undefined ? opt.brotli + : isTBR ? undefined + : false // have to set this so that streams are ok piping into it this.writable = true @@ -351,7 +357,9 @@ module.exports = warner(class Parser extends EE { } // first write, might be gzipped - if (this[UNZIP] === null && chunk) { + const needSniff = this[UNZIP] === null || + this.brotli === undefined && this[UNZIP] === false + if (needSniff && chunk) { if (this[BUFFER]) { chunk = Buffer.concat([this[BUFFER], chunk]) this[BUFFER] = null @@ -360,15 +368,45 @@ module.exports = warner(class Parser extends EE { this[BUFFER] = chunk return true } + + // look for gzip header for (let i = 0; this[UNZIP] === null && i < gzipHeader.length; i++) { if (chunk[i] !== gzipHeader[i]) { this[UNZIP] = false } } + + const maybeBrotli = this.brotli === undefined + if (this[UNZIP] === false && maybeBrotli) { + // read the first header to see if it's a valid tar file. If so, + // we can safely assume that it's not actually brotli, despite the + // .tbr or .tar.br file extension. + // if we ended before getting a full chunk, yes, def brotli + if (chunk.length < 512) { + if (this[ENDED]) { + this.brotli = true + } else { + this[BUFFER] = chunk + return true + } + } else { + // if it's tar, it's pretty reliably not brotli, chances of + // that happening are astronomical. + try { + new Header(chunk.slice(0, 512)) + this.brotli = false + } catch (_) { + this.brotli = true + } + } + } + if (this[UNZIP] === null || (this[UNZIP] === false && this.brotli)) { const ended = this[ENDED] this[ENDED] = false - this[UNZIP] = this.brotli ? new zlib.BrotliDecompress() : new zlib.Unzip() + this[UNZIP] = this[UNZIP] === null + ? new zlib.Unzip() + : new zlib.BrotliDecompress() this[UNZIP].on('data', chunk => this[CONSUMECHUNK](chunk)) this[UNZIP].on('error', er => this.abort(er)) this[UNZIP].on('end', _ => { @@ -506,6 +544,7 @@ module.exports = warner(class Parser extends EE { this[UNZIP].end(chunk) } else { this[ENDED] = true + if (this.brotli === undefined) chunk = chunk || Buffer.alloc(0) this.write(chunk) } } diff --git a/test/parse.js b/test/parse.js index dff01f3c..549b3701 100644 --- a/test/parse.js +++ b/test/parse.js @@ -80,7 +80,7 @@ t.test('fixture tests', t => { const eventsFile = parsedir + '/' + base + tail const expect = require(eventsFile) - t.test('one byte at a time', t => { + t.test('uncompressed one byte at a time', t => { const bs = new ByteStream() const opt = (maxMeta || filter || strict) ? { maxMetaEntrySize: maxMeta, @@ -93,7 +93,7 @@ t.test('fixture tests', t => { bs.end(tardata) }) - t.test('all at once', t => { + t.test('uncompressed all at once', t => { const p = new Parse({ maxMetaEntrySize: maxMeta, filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, @@ -103,6 +103,31 @@ t.test('fixture tests', t => { p.end(tardata) }) + t.test('uncompressed one byte at a time, filename .tbr', t => { + const bs = new ByteStream() + const opt = (maxMeta || filter || strict) ? { + maxMetaEntrySize: maxMeta, + filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, + strict: strict, + file: 'example.tbr', + } : null + const bp = new Parse(opt) + trackEvents(t, expect, bp) + bs.pipe(bp) + bs.end(tardata) + }) + + t.test('uncompressed all at once, filename .tar.br', t => { + const p = new Parse({ + maxMetaEntrySize: maxMeta, + filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, + strict: strict, + file: 'example.tar.br', + }) + trackEvents(t, expect, p) + p.end(tardata) + }) + t.test('gzipped all at once', t => { const p = new Parse({ maxMetaEntrySize: maxMeta, @@ -113,6 +138,17 @@ t.test('fixture tests', t => { p.end(zlib.gzipSync(tardata)) }) + t.test('gzipped all at once, filename .tbr', t => { + const p = new Parse({ + maxMetaEntrySize: maxMeta, + filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, + strict: strict, + file: 'example.tbr', + }) + trackEvents(t, expect, p) + p.end(zlib.gzipSync(tardata)) + }) + t.test('gzipped byte at a time', t => { const bs = new ByteStream() const bp = new Parse({ @@ -171,6 +207,19 @@ t.test('fixture tests', t => { bs.end(zlib.brotliCompressSync(tardata)) }) + t.test('compress with brotli .tbr byte at a time', t => { + const bs = new ByteStream() + const bp = new Parse({ + maxMetaEntrySize: maxMeta, + filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, + strict: strict, + file: 'example.tbr', + }) + trackEvents(t, expect, bp) + bs.pipe(bp) + bs.end(zlib.brotliCompressSync(tardata)) + }) + t.test('async chunks', t => { const p = new Parse({ maxMetaEntrySize: maxMeta, From 689928a0ba7d9b9014d88a5fa35261f9ae4ef2f3 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Mon, 4 Sep 2023 22:26:30 -0700 Subject: [PATCH 52/96] ci that works outside of npm org --- .github/CODEOWNERS | 3 - .github/ISSUE_TEMPLATE/bug.yml | 54 ----- .github/ISSUE_TEMPLATE/config.yml | 3 - .github/matchers/tap.json | 32 --- .github/workflows/audit.yml | 42 ---- .github/workflows/ci-release.yml | 223 ------------------- .github/workflows/ci.yml | 125 +++-------- .github/workflows/codeql-analysis.yml | 41 ---- .github/workflows/post-dependabot.yml | 124 ----------- .github/workflows/pull-request.yml | 51 ----- .github/workflows/release.yml | 308 -------------------------- 11 files changed, 25 insertions(+), 981 deletions(-) delete mode 100644 .github/CODEOWNERS delete mode 100644 .github/ISSUE_TEMPLATE/bug.yml delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/matchers/tap.json delete mode 100644 .github/workflows/audit.yml delete mode 100644 .github/workflows/ci-release.yml delete mode 100644 .github/workflows/codeql-analysis.yml delete mode 100644 .github/workflows/post-dependabot.yml delete mode 100644 .github/workflows/pull-request.yml delete mode 100644 .github/workflows/release.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 2c54b0d2..00000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -* @npm/cli-team diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml deleted file mode 100644 index d043192f..00000000 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ /dev/null @@ -1,54 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -name: Bug -description: File a bug/issue -title: "[BUG] <title>" -labels: [ Bug, Needs Triage ] - -body: - - type: checkboxes - attributes: - label: Is there an existing issue for this? - description: Please [search here](./issues) to see if an issue already exists for your problem. - options: - - label: I have searched the existing issues - required: true - - type: textarea - attributes: - label: Current Behavior - description: A clear & concise description of what you're experiencing. - validations: - required: false - - type: textarea - attributes: - label: Expected Behavior - description: A clear & concise description of what you expected to happen. - validations: - required: false - - type: textarea - attributes: - label: Steps To Reproduce - description: Steps to reproduce the behavior. - value: | - 1. In this environment... - 2. With this config... - 3. Run '...' - 4. See error... - validations: - required: false - - type: textarea - attributes: - label: Environment - description: | - examples: - - **npm**: 7.6.3 - - **Node**: 13.14.0 - - **OS**: Ubuntu 20.04 - - **platform**: Macbook Pro - value: | - - npm: - - Node: - - OS: - - platform: - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index d640909f..00000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,3 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -blank_issues_enabled: true diff --git a/.github/matchers/tap.json b/.github/matchers/tap.json deleted file mode 100644 index 2c81ea98..00000000 --- a/.github/matchers/tap.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "//@npmcli/template-oss": "This file is automatically added by @npmcli/template-oss. Do not edit.", - "problemMatcher": [ - { - "owner": "tap", - "pattern": [ - { - "regexp": "^\\s*not ok \\d+ - (.*)", - "message": 1 - }, - { - "regexp": "^\\s*---" - }, - { - "regexp": "^\\s*at:" - }, - { - "regexp": "^\\s*line:\\s*(\\d+)", - "line": 1 - }, - { - "regexp": "^\\s*column:\\s*(\\d+)", - "column": 1 - }, - { - "regexp": "^\\s*file:\\s*(.*)", - "file": 1 - } - ] - } - ] -} diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml deleted file mode 100644 index a4d035a7..00000000 --- a/.github/workflows/audit.yml +++ /dev/null @@ -1,42 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -name: Audit - -on: - workflow_dispatch: - schedule: - # "At 08:00 UTC (01:00 PT) on Monday" https://crontab.guru/#0_8_*_*_1 - - cron: "0 8 * * 1" - -jobs: - audit: - name: Audit Dependencies - if: github.repository_owner == 'npm' - runs-on: ubuntu-latest - defaults: - run: - shell: bash - steps: - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Install npm@latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --ignore-scripts --no-audit --no-fund --package-lock - - name: Run Production Audit - run: npm audit --omit=dev - - name: Run Full Audit - run: npm audit --audit-level=none diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml deleted file mode 100644 index b062c0a0..00000000 --- a/.github/workflows/ci-release.yml +++ /dev/null @@ -1,223 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -name: CI - Release - -on: - workflow_dispatch: - inputs: - ref: - required: true - type: string - default: main - workflow_call: - inputs: - ref: - required: true - type: string - check-sha: - required: true - type: string - -jobs: - lint-all: - name: Lint All - if: github.repository_owner == 'npm' - runs-on: ubuntu-latest - defaults: - run: - shell: bash - steps: - - name: Get Workflow Job - uses: actions/github-script@v6 - if: inputs.check-sha - id: check-output - env: - JOB_NAME: "Lint All" - MATRIX_NAME: "" - with: - script: | - const { owner, repo } = context.repo - - const { data } = await github.rest.actions.listJobsForWorkflowRun({ - owner, - repo, - run_id: context.runId, - per_page: 100 - }) - - const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME - const job = data.jobs.find(j => j.name.endsWith(jobName)) - const jobUrl = job?.html_url - - const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ inputs.check-sha }}` - - let summary = `This check is assosciated with ${shaUrl}\n\n` - - if (jobUrl) { - summary += `For run logs, click here: ${jobUrl}` - } else { - summary += `Run logs could not be found for a job with name: "${jobName}"` - } - - return { summary } - - name: Create Check - uses: LouisBrunner/checks-action@v1.3.1 - id: check - if: inputs.check-sha - with: - token: ${{ secrets.GITHUB_TOKEN }} - status: in_progress - name: Lint All - sha: ${{ inputs.check-sha }} - output: ${{ steps.check-output.outputs.result }} - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - with: - ref: ${{ inputs.ref }} - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Install npm@latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --ignore-scripts --no-audit --no-fund - - name: Lint - run: npm run lint --ignore-scripts - - name: Post Lint - run: npm run postlint --ignore-scripts - - name: Conclude Check - uses: LouisBrunner/checks-action@v1.3.1 - if: steps.check.outputs.check_id && always() - with: - token: ${{ secrets.GITHUB_TOKEN }} - conclusion: ${{ job.status }} - check_id: ${{ steps.check.outputs.check_id }} - - test-all: - name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }} - if: github.repository_owner == 'npm' - strategy: - fail-fast: false - matrix: - platform: - - name: Linux - os: ubuntu-latest - shell: bash - - name: macOS - os: macos-latest - shell: bash - - name: Windows - os: windows-latest - shell: cmd - node-version: - - 10.x - - 12.x - - 14.x - - 16.x - - 18.x - runs-on: ${{ matrix.platform.os }} - defaults: - run: - shell: ${{ matrix.platform.shell }} - steps: - - name: Get Workflow Job - uses: actions/github-script@v6 - if: inputs.check-sha - id: check-output - env: - JOB_NAME: "Test All" - MATRIX_NAME: " - ${{ matrix.platform.name }} - ${{ matrix.node-version }}" - with: - script: | - const { owner, repo } = context.repo - - const { data } = await github.rest.actions.listJobsForWorkflowRun({ - owner, - repo, - run_id: context.runId, - per_page: 100 - }) - - const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME - const job = data.jobs.find(j => j.name.endsWith(jobName)) - const jobUrl = job?.html_url - - const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ inputs.check-sha }}` - - let summary = `This check is assosciated with ${shaUrl}\n\n` - - if (jobUrl) { - summary += `For run logs, click here: ${jobUrl}` - } else { - summary += `Run logs could not be found for a job with name: "${jobName}"` - } - - return { summary } - - name: Create Check - uses: LouisBrunner/checks-action@v1.3.1 - id: check - if: inputs.check-sha - with: - token: ${{ secrets.GITHUB_TOKEN }} - status: in_progress - name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }} - sha: ${{ inputs.check-sha }} - output: ${{ steps.check-output.outputs.result }} - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - with: - ref: ${{ inputs.ref }} - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - name: Update Windows npm - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Install npm@7 - if: startsWith(matrix.node-version, '10.') || startsWith(matrix.node-version, '12.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Install npm@latest - if: ${{ !startsWith(matrix.node-version, '10.') && !startsWith(matrix.node-version, '12.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --ignore-scripts --no-audit --no-fund - - name: Set Tap RC - run: node ./test/fixtures/taprc.js - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - - name: Test - run: npm test --ignore-scripts - - name: Conclude Check - uses: LouisBrunner/checks-action@v1.3.1 - if: steps.check.outputs.check_id && always() - with: - token: ${{ secrets.GITHUB_TOKEN }} - conclusion: ${{ job.status }} - check_id: ${{ steps.check.outputs.check_id }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc3cf2e8..d026a49f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,114 +1,39 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - name: CI -on: - workflow_dispatch: - pull_request: - push: - branches: - - main - - latest - schedule: - # "At 09:00 UTC (02:00 PT) on Monday" https://crontab.guru/#0_9_*_*_1 - - cron: "0 9 * * 1" +on: [push, pull_request] jobs: - lint: - name: Lint - if: github.repository_owner == 'npm' - runs-on: ubuntu-latest - defaults: - run: - shell: bash - steps: - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Install npm@latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --ignore-scripts --no-audit --no-fund - - name: Lint - run: npm run lint --ignore-scripts - - name: Post Lint - run: npm run postlint --ignore-scripts - - test: - name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} - if: github.repository_owner == 'npm' + build: strategy: - fail-fast: false matrix: + node-version: [16.x, 18.x, 20.x] platform: - - name: Linux - os: ubuntu-latest - shell: bash - - name: macOS - os: macos-latest - shell: bash - - name: Windows - os: windows-latest - shell: cmd - node-version: - - 10.x - - 12.x - - 14.x - - 16.x - - 18.x + - os: ubuntu-latest + shell: bash + - os: macos-latest + shell: bash + - os: windows-latest + shell: bash + - os: windows-latest + shell: powershell + fail-fast: false + runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} + steps: - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 + - name: Checkout Repository + uses: actions/checkout@v1.1.0 + + - name: Use Nodejs ${{ matrix.node-version }} + uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - - name: Update Windows npm - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Install npm@7 - if: startsWith(matrix.node-version, '10.') || startsWith(matrix.node-version, '12.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Install npm@latest - if: ${{ !startsWith(matrix.node-version, '10.') && !startsWith(matrix.node-version, '12.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --ignore-scripts --no-audit --no-fund - - name: Set Tap RC - run: node ./test/fixtures/taprc.js - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - - name: Test - run: npm test --ignore-scripts + + - name: Install dependencies + run: npm install + + - name: Run Tests + run: npm test -- -c -t0 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index cf9dc41c..00000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,41 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -name: CodeQL - -on: - push: - branches: - - main - - latest - pull_request: - branches: - - main - - latest - schedule: - # "At 10:00 UTC (03:00 PT) on Monday" https://crontab.guru/#0_10_*_*_1 - - cron: "0 10 * * 1" - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - steps: - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: javascript - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml deleted file mode 100644 index 3bc9f1f9..00000000 --- a/.github/workflows/post-dependabot.yml +++ /dev/null @@ -1,124 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -name: Post Dependabot - -on: pull_request - -permissions: - contents: write - -jobs: - template-oss: - name: template-oss - if: github.repository_owner == 'npm' && github.actor == 'dependabot[bot]' - runs-on: ubuntu-latest - defaults: - run: - shell: bash - steps: - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.ref }} - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Install npm@latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --ignore-scripts --no-audit --no-fund - - name: Fetch Dependabot Metadata - id: metadata - uses: dependabot/fetch-metadata@v1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - - # Dependabot can update multiple directories so we output which directory - # it is acting on so we can run the command for the correct root or workspace - - name: Get Dependabot Directory - if: contains(steps.metadata.outputs.dependency-names, '@npmcli/template-oss') - id: flags - run: | - dependabot_dir="${{ steps.metadata.outputs.directory }}" - if [[ "$dependabot_dir" == "/" ]]; then - echo "::set-output name=workspace::-iwr" - else - # strip leading slash from directory so it works as a - # a path to the workspace flag - echo "::set-output name=workspace::-w ${dependabot_dir#/}" - fi - - - name: Apply Changes - if: steps.flags.outputs.workspace - id: apply - run: | - npm run template-oss-apply ${{ steps.flags.outputs.workspace }} - if [[ `git status --porcelain` ]]; then - echo "::set-output name=changes::true" - fi - # This only sets the conventional commit prefix. This workflow can't reliably determine - # what the breaking change is though. If a BREAKING CHANGE message is required then - # this PR check will fail and the commit will be amended with stafftools - if [[ "${{ steps.metadata.outputs.update-type }}" == "version-update:semver-major" ]]; then - prefix='feat!' - else - prefix='chore' - fi - echo "::set-output name=message::$prefix: postinstall for dependabot template-oss PR" - - # This step will fail if template-oss has made any workflow updates. It is impossible - # for a workflow to update other workflows. In the case it does fail, we continue - # and then try to apply only a portion of the changes in the next step - - name: Push All Changes - if: steps.apply.outputs.changes - id: push - continue-on-error: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git commit -am "${{ steps.apply.outputs.message }}" - git push - - # If the previous step failed, then reset the commit and remove any workflow changes - # and attempt to commit and push again. This is helpful because we will have a commit - # with the correct prefix that we can then --amend with @npmcli/stafftools later. - - name: Push All Changes Except Workflows - if: steps.apply.outputs.changes && steps.push.outcome == 'failure' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git reset HEAD~ - git checkout HEAD -- .github/workflows/ - git clean -fd .github/workflows/ - git commit -am "${{ steps.apply.outputs.message }}" - git push - - # Check if all the necessary template-oss changes were applied. Since we continued - # on errors in one of the previous steps, this check will fail if our follow up - # only applied a portion of the changes and we need to followup manually. - # - # Note that this used to run `lint` and `postlint` but that will fail this action - # if we've also shipped any linting changes separate from template-oss. We do - # linting in another action, so we want to fail this one only if there are - # template-oss changes that could not be applied. - - name: Check Changes - if: steps.apply.outputs.changes - run: | - npm exec --offline ${{ steps.flags.outputs.workspace }} -- template-oss-check - - - name: Fail on Breaking Change - if: steps.apply.outputs.changes && startsWith(steps.apply.outputs.message, 'feat!') - run: | - echo "This PR has a breaking change. Run 'npx -p @npmcli/stafftools gh template-oss-fix'" - echo "for more information on how to fix this with a BREAKING CHANGE footer." - exit 1 diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml deleted file mode 100644 index a194b619..00000000 --- a/.github/workflows/pull-request.yml +++ /dev/null @@ -1,51 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -name: Pull Request - -on: - pull_request: - types: - - opened - - reopened - - edited - - synchronize - -jobs: - commitlint: - name: Lint Commits - if: github.repository_owner == 'npm' - runs-on: ubuntu-latest - defaults: - run: - shell: bash - steps: - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Install npm@latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --ignore-scripts --no-audit --no-fund - - name: Run Commitlint on Commits - id: commit - continue-on-error: true - run: | - npx --offline commitlint -V --from origin/${{ github.base_ref }} --to ${{ github.event.pull_request.head.sha }} - - name: Run Commitlint on PR Title - if: steps.commit.outcome == 'failure' - run: | - echo ${{ github.event.pull_request.title }} | npx --offline commitlint -V diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index e95ae8c6..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,308 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -name: Release - -on: - workflow_dispatch: - push: - branches: - - main - - latest - - release/v* - -permissions: - contents: write - pull-requests: write - checks: write - -jobs: - release: - outputs: - pr: ${{ steps.release.outputs.pr }} - releases: ${{ steps.release.outputs.releases }} - release-flags: ${{ steps.release.outputs.release-flags }} - branch: ${{ steps.release.outputs.pr-branch }} - pr-number: ${{ steps.release.outputs.pr-number }} - comment-id: ${{ steps.pr-comment.outputs.result }} - check-id: ${{ steps.check.outputs.check_id }} - name: Release - if: github.repository_owner == 'npm' - runs-on: ubuntu-latest - defaults: - run: - shell: bash - steps: - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Install npm@latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --ignore-scripts --no-audit --no-fund - - name: Release Please - id: release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - npx --offline template-oss-release-please ${{ github.ref_name }} ${{ github.event_name }} - - name: Post Pull Request Comment - if: steps.release.outputs.pr-number - uses: actions/github-script@v6 - id: pr-comment - env: - PR_NUMBER: ${{ steps.release.outputs.pr-number }} - REF_NAME: ${{ github.ref_name }} - with: - script: | - const { REF_NAME, PR_NUMBER } = process.env - const repo = { owner: context.repo.owner, repo: context.repo.repo } - const issue = { ...repo, issue_number: PR_NUMBER } - - const { data: workflow } = await github.rest.actions.getWorkflowRun({ ...repo, run_id: context.runId }) - - let body = '## Release Manager\n\n' - - const comments = await github.paginate(github.rest.issues.listComments, issue) - let commentId = comments?.find(c => c.user.login === 'github-actions[bot]' && c.body.startsWith(body))?.id - - body += `Release workflow run: ${workflow.html_url}\n\n#### Force CI to Update This Release\n\n` - body += `This PR will be updated and CI will run for every non-\`chore:\` commit that is pushed to \`main\`. ` - body += `To force CI to update this PR, run this command:\n\n` - body += `\`\`\`\ngh workflow run release.yml -r ${REF_NAME}\n\`\`\`` - - if (commentId) { - await github.rest.issues.updateComment({ ...repo, comment_id: commentId, body }) - } else { - const { data: comment } = await github.rest.issues.createComment({ ...issue, body }) - commentId = comment?.id - } - - return commentId - - name: Get Workflow Job - uses: actions/github-script@v6 - if: steps.release.outputs.pr-sha - id: check-output - env: - JOB_NAME: "Release" - MATRIX_NAME: "" - with: - script: | - const { owner, repo } = context.repo - - const { data } = await github.rest.actions.listJobsForWorkflowRun({ - owner, - repo, - run_id: context.runId, - per_page: 100 - }) - - const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME - const job = data.jobs.find(j => j.name.endsWith(jobName)) - const jobUrl = job?.html_url - - const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ steps.release.outputs.pr-sha }}` - - let summary = `This check is assosciated with ${shaUrl}\n\n` - - if (jobUrl) { - summary += `For run logs, click here: ${jobUrl}` - } else { - summary += `Run logs could not be found for a job with name: "${jobName}"` - } - - return { summary } - - name: Create Check - uses: LouisBrunner/checks-action@v1.3.1 - id: check - if: steps.release.outputs.pr-sha - with: - token: ${{ secrets.GITHUB_TOKEN }} - status: in_progress - name: Release - sha: ${{ steps.release.outputs.pr-sha }} - output: ${{ steps.check-output.outputs.result }} - - update: - needs: release - outputs: - sha: ${{ steps.commit.outputs.sha }} - check-id: ${{ steps.check.outputs.check_id }} - name: Update - Release - if: github.repository_owner == 'npm' && needs.release.outputs.pr - runs-on: ubuntu-latest - defaults: - run: - shell: bash - steps: - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - ref: ${{ needs.release.outputs.branch }} - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Install npm@latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --ignore-scripts --no-audit --no-fund - - name: Run Post Pull Request Actions - env: - RELEASE_PR_NUMBER: ${{ needs.release.outputs.pr-number }} - RELEASE_COMMENT_ID: ${{ needs.release.outputs.comment-id }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - npm exec --offline -- template-oss-release-manager --lockfile=false - npm run rp-pull-request --ignore-scripts --if-present - - name: Commit - id: commit - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git commit --all --amend --no-edit || true - git push --force-with-lease - echo "::set-output name=sha::$(git rev-parse HEAD)" - - name: Get Workflow Job - uses: actions/github-script@v6 - if: steps.commit.outputs.sha - id: check-output - env: - JOB_NAME: "Update - Release" - MATRIX_NAME: "" - with: - script: | - const { owner, repo } = context.repo - - const { data } = await github.rest.actions.listJobsForWorkflowRun({ - owner, - repo, - run_id: context.runId, - per_page: 100 - }) - - const jobName = process.env.JOB_NAME + process.env.MATRIX_NAME - const job = data.jobs.find(j => j.name.endsWith(jobName)) - const jobUrl = job?.html_url - - const shaUrl = `${context.serverUrl}/${owner}/${repo}/commit/${{ steps.commit.outputs.sha }}` - - let summary = `This check is assosciated with ${shaUrl}\n\n` - - if (jobUrl) { - summary += `For run logs, click here: ${jobUrl}` - } else { - summary += `Run logs could not be found for a job with name: "${jobName}"` - } - - return { summary } - - name: Create Check - uses: LouisBrunner/checks-action@v1.3.1 - id: check - if: steps.commit.outputs.sha - with: - token: ${{ secrets.GITHUB_TOKEN }} - status: in_progress - name: Release - sha: ${{ steps.commit.outputs.sha }} - output: ${{ steps.check-output.outputs.result }} - - name: Conclude Check - uses: LouisBrunner/checks-action@v1.3.1 - if: needs.release.outputs.check-id && always() - with: - token: ${{ secrets.GITHUB_TOKEN }} - conclusion: ${{ job.status }} - check_id: ${{ needs.release.outputs.check-id }} - - ci: - name: CI - Release - needs: [ release, update ] - if: needs.release.outputs.pr - uses: ./.github/workflows/ci-release.yml - with: - ref: ${{ needs.release.outputs.branch }} - check-sha: ${{ needs.update.outputs.sha }} - - post-ci: - needs: [ release, update, ci ] - name: Post CI - Release - if: github.repository_owner == 'npm' && needs.release.outputs.pr && always() - runs-on: ubuntu-latest - defaults: - run: - shell: bash - steps: - - name: Get Needs Result - id: needs-result - run: | - result="" - if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then - result="failure" - elif [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then - result="cancelled" - else - result="success" - fi - echo "::set-output name=result::$result" - - name: Conclude Check - uses: LouisBrunner/checks-action@v1.3.1 - if: needs.update.outputs.check-id && always() - with: - token: ${{ secrets.GITHUB_TOKEN }} - conclusion: ${{ steps.needs-result.outputs.result }} - check_id: ${{ needs.update.outputs.check-id }} - - post-release: - needs: release - name: Post Release - Release - if: github.repository_owner == 'npm' && needs.release.outputs.releases - runs-on: ubuntu-latest - defaults: - run: - shell: bash - steps: - - name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Install npm@latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --ignore-scripts --no-audit --no-fund - - name: Run Post Release Actions - env: - RELEASES: ${{ needs.release.outputs.releases }} - run: | - npm run rp-release --ignore-scripts --if-present ${{ join(fromJSON(needs.release.outputs.release-flags), ' ') }} From e483220935d931cf6b09292aba62170e68f36205 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Mon, 4 Sep 2023 22:31:31 -0700 Subject: [PATCH 53/96] get rid of npm lint stuff Will replace with prettier at some point, but for now, whatever. --- package.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/package.json b/package.json index f59f54ae..2afdc1a9 100644 --- a/package.json +++ b/package.json @@ -9,13 +9,8 @@ }, "scripts": { "genparse": "node scripts/generate-parse-fixtures.js", - "template-oss-apply": "template-oss-apply --force", - "lint": "eslint \"**/*.js\"", - "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", "snap": "tap", - "test": "tap", - "posttest": "npm run lint" + "test": "tap" }, "dependencies": { "chownr": "^2.0.0", From fe1ef5ec87156ddadcec8b70cdec201f26665681 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Mon, 4 Sep 2023 22:33:15 -0700 Subject: [PATCH 54/96] changelog 6.2 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ee82011..f4b27a7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 6.2 + +* Add support for brotli compression + ## [6.1.13](https://github.com/npm/node-tar/compare/v6.1.12...v6.1.13) (2022-12-07) ### Dependencies From 5bc9d404e88c39870e0fbb55655a53de6fbf0a04 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Mon, 4 Sep 2023 22:33:20 -0700 Subject: [PATCH 55/96] 6.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2afdc1a9..46d91ee1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "6.1.15", + "version": "6.2.0", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From fe7ebfdcede1f8a2e65db12e19ecc4b3a9934648 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Mon, 12 Feb 2024 10:58:12 -0800 Subject: [PATCH 56/96] remove security.md Fix: https://github.com/isaacs/node-tar/security/advisories/GHSA-hr8v-f3j8-8w2m --- SECURITY.md | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 4e7c26c6..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,14 +0,0 @@ -<!-- This file is automatically added by @npmcli/template-oss. Do not edit. --> - -GitHub takes the security of our software products and services seriously, including the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub). - -If you believe you have found a security vulnerability in this GitHub-owned open source repository, you can report it to us in one of two ways. - -If the vulnerability you have found is *not* [in scope for the GitHub Bug Bounty Program](https://bounty.github.com/#scope) or if you do not wish to be considered for a bounty reward, please report the issue to us directly using [private vulnerability reporting](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability). - -If the vulnerability you have found is [in scope for the GitHub Bug Bounty Program](https://bounty.github.com/#scope) and you would like for your finding to be considered for a bounty reward, please submit the vulnerability to us through [HackerOne](https://hackerone.com/github) in order to be eligible to receive a bounty award. - -**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** - -Thanks for helping make GitHub safe for everyone. - From fe8cd57da5686f8695415414bda49206a545f7f7 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Fri, 15 Mar 2024 22:50:56 -0700 Subject: [PATCH 57/96] prevent extraction in excessively deep subfolders This sets the limit at 1024 subfolders nesting by default, but that can be dropped down, or set to Infinity to remove the limitation. --- README.md | 10 +++++ lib/unpack.js | 27 ++++++++++--- test/fixtures/excessively-deep.tar | Bin 0 -> 450560 bytes test/parse.js | 2 +- test/unpack.js | 61 +++++++++++++++++++++++++++++ 5 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 test/fixtures/excessively-deep.tar diff --git a/README.md b/README.md index 7cb09da6..f620568e 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,8 @@ Handlers receive 3 arguments: encountered an error which prevented it from being unpacked. This occurs when: - an unrecoverable fs error happens during unpacking, + - an entry is trying to extract into an excessively deep + location (by default, limited to 1024 subfolders), - an entry has `..` in the path and `preservePaths` is not set, or - an entry is extracting through a symbolic link, when `preservePaths` is not set. @@ -427,6 +429,10 @@ The following options are supported: `process.umask()` to determine the default umask value, since tar will extract with whatever mode is provided, and let the process `umask` apply normally. +- `maxDepth` The maximum depth of subfolders to extract into. This + defaults to 1024. Anything deeper than the limit will raise a + warning and skip the entry. Set to `Infinity` to remove the + limitation. The following options are mostly internal, but can be modified in some advanced use cases, such as re-using caches between runs. @@ -749,6 +755,10 @@ Most unpack errors will cause a `warn` event to be emitted. If the `process.umask()` to determine the default umask value, since tar will extract with whatever mode is provided, and let the process `umask` apply normally. +- `maxDepth` The maximum depth of subfolders to extract into. This + defaults to 1024. Anything deeper than the limit will raise a + warning and skip the entry. Set to `Infinity` to remove the + limitation. ### class tar.Unpack.Sync diff --git a/lib/unpack.js b/lib/unpack.js index fa46611c..03172e2c 100644 --- a/lib/unpack.js +++ b/lib/unpack.js @@ -48,6 +48,7 @@ const crypto = require('crypto') const getFlag = require('./get-write-flag.js') const platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform const isWindows = platform === 'win32' +const DEFAULT_MAX_DEPTH = 1024 // Unlinks on Windows are not atomic. // @@ -181,6 +182,12 @@ class Unpack extends Parser { this.processGid = (this.preserveOwner || this.setOwner) && process.getgid ? process.getgid() : null + // prevent excessively deep nesting of subfolders + // set to `Infinity` to remove this restriction + this.maxDepth = typeof opt.maxDepth === 'number' + ? opt.maxDepth + : DEFAULT_MAX_DEPTH + // mostly just for testing, but useful in some cases. // Forcibly trigger a chown on every entry, no matter what this.forceChown = opt.forceChown === true @@ -238,13 +245,13 @@ class Unpack extends Parser { } [CHECKPATH] (entry) { + const p = normPath(entry.path) + const parts = p.split('/') + if (this.strip) { - const parts = normPath(entry.path).split('/') if (parts.length < this.strip) { return false } - entry.path = parts.slice(this.strip).join('/') - if (entry.type === 'Link') { const linkparts = normPath(entry.linkpath).split('/') if (linkparts.length >= this.strip) { @@ -253,11 +260,21 @@ class Unpack extends Parser { return false } } + parts.splice(0, this.strip) + entry.path = parts.join('/') + } + + if (isFinite(this.maxDepth) && parts.length > this.maxDepth) { + this.warn('TAR_ENTRY_ERROR', 'path excessively deep', { + entry, + path: p, + depth: parts.length, + maxDepth: this.maxDepth, + }) + return false } if (!this.preservePaths) { - const p = normPath(entry.path) - const parts = p.split('/') if (parts.includes('..') || isWindows && /^[a-z]:\.\.$/i.test(parts[0])) { this.warn('TAR_ENTRY_ERROR', `path contains '..'`, { entry, diff --git a/test/fixtures/excessively-deep.tar b/test/fixtures/excessively-deep.tar new file mode 100644 index 0000000000000000000000000000000000000000..e42aa3dab63338cf5036d99426efae716c42b892 GIT binary patch literal 450560 zcmeIwF>1pw6b4|;IfYN)NV05AfsP$}1w&KXA*3WO<oH!6T|&nug!cPAJS+*l$A|iL zzkYa{PmkOAd3y*~N&HIqsiv`%aVp<?=OZDem`e=Z=_=D)T>5cb=0j_LvHV|tODT2A z-TS<}Zu<4?BS3%v0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK;TaayzKY=a#~h->UPW9Zo5e})|iK}ls*qBmQ}c; z^f$1NEmJAsTw5+{TN*+t<5;IO<=Xc1P-_ZZyoJ-pahVToq+9g5!yfIm-r-b6B0zuu V0RjXF5FkK+009C72oU%!flp(o{=)zO literal 0 HcmV?d00001 diff --git a/test/parse.js b/test/parse.js index 549b3701..2cc68782 100644 --- a/test/parse.js +++ b/test/parse.js @@ -646,7 +646,7 @@ t.test('truncated gzip input', t => { p.write(tgz.slice(split)) p.end() t.equal(aborted, true, 'aborted writing') - t.same(warnings, ['zlib: incorrect data check']) + t.match(warnings, [/^zlib: /]) t.end() }) diff --git a/test/unpack.js b/test/unpack.js index 399ae0e6..2f1d3026 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -22,6 +22,7 @@ const mkdirp = require('mkdirp') const mutateFS = require('mutate-fs') const eos = require('end-of-stream') const normPath = require('../lib/normalize-windows-path.js') +const ReadEntry = require('../lib/read-entry.js') // On Windows in particular, the "really deep folder path" file // often tends to cause problems, which don't indicate a failure @@ -3235,3 +3236,63 @@ t.test('recognize C:.. as a dot path part', t => { t.end() }) + +t.test('excessively deep subfolder nesting', async t => { + const tf = path.resolve(fixtures, 'excessively-deep.tar') + const data = fs.readFileSync(tf) + const warnings = [] + const onwarn = (c, w, { entry, path, depth, maxDepth }) => + warnings.push([c, w, { entry, path, depth, maxDepth }]) + + const check = (t, maxDepth = 1024) => { + t.match(warnings, [ + ['TAR_ENTRY_ERROR', + 'path excessively deep', + { + entry: ReadEntry, + path: /^\.(\/a){1024,}\/foo.txt$/, + depth: 222372, + maxDepth, + } + ] + ]) + warnings.length = 0 + t.end() + } + + t.test('async', t => { + const cwd = t.testdir() + new Unpack({ + cwd, + onwarn + }).on('end', () => check(t)).end(data) + }) + + t.test('sync', t => { + const cwd = t.testdir() + new UnpackSync({ + cwd, + onwarn + }).end(data) + check(t) + }) + + t.test('async set md', t => { + const cwd = t.testdir() + new Unpack({ + cwd, + onwarn, + maxDepth: 64, + }).on('end', () => check(t, 64)).end(data) + }) + + t.test('sync set md', t => { + const cwd = t.testdir() + new UnpackSync({ + cwd, + onwarn, + maxDepth: 64, + }).end(data) + check(t, 64) + }) +}) From bef7b1e4ffab822681fea2a9b22187192ed14717 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Thu, 21 Mar 2024 14:12:18 -0700 Subject: [PATCH 58/96] 6.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 46d91ee1..f84a41cc 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "6.2.0", + "version": "6.2.1", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From 0510c9ea6d000c40446d56674a7efeec8e72f052 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Thu, 21 Mar 2024 16:39:47 -0700 Subject: [PATCH 59/96] do not CI on windows, can't handle the long paths --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d026a49f..1e477a87 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,10 +12,6 @@ jobs: shell: bash - os: macos-latest shell: bash - - os: windows-latest - shell: bash - - os: windows-latest - shell: powershell fail-fast: false runs-on: ${{ matrix.platform.os }} From 114c7ac4c24441cbe13de4aa46a864d46676c6bc Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Mon, 8 Apr 2024 15:34:14 -0700 Subject: [PATCH 60/96] first pass TS refactor --- .github/workflows/typedoc.yml | 50 ++ .gitignore | 2 +- README.md | 1 + lib/path-reservations.js | 39 +- package.json | 233 +++++-- src/create.ts | 160 +++++ src/cwd-error.ts | 15 + src/extract.ts | 165 +++++ src/get-write-flag.ts | 29 + src/header.ts | 397 ++++++++++++ src/index.ts | 21 + src/large-numbers.ts | 98 +++ src/list.ts | 185 ++++++ src/mkdir.ts | 292 +++++++++ src/mode-fix.ts | 26 + src/normalize-unicode.ts | 12 + src/normalize-windows-path.ts | 12 + src/options.ts | 473 ++++++++++++++ src/pack.ts | 500 +++++++++++++++ src/parse.ts | 629 +++++++++++++++++++ src/path-reservations.ts | 192 ++++++ src/pax.ts | 181 ++++++ src/read-entry.ts | 151 +++++ src/replace.ts | 317 ++++++++++ src/strip-absolute-path.ts | 27 + src/strip-trailing-slashes.ts | 13 + src/symlink-error.ts | 14 + src/types.ts | 97 +++ src/unpack.ts | 1101 +++++++++++++++++++++++++++++++++ src/update.ts | 62 ++ src/warn-method.ts | 59 ++ src/winchars.ts | 16 + src/write-entry.ts | 733 ++++++++++++++++++++++ 33 files changed, 6248 insertions(+), 54 deletions(-) create mode 100644 .github/workflows/typedoc.yml create mode 100644 src/create.ts create mode 100644 src/cwd-error.ts create mode 100644 src/extract.ts create mode 100644 src/get-write-flag.ts create mode 100644 src/header.ts create mode 100644 src/index.ts create mode 100644 src/large-numbers.ts create mode 100644 src/list.ts create mode 100644 src/mkdir.ts create mode 100644 src/mode-fix.ts create mode 100644 src/normalize-unicode.ts create mode 100644 src/normalize-windows-path.ts create mode 100644 src/options.ts create mode 100644 src/pack.ts create mode 100644 src/parse.ts create mode 100644 src/path-reservations.ts create mode 100644 src/pax.ts create mode 100644 src/read-entry.ts create mode 100644 src/replace.ts create mode 100644 src/strip-absolute-path.ts create mode 100644 src/strip-trailing-slashes.ts create mode 100644 src/symlink-error.ts create mode 100644 src/types.ts create mode 100644 src/unpack.ts create mode 100644 src/update.ts create mode 100644 src/warn-method.ts create mode 100644 src/winchars.ts create mode 100644 src/write-entry.ts diff --git a/.github/workflows/typedoc.yml b/.github/workflows/typedoc.yml new file mode 100644 index 00000000..e5bc0ef8 --- /dev/null +++ b/.github/workflows/typedoc.yml @@ -0,0 +1,50 @@ +# Simple workflow for deploying static content to GitHub Pages +name: Deploy static content to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow one concurrent deployment +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + # Single deploy job since we're just deploying + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Use Nodejs ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: 18.x + - name: Install dependencies + run: npm install + - name: Generate typedocs + run: npm run typedoc + + - name: Setup Pages + uses: actions/configure-pages@v3 + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + path: './docs' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v1 diff --git a/.gitignore b/.gitignore index effd9b9a..44be827b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ # keep these !**/.gitignore +!/src !/.commitlintrc.js !/.eslintrc.js !/.eslintrc.local.* @@ -15,7 +16,6 @@ !/bin/ !/CHANGELOG* !/CODE_OF_CONDUCT.md -!/docs/ !/index.js !/lib/ !/LICENSE* diff --git a/README.md b/README.md index f620568e..296229c5 100644 --- a/README.md +++ b/README.md @@ -630,6 +630,7 @@ The following options are supported: default" for most unix systems, based on a `umask` value of `0o22`. - `preservePaths` Allow absolute paths. By default, `/` is stripped from absolute paths. + - `linkCache` A Map object containing the device and inode value for any file whose nlink is > 1, to identify hard links. - `statCache` A Map object that caches calls `lstat`. diff --git a/lib/path-reservations.js b/lib/path-reservations.js index 8d349d58..62890060 100644 --- a/lib/path-reservations.js +++ b/lib/path-reservations.js @@ -11,7 +11,8 @@ const normalize = require('./normalize-unicode.js') const stripSlashes = require('./strip-trailing-slashes.js') const { join } = require('path') -const platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform +const platform = + process.env.TESTING_TAR_FAKE_PLATFORM || process.platform const isWindows = platform === 'win32' module.exports = () => { @@ -26,13 +27,16 @@ module.exports = () => { // return a set of parent dirs for a given path // '/a/b/c/d' -> ['/', '/a', '/a/b', '/a/b/c', '/a/b/c/d'] const getDirs = path => { - const dirs = path.split('/').slice(0, -1).reduce((set, path) => { - if (set.length) { - path = join(set[set.length - 1], path) - } - set.push(path || '/') - return set - }, []) + const dirs = path + .split('/') + .slice(0, -1) + .reduce((set, path) => { + if (set.length) { + path = join(set[set.length - 1], path) + } + set.push(path || '/') + return set + }, []) return dirs } @@ -57,8 +61,10 @@ module.exports = () => { // included in the first set for all its dir queues const check = fn => { const { paths, dirs } = getQueues(fn) - return paths.every(q => q[0] === fn) && - dirs.every(q => q[0] instanceof Set && q[0].has(fn)) + return ( + paths.every(q => q && q[0] === fn) && + dirs.every(q => q && q[0] instanceof Set && q[0].has(fn)) + ) } // run the function if it's first in line and not already running @@ -102,7 +108,6 @@ module.exports = () => { } else if (q[0].size === 1) { q.shift() - // must be a function or else the Set would've been reused next.add(q[0]) } else { q[0].delete(fn) @@ -121,13 +126,15 @@ module.exports = () => { // disk, without asking the kernel for a shortname. // So, we just pretend that every path matches every other path here, // effectively removing all parallelization on windows. - paths = isWindows ? ['win32 parallelization disabled'] : paths.map(p => { - // don't need normPath, because we skip this entirely for windows - return stripSlashes(join(normalize(p))).toLowerCase() - }) + paths = isWindows + ? ['win32 parallelization disabled'] + : paths.map(p => { + // don't need normPath, because we skip this entirely for windows + return stripSlashes(join(normalize(p))).toLowerCase() + }) const dirs = new Set( - paths.map(path => getDirs(path)).reduce((a, b) => a.concat(b)) + paths.map(path => getDirs(path)).reduce((a, b) => a.concat(b)), ) reservations.set(fn, { dirs, paths }) paths.forEach(path => { diff --git a/package.json b/package.json index f84a41cc..7cfcb4f5 100644 --- a/package.json +++ b/package.json @@ -10,61 +10,220 @@ "scripts": { "genparse": "node scripts/generate-parse-fixtures.js", "snap": "tap", - "test": "tap" + "test": "tap", + "pretest": "npm run prepare", + "presnap": "npm run prepare", + "prepare": "tshy", + "preversion": "npm test", + "postversion": "npm publish", + "prepublishOnly": "git push origin --follow-tags", + "format": "prettier --write . --loglevel warn", + "typedoc": "typedoc --tsconfig .tshy/esm.json ./src/*.ts" }, "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1" }, "devDependencies": { - "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.11.0", "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", "events-to-array": "^2.0.3", "mutate-fs": "^2.1.1", "nock": "^13.2.9", + "prettier": "^3.2.5", "rimraf": "^3.0.2", - "tap": "^16.0.1" + "tap": "^16.0.1", + "tshy": "^1.13.1", + "typedoc": "^0.25.13" }, "license": "ISC", "engines": { - "node": ">=10" + "node": ">=18" }, "files": [ - "bin/", - "lib/", - "index.js" + "dist" ], "tap": { "coverage-map": "map.js", - "timeout": 0, - "nyc-arg": [ - "--exclude", - "tap-snapshots/**" - ] + "timeout": 0 }, - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.11.0", - "content": "scripts/template-oss", - "engines": ">=10", - "distPaths": [ - "index.js" - ], - "allowPaths": [ - "/index.js" - ], - "ciVersions": [ - "10.x", - "12.x", - "14.x", - "16.x", - "18.x" - ] - } + "prettier": { + "semi": false, + "printWidth": 70, + "tabWidth": 2, + "useTabs": false, + "singleQuote": true, + "jsxSingleQuote": false, + "bracketSameLine": true, + "arrowParens": "avoid", + "endOfLine": "lf" + }, + "tshy": { + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./create": "./src/create.ts", + "./replace": "./src/create.ts", + "./list": "./src/list.ts", + "./update": "./src/update.ts", + "./extract": "./src/extract.ts", + "./pack": "./src/pack.ts", + "./unpack": "./src/unpack.ts", + "./parse": "./src/parse.ts", + "./read-entry": "./src/read-entry.ts", + "./write-entry": "./src/write-entry.ts", + "./header": "./src/header.ts", + "./pax": "./src/pax.ts", + "./types": "./src/types.ts" + } + }, + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/commonjs/index.d.ts", + "default": "./dist/commonjs/index.js" + } + }, + "./create": { + "import": { + "types": "./dist/esm/create.d.ts", + "default": "./dist/esm/create.js" + }, + "require": { + "types": "./dist/commonjs/create.d.ts", + "default": "./dist/commonjs/create.js" + } + }, + "./replace": { + "import": { + "types": "./dist/esm/create.d.ts", + "default": "./dist/esm/create.js" + }, + "require": { + "types": "./dist/commonjs/create.d.ts", + "default": "./dist/commonjs/create.js" + } + }, + "./list": { + "import": { + "types": "./dist/esm/list.d.ts", + "default": "./dist/esm/list.js" + }, + "require": { + "types": "./dist/commonjs/list.d.ts", + "default": "./dist/commonjs/list.js" + } + }, + "./update": { + "import": { + "types": "./dist/esm/update.d.ts", + "default": "./dist/esm/update.js" + }, + "require": { + "types": "./dist/commonjs/update.d.ts", + "default": "./dist/commonjs/update.js" + } + }, + "./extract": { + "import": { + "types": "./dist/esm/extract.d.ts", + "default": "./dist/esm/extract.js" + }, + "require": { + "types": "./dist/commonjs/extract.d.ts", + "default": "./dist/commonjs/extract.js" + } + }, + "./pack": { + "import": { + "types": "./dist/esm/pack.d.ts", + "default": "./dist/esm/pack.js" + }, + "require": { + "types": "./dist/commonjs/pack.d.ts", + "default": "./dist/commonjs/pack.js" + } + }, + "./unpack": { + "import": { + "types": "./dist/esm/unpack.d.ts", + "default": "./dist/esm/unpack.js" + }, + "require": { + "types": "./dist/commonjs/unpack.d.ts", + "default": "./dist/commonjs/unpack.js" + } + }, + "./parse": { + "import": { + "types": "./dist/esm/parse.d.ts", + "default": "./dist/esm/parse.js" + }, + "require": { + "types": "./dist/commonjs/parse.d.ts", + "default": "./dist/commonjs/parse.js" + } + }, + "./read-entry": { + "import": { + "types": "./dist/esm/read-entry.d.ts", + "default": "./dist/esm/read-entry.js" + }, + "require": { + "types": "./dist/commonjs/read-entry.d.ts", + "default": "./dist/commonjs/read-entry.js" + } + }, + "./write-entry": { + "import": { + "types": "./dist/esm/write-entry.d.ts", + "default": "./dist/esm/write-entry.js" + }, + "require": { + "types": "./dist/commonjs/write-entry.d.ts", + "default": "./dist/commonjs/write-entry.js" + } + }, + "./header": { + "import": { + "types": "./dist/esm/header.d.ts", + "default": "./dist/esm/header.js" + }, + "require": { + "types": "./dist/commonjs/header.d.ts", + "default": "./dist/commonjs/header.js" + } + }, + "./pax": { + "import": { + "types": "./dist/esm/pax.d.ts", + "default": "./dist/esm/pax.js" + }, + "require": { + "types": "./dist/commonjs/pax.d.ts", + "default": "./dist/commonjs/pax.js" + } + }, + "./types": { + "import": { + "types": "./dist/esm/types.d.ts", + "default": "./dist/esm/types.js" + }, + "require": { + "types": "./dist/commonjs/types.d.ts", + "default": "./dist/commonjs/types.js" + } + } + }, + "type": "module", + "main": "./dist/commonjs/index.js", + "types": "./dist/commonjs/index.d.ts" } diff --git a/src/create.ts b/src/create.ts new file mode 100644 index 00000000..b97eb2e8 --- /dev/null +++ b/src/create.ts @@ -0,0 +1,160 @@ +import { + dealias, + isFile, + isSync, + isSyncFile, + TarOptions, + TarOptionsFile, + TarOptionsSync, + TarOptionsSyncFile, + TarOptionsWithAliases, + TarOptionsWithAliasesFile, + TarOptionsWithAliasesSync, + TarOptionsWithAliasesSyncFile, +} from './options.js' + +import { WriteStream, WriteStreamSync } from '@isaacs/fs-minipass' +import { Minipass } from 'minipass' +import path from 'node:path' +import { list } from './list.js' +import { Pack, PackSync } from './pack.js' + +export function create( + opt: TarOptionsWithAliasesSyncFile, + files?: string[], +): void +export function create( + opt: TarOptionsWithAliasesSync, + files?: string[], +): void +export function create( + opt: TarOptionsWithAliasesFile, + files?: string[], + cb?: () => any, +): Promise<void> +export function create( + opt: TarOptionsWithAliasesFile, + cb: () => any, +): Promise<void> +export function create( + opt: TarOptionsWithAliases, + files?: string[], +): Pack +export function create( + opt_: TarOptionsWithAliases, + files?: string[] | (() => any), + cb?: () => any, +): void | Promise<void> | Pack { + if (typeof files === 'function') { + cb = files + } + + if (Array.isArray(opt_)) { + ;(files = opt_), (opt_ = {}) + } + + if (!files || !Array.isArray(files) || !files.length) { + throw new TypeError('no files or directories specified') + } + + files = Array.from(files) + + const opt = dealias(opt_) + + if (opt.sync && typeof cb === 'function') { + throw new TypeError( + 'callback not supported for sync tar functions', + ) + } + + if (!opt.file && typeof cb === 'function') { + throw new TypeError('callback only supported with file option') + } + + return isSyncFile(opt) + ? createFileSync(opt, files) + : isFile(opt) + ? createFile(opt, files, cb) + : isSync(opt) + ? createSync(opt, files) + : create_(opt, files) +} + +const createFileSync = (opt: TarOptionsSyncFile, files: string[]) => { + const p = new PackSync(opt) + const stream = new WriteStreamSync(opt.file, { + mode: opt.mode || 0o666, + }) + p.pipe(stream as unknown as Minipass.Writable) + addFilesSync(p, files) +} + +const createFile = ( + opt: TarOptionsFile, + files: string[], + cb?: () => any, +) => { + const p = new Pack(opt) + const stream = new WriteStream(opt.file, { + mode: opt.mode || 0o666, + }) + p.pipe(stream as unknown as Minipass.Writable) + + const promise = new Promise<void>((res, rej) => { + stream.on('error', rej) + stream.on('close', res) + p.on('error', rej) + }) + + addFilesAsync(p, files) + + return cb ? promise.then(cb, cb) : promise +} + +const addFilesSync = (p: PackSync, files: string[]) => { + files.forEach(file => { + if (file.charAt(0) === '@') { + list({ + file: path.resolve(p.cwd, file.slice(1)), + sync: true, + noResume: true, + onentry: entry => p.add(entry), + }) + } else { + p.add(file) + } + }) + p.end() +} + +const addFilesAsync = async ( + p: Pack, + files: string[], + i = 0, +): Promise<void> => { + for (; i < files.length; i++) { + const file = String(files[i]) + if (file.charAt(0) === '@') { + return list({ + file: path.resolve(String(p.cwd), file.slice(1)), + noResume: true, + onentry: entry => p.add(entry), + }).then(_ => addFilesAsync(p, files)) + } else { + p.add(file) + } + } + p.end() +} + +const createSync = (opt: TarOptionsSync, files: string[]) => { + const p = new PackSync(opt) + addFilesSync(p, files) + return p +} + +const create_ = (opt: TarOptions, files: string[]) => { + const p = new Pack(opt) + addFilesAsync(p, files) + return p +} diff --git a/src/cwd-error.ts b/src/cwd-error.ts new file mode 100644 index 00000000..7a708ed4 --- /dev/null +++ b/src/cwd-error.ts @@ -0,0 +1,15 @@ +export class CwdError extends Error { + path: string + code: string + syscall: 'chdir' = 'chdir' + + constructor(path: string, code: string) { + super(code + ": Cannot cd into '" + path + "'") + this.path = path + this.code = code + } + + get name() { + return 'CwdError' + } +} diff --git a/src/extract.ts b/src/extract.ts new file mode 100644 index 00000000..f79f9408 --- /dev/null +++ b/src/extract.ts @@ -0,0 +1,165 @@ +// tar -x +import * as fsm from '@isaacs/fs-minipass' +import fs from 'node:fs' +import { dirname, parse } from 'node:path' +import { + dealias, + isFile, + isSync, + isSyncFile, + TarOptions, + TarOptionsFile, + TarOptionsSync, + TarOptionsSyncFile, + TarOptionsWithAliases, + TarOptionsWithAliasesFile, + TarOptionsWithAliasesSync, + TarOptionsWithAliasesSyncFile, +} from './options.js' +import { stripTrailingSlashes } from './strip-trailing-slashes.js' +import { Unpack, UnpackSync } from './unpack.js' + +export function extract( + opt: TarOptionsWithAliasesSyncFile, + files?: string[], +): void +export function extract( + opt: TarOptionsWithAliasesSync, + files?: string[], +): void +export function extract( + opt: TarOptionsWithAliasesFile, + files?: string[], + cb?: () => any, +): Promise<void> +export function extract( + opt: TarOptionsWithAliasesFile, + cb: () => any, +): Promise<void> +export function extract( + opt: TarOptionsWithAliases, + files?: string[], +): Unpack +export function extract( + opt_: TarOptionsWithAliases, + files?: string[] | (() => any), + cb?: () => any, +): void | Promise<void> | Unpack { + if (typeof opt_ === 'function') { + ;(cb = opt_), (files = undefined), (opt_ = {}) + } else if (Array.isArray(opt_)) { + ;(files = opt_), (opt_ = {}) + } + + if (typeof files === 'function') { + ;(cb = files), (files = undefined) + } + + if (!files) { + files = [] + } else { + files = Array.from(files) + } + + const opt = dealias(opt_) + + if (opt.sync && typeof cb === 'function') { + throw new TypeError( + 'callback not supported for sync tar functions', + ) + } + + if (!opt.file && typeof cb === 'function') { + throw new TypeError('callback only supported with file option') + } + + if (files.length) { + filesFilter(opt, files) + } + + return isSyncFile(opt) + ? extractFileSync(opt) + : isFile(opt) + ? extractFile(opt, cb) + : isSync(opt) + ? extractSync(opt) + : extract_(opt) +} + +// construct a filter that limits the file entries listed +// include child entries if a dir is included +const filesFilter = (opt: TarOptions, files: string[]) => { + const map = new Map(files.map(f => [stripTrailingSlashes(f), true])) + const filter = opt.filter + + const mapHas = (file: string, r: string = ''): boolean => { + const root = r || parse(file).root || '.' + let ret: boolean + if (file === root) ret = false + else { + const m = map.get(file) + if (m !== undefined) { + ret = m + } else { + ret = mapHas(dirname(file), root) + } + } + + map.set(file, ret) + return ret + } + + opt.filter = filter + ? (file, entry) => + filter(file, entry) && mapHas(stripTrailingSlashes(file)) + : file => mapHas(stripTrailingSlashes(file)) +} + +const extractFileSync = (opt: TarOptionsSyncFile) => { + const u = new UnpackSync(opt) + + const file = opt.file + const stat = fs.statSync(file) + // This trades a zero-byte read() syscall for a stat + // However, it will usually result in less memory allocation + const readSize = opt.maxReadSize || 16 * 1024 * 1024 + const stream = new fsm.ReadStreamSync(file, { + readSize: readSize, + size: stat.size, + }) + stream.pipe(u) +} + +const extractFile = ( + opt: TarOptionsFile, + cb: () => void = () => {}, +) => { + const u = new Unpack(opt) + const readSize = opt.maxReadSize || 16 * 1024 * 1024 + + const file = opt.file + const p = new Promise<void>((resolve, reject) => { + u.on('error', reject) + u.on('close', resolve) + + // This trades a zero-byte read() syscall for a stat + // However, it will usually result in less memory allocation + fs.stat(file, (er, stat) => { + if (er) { + reject(er) + } else { + const stream = new fsm.ReadStream(file, { + readSize: readSize, + size: stat.size, + }) + stream.on('error', reject) + stream.pipe(u) + } + }) + }) + return cb ? p.then(cb, cb) : p +} + +const extractSync = (opt: TarOptionsSync) => new UnpackSync(opt) + +const extract_ = (opt: TarOptions) => new Unpack(opt) diff --git a/src/get-write-flag.ts b/src/get-write-flag.ts new file mode 100644 index 00000000..db358591 --- /dev/null +++ b/src/get-write-flag.ts @@ -0,0 +1,29 @@ +// Get the appropriate flag to use for creating files +// We use fmap on Windows platforms for files less than +// 512kb. This is a fairly low limit, but avoids making +// things slower in some cases. Since most of what this +// library is used for is extracting tarballs of many +// relatively small files in npm packages and the like, +// it can be a big boost on Windows platforms. +// Only supported in Node v12.9.0 and above. +const platform = process.env.__FAKE_PLATFORM__ || process.platform +const isWindows = platform === 'win32' +const g = globalThis as typeof globalThis & { + __FAKE_TESTING_FS__: typeof import('fs') +} +const fs = g.__FAKE_TESTING_FS__ || require('fs') + +/* istanbul ignore next */ +const { + O_CREAT, + O_TRUNC, + O_WRONLY, + UV_FS_O_FILEMAP = 0, +} = fs.constants + +const fMapEnabled = isWindows && !!UV_FS_O_FILEMAP +const fMapLimit = 512 * 1024 +const fMapFlag = UV_FS_O_FILEMAP | O_TRUNC | O_CREAT | O_WRONLY +export const getWriteFlag = !fMapEnabled + ? () => 'w' + : (size: number) => (size < fMapLimit ? fMapFlag : 'w') diff --git a/src/header.ts b/src/header.ts new file mode 100644 index 00000000..b9efbda6 --- /dev/null +++ b/src/header.ts @@ -0,0 +1,397 @@ +// parse a 512-byte header block to a data object, or vice-versa +// encode returns `true` if a pax extended header is needed, because +// the data could not be faithfully encoded in a simple header. +// (Also, check header.needPax to see if it needs a pax header.) + +import { posix as pathModule } from 'node:path' +import * as large from './large-numbers.js' +import type { EntryTypeCode, EntryTypeName } from './types.js' +import * as types from './types.js' + +export type HeaderData = { + path?: string + mode?: number + uid?: number + gid?: number + size?: number + cksum?: number + type?: EntryTypeCode | EntryTypeName + linkpath?: string + uname?: string + gname?: string + devmaj?: number + devmin?: number + atime?: Date + ctime?: Date + mtime?: Date + + // fields that are common in extended PAX headers, but not in the + // "standard" tar header block + charset?: string + comment?: string + dev?: number + ino?: number + nlink?: number +} + +export class Header implements HeaderData { + cksumValid: boolean = false + needPax: boolean = false + nullBlock: boolean = false + + block?: Buffer + path?: string + mode?: number + uid?: number + gid?: number + size?: number + cksum?: number + #type: EntryTypeCode = '0' + linkpath?: string + uname?: string + gname?: string + devmaj: number = 0 + devmin: number = 0 + atime?: Date + ctime?: Date + mtime?: Date + + charset?: string + comment?: string + + constructor( + data?: Buffer | HeaderData, + off: number = 0, + ex?: HeaderData, + gex?: HeaderData, + ) { + if (Buffer.isBuffer(data)) { + this.decode(data, off || 0, ex, gex) + } else if (data) { + this.#slurp(data) + } + } + + decode( + buf: Buffer, + off: number, + ex?: HeaderData, + gex?: HeaderData, + ) { + if (!off) { + off = 0 + } + + if (!buf || !(buf.length >= off + 512)) { + throw new Error('need 512 bytes for header') + } + + this.path = decString(buf, off, 100) + this.mode = decNumber(buf, off + 100, 8) + this.uid = decNumber(buf, off + 108, 8) + this.gid = decNumber(buf, off + 116, 8) + this.size = decNumber(buf, off + 124, 12) + this.mtime = decDate(buf, off + 136, 12) + this.cksum = decNumber(buf, off + 148, 12) + + // if we have extended or global extended headers, apply them now + // See https://github.com/npm/node-tar/pull/187 + if (ex) this.#slurp(ex) + if (gex) this.#slurp(gex, true) + + // old tar versions marked dirs as a file with a trailing / + const t = decString(buf, off + 156, 1) + if (types.isCode(t)) this.#type = t + else this.#type = '0' + if (this.#type === '') { + this.#type = '0' + } + if (this.#type === '0' && this.path.slice(-1) === '/') { + this.#type = '5' + } + + // tar implementations sometimes incorrectly put the stat(dir).size + // as the size in the tarball, even though Directory entries are + // not able to have any body at all. In the very rare chance that + // it actually DOES have a body, we weren't going to do anything with + // it anyway, and it'll just be a warning about an invalid header. + if (this.#type === '5') { + this.size = 0 + } + + this.linkpath = decString(buf, off + 157, 100) + if ( + buf.subarray(off + 257, off + 265).toString() === + 'ustar\u000000' + ) { + this.uname = decString(buf, off + 265, 32) + this.gname = decString(buf, off + 297, 32) + this.devmaj = decNumber(buf, off + 329, 8) ?? 0 + this.devmin = decNumber(buf, off + 337, 8) ?? 0 + if (buf[off + 475] !== 0) { + // definitely a prefix, definitely >130 chars. + const prefix = decString(buf, off + 345, 155) + this.path = prefix + '/' + this.path + } else { + const prefix = decString(buf, off + 345, 130) + if (prefix) { + this.path = prefix + '/' + this.path + } + this.atime = decDate(buf, off + 476, 12) + this.ctime = decDate(buf, off + 488, 12) + } + } + + let sum = 8 * 0x20 + for (let i = off; i < off + 148; i++) { + sum += buf[i] as number + } + + for (let i = off + 156; i < off + 512; i++) { + sum += buf[i] as number + } + + this.cksumValid = sum === this.cksum + if (this.cksum === null && sum === 8 * 0x20) { + this.nullBlock = true + } + } + + #slurp(ex: HeaderData, gex: boolean = false) { + Object.assign( + this, + Object.fromEntries( + Object.entries(ex).filter(([k, v]) => { + // we slurp in everything except for the path attribute in + // a global extended header, because that's weird. Also, any + // null/undefined values are ignored. + return !( + v === null || + v === undefined || + (k === 'path' && gex) + ) + }), + ), + ) + } + + encode(buf?: Buffer, off: number = 0) { + if (!buf) { + buf = this.block = Buffer.alloc(512) + } + + if (!(buf.length >= off + 512)) { + throw new Error('need 512 bytes for header') + } + + const prefixSize = this.ctime || this.atime ? 130 : 155 + const split = splitPrefix(this.path || '', prefixSize) + const path = split[0] + const prefix = split[1] + this.needPax = !!split[2] + + this.needPax = encString(buf, off, 100, path) || this.needPax + this.needPax = + encNumber(buf, off + 100, 8, this.mode) || this.needPax + this.needPax = + encNumber(buf, off + 108, 8, this.uid) || this.needPax + this.needPax = + encNumber(buf, off + 116, 8, this.gid) || this.needPax + this.needPax = + encNumber(buf, off + 124, 12, this.size) || this.needPax + this.needPax = + encDate(buf, off + 136, 12, this.mtime) || this.needPax + buf[off + 156] = this.#type.charCodeAt(0) + this.needPax = + encString(buf, off + 157, 100, this.linkpath) || this.needPax + buf.write('ustar\u000000', off + 257, 8) + this.needPax = + encString(buf, off + 265, 32, this.uname) || this.needPax + this.needPax = + encString(buf, off + 297, 32, this.gname) || this.needPax + this.needPax = + encNumber(buf, off + 329, 8, this.devmaj) || this.needPax + this.needPax = + encNumber(buf, off + 337, 8, this.devmin) || this.needPax + this.needPax = + encString(buf, off + 345, prefixSize, prefix) || this.needPax + if (buf[off + 475] !== 0) { + this.needPax = + encString(buf, off + 345, 155, prefix) || this.needPax + } else { + this.needPax = + encString(buf, off + 345, 130, prefix) || this.needPax + this.needPax = + encDate(buf, off + 476, 12, this.atime) || this.needPax + this.needPax = + encDate(buf, off + 488, 12, this.ctime) || this.needPax + } + + let sum = 8 * 0x20 + for (let i = off; i < off + 148; i++) { + sum += buf[i] as number + } + + for (let i = off + 156; i < off + 512; i++) { + sum += buf[i] as number + } + + this.cksum = sum + encNumber(buf, off + 148, 8, this.cksum) + this.cksumValid = true + + return this.needPax + } + + get type(): EntryTypeName { + return types.name.get(this.#type) as EntryTypeName + } + + get typeKey(): EntryTypeCode { + return this.#type + } + + set type(type: EntryTypeCode | EntryTypeName) { + const c = String(types.code.get(type as EntryTypeName)) + if (types.isCode(c)) { + this.#type = c + } else if (types.isCode(type)) { + this.#type = type + } else { + throw new TypeError('invalid entry type: ' + type) + } + } +} + +const splitPrefix = ( + p: string, + prefixSize: number, +): [string, string, boolean] => { + const pathSize = 100 + let pp = p + let prefix = '' + let ret: undefined | [string, string, boolean] = undefined + const root = pathModule.parse(p).root || '.' + + if (Buffer.byteLength(pp) < pathSize) { + ret = [pp, prefix, false] + } else { + // first set prefix to the dir, and path to the base + prefix = pathModule.dirname(pp) + pp = pathModule.basename(pp) + + do { + if ( + Buffer.byteLength(pp) <= pathSize && + Buffer.byteLength(prefix) <= prefixSize + ) { + // both fit! + ret = [pp, prefix, false] + } else if ( + Buffer.byteLength(pp) > pathSize && + Buffer.byteLength(prefix) <= prefixSize + ) { + // prefix fits in prefix, but path doesn't fit in path + ret = [pp.slice(0, pathSize - 1), prefix, true] + } else { + // make path take a bit from prefix + pp = pathModule.join(pathModule.basename(prefix), pp) + prefix = pathModule.dirname(prefix) + } + } while (prefix !== root && ret === undefined) + + // at this point, found no resolution, just truncate + if (!ret) { + ret = [p.slice(0, pathSize - 1), '', true] + } + } + return ret +} + +const decString = (buf: Buffer, off: number, size: number) => + buf + .subarray(off, off + size) + .toString('utf8') + .replace(/\0.*/, '') + +const decDate = (buf: Buffer, off: number, size: number) => + numToDate(decNumber(buf, off, size)) + +const numToDate = (num?: number) => + num === undefined ? undefined : new Date(num * 1000) + +const decNumber = (buf: Buffer, off: number, size: number) => + Number(buf[off]) & 0x80 + ? large.parse(buf.subarray(off, off + size)) + : decSmallNumber(buf, off, size) + +const nanUndef = (value: number) => (isNaN(value) ? undefined : value) + +const decSmallNumber = (buf: Buffer, off: number, size: number) => + nanUndef( + parseInt( + buf + .subarray(off, off + size) + .toString('utf8') + .replace(/\0.*$/, '') + .trim(), + 8, + ), + ) + +// the maximum encodable as a null-terminated octal, by field size +const MAXNUM = { + 12: 0o77777777777, + 8: 0o7777777, +} + +const encNumber = ( + buf: Buffer, + off: number, + size: 12 | 8, + num?: number, +) => + num === undefined + ? false + : num > MAXNUM[size] || num < 0 + ? (large.encode(num, buf.subarray(off, off + size)), true) + : (encSmallNumber(buf, off, size, num), false) + +const encSmallNumber = ( + buf: Buffer, + off: number, + size: number, + num: number, +) => buf.write(octalString(num, size), off, size, 'ascii') + +const octalString = (num: number, size: number) => + padOctal(Math.floor(num).toString(8), size) + +const padOctal = (str: string, size: number) => + (str.length === size - 1 + ? str + : new Array(size - str.length - 1).join('0') + str + ' ') + '\0' + +const encDate = ( + buf: Buffer, + off: number, + size: 8 | 12, + date?: Date, +) => + date === undefined + ? false + : encNumber(buf, off, size, date.getTime() / 1000) + +// enough to fill the longest string we've got +const NULLS = new Array(156).join('\0') +// pad with nulls, return true if it's longer or non-ascii +const encString = ( + buf: Buffer, + off: number, + size: number, + str?: string, +) => + str === undefined + ? false + : (buf.write(str + NULLS, off, size, 'utf8'), + str.length !== Buffer.byteLength(str) || str.length > size) diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..bc2c67fe --- /dev/null +++ b/src/index.ts @@ -0,0 +1,21 @@ +export * from './create.js' +export * from './replace.js' +export * from './list.js' +export * from './update.js' +export * from './extract.js' + +export { create as c } from './create.js' +export { replace as r } from './replace.js' +export { list as t } from './list.js' +export { update as u } from './update.js' +export { extract as x } from './extract.js' + +// classes +export * from './pack.js' +export * from './unpack.js' +export * from './parse.js' +export * from './read-entry.js' +export * from './write-entry.js' +export * from './header.js' +export * from './pax.js' +export * as types from './types.js' diff --git a/src/large-numbers.ts b/src/large-numbers.ts new file mode 100644 index 00000000..cd62726d --- /dev/null +++ b/src/large-numbers.ts @@ -0,0 +1,98 @@ +// Tar can encode large and negative numbers using a leading byte of +// 0xff for negative, and 0x80 for positive. + +export const encode = (num: number, buf: Buffer) => { + if (!Number.isSafeInteger(num)) { + // The number is so large that javascript cannot represent it with integer + // precision. + throw Error('cannot encode number outside of javascript safe integer range') + } else if (num < 0) { + encodeNegative(num, buf) + } else { + encodePositive(num, buf) + } + return buf +} + +const encodePositive = (num: number, buf: Buffer) => { + buf[0] = 0x80 + + for (var i = buf.length; i > 1; i--) { + buf[i - 1] = num & 0xff + num = Math.floor(num / 0x100) + } +} + +const encodeNegative = (num: number, buf: Buffer) => { + buf[0] = 0xff + var flipped = false + num = num * -1 + for (var i = buf.length; i > 1; i--) { + var byte = num & 0xff + num = Math.floor(num / 0x100) + if (flipped) { + buf[i - 1] = onesComp(byte) + } else if (byte === 0) { + buf[i - 1] = 0 + } else { + flipped = true + buf[i - 1] = twosComp(byte) + } + } +} + +export const parse = (buf: Buffer) => { + const pre = buf[0] + const value = pre === 0x80 ? pos(buf.subarray(1, buf.length)) + : pre === 0xff ? twos(buf) + : null + if (value === null) { + throw Error('invalid base256 encoding') + } + + if (!Number.isSafeInteger(value)) { + // The number is so large that javascript cannot represent it with integer + // precision. + throw Error('parsed number outside of javascript safe integer range') + } + + return value +} + +const twos = (buf: Buffer) => { + var len = buf.length + var sum = 0 + var flipped = false + for (var i = len - 1; i > -1; i--) { + var byte = Number(buf[i]) + var f + if (flipped) { + f = onesComp(byte) + } else if (byte === 0) { + f = byte + } else { + flipped = true + f = twosComp(byte) + } + if (f !== 0) { + sum -= f * Math.pow(256, len - i - 1) + } + } + return sum +} + +const pos = (buf: Buffer) => { + var len = buf.length + var sum = 0 + for (var i = len - 1; i > -1; i--) { + var byte = Number(buf[i]) + if (byte !== 0) { + sum += byte * Math.pow(256, len - i - 1) + } + } + return sum +} + +const onesComp = (byte: number) => (0xff ^ byte) & 0xff + +const twosComp = (byte: number) => ((0xff ^ byte) + 1) & 0xff diff --git a/src/list.ts b/src/list.ts new file mode 100644 index 00000000..a31a4397 --- /dev/null +++ b/src/list.ts @@ -0,0 +1,185 @@ +// tar -t +import * as fsm from '@isaacs/fs-minipass' +import fs from 'node:fs' +import { dirname, parse } from 'path' +import { + dealias, + isFile, + isSyncFile, + TarOptions, + TarOptionsFile, + TarOptionsWithAliases, + TarOptionsWithAliasesFile, + TarOptionsWithAliasesSync, + TarOptionsWithAliasesSyncFile, +} from './options.js' +import { Parser } from './parse.js' +import { stripTrailingSlashes } from './strip-trailing-slashes.js' + +export function list( + opt: TarOptionsWithAliasesSyncFile, + files?: string[], +): void +export function list( + opt: TarOptionsWithAliasesSync, + files?: string[], +): void +export function list( + opt: TarOptionsWithAliasesFile, + files?: string[], + cb?: () => any, +): Promise<void> +export function list( + opt: TarOptionsWithAliasesFile, + cb: () => any, +): Promise<void> +export function list( + opt: TarOptionsWithAliases, + files?: string[], +): Parser +export function list( + opt_: TarOptionsWithAliases, + files?: string[] | (() => any), + cb?: () => any, +): void | Promise<void> | Parser { + if (typeof opt_ === 'function') { + ;(cb = opt_), (files = undefined), (opt_ = {}) + } else if (Array.isArray(opt_)) { + ;(files = opt_), (opt_ = {}) + } + + if (typeof files === 'function') { + ;(cb = files), (files = undefined) + } + + if (!files) { + files = [] + } else { + files = Array.from(files) + } + + const opt = dealias(opt_) + + if (opt.sync && typeof cb === 'function') { + throw new TypeError( + 'callback not supported for sync tar functions', + ) + } + + if (!opt.file && typeof cb === 'function') { + throw new TypeError('callback only supported with file option') + } + + if (files.length) { + filesFilter(opt, files) + } + + if (!opt.noResume) { + onentryFunction(opt) + } + + return isSyncFile(opt) + ? listFileSync(opt) + : isFile(opt) + ? listFile(opt, cb) + : list_(opt) +} + +const onentryFunction = (opt: TarOptions) => { + const onentry = opt.onentry + opt.onentry = onentry + ? e => { + onentry(e) + e.resume() + } + : e => e.resume() +} + +// construct a filter that limits the file entries listed +// include child entries if a dir is included +const filesFilter = (opt: TarOptions, files: string[]) => { + const map = new Map<string, boolean>( + files.map(f => [stripTrailingSlashes(f), true]), + ) + const filter = opt.filter + + const mapHas = (file: string, r: string = ''): boolean => { + const root = r || parse(file).root || '.' + let ret: boolean + if (file === root) ret = false + else { + const m = map.get(file) + if (m !== undefined) { + ret = m + } else { + ret = mapHas(dirname(file), root) + } + } + + map.set(file, ret) + return ret + } + + opt.filter = filter + ? (file, entry) => + filter(file, entry) && mapHas(stripTrailingSlashes(file)) + : file => mapHas(stripTrailingSlashes(file)) +} + +const listFileSync = (opt: TarOptionsWithAliasesSyncFile) => { + const p = list_(opt) + const file = opt.file + let threw = true + let fd + try { + const stat = fs.statSync(file) + const readSize = opt.maxReadSize || 16 * 1024 * 1024 + if (stat.size < readSize) { + p.end(fs.readFileSync(file)) + } else { + let pos = 0 + const buf = Buffer.allocUnsafe(readSize) + fd = fs.openSync(file, 'r') + while (pos < stat.size) { + const bytesRead = fs.readSync(fd, buf, 0, readSize, pos) + pos += bytesRead + p.write(buf.subarray(0, bytesRead)) + } + p.end() + } + threw = false + } finally { + if (threw && fd) { + try { + fs.closeSync(fd) + } catch (er) {} + } + } +} + +const listFile = (opt: TarOptionsFile, cb?: () => void) => { + const parse = new Parser(opt) + const readSize = opt.maxReadSize || 16 * 1024 * 1024 + + const file = opt.file + const p = new Promise<void>((resolve, reject) => { + parse.on('error', reject) + parse.on('end', resolve) + + fs.stat(file, (er, stat) => { + if (er) { + reject(er) + } else { + const stream = new fsm.ReadStream(file, { + readSize: readSize, + size: stat.size, + }) + stream.on('error', reject) + stream.pipe(parse) + } + }) + }) + return cb ? p.then(cb, cb) : p +} + +const list_ = (opt: TarOptions) => new Parser(opt) diff --git a/src/mkdir.ts b/src/mkdir.ts new file mode 100644 index 00000000..6c84654b --- /dev/null +++ b/src/mkdir.ts @@ -0,0 +1,292 @@ +import { chownr, chownrSync } from 'chownr' +import fs from 'fs' +import { mkdirp, mkdirpSync } from 'mkdirp' +import path from 'node:path' +import { CwdError } from './cwd-error.js' +import { normalizeWindowsPath } from './normalize-windows-path.js' +import { SymlinkError } from './symlink-error.js' + +export type MkdirOptions = { + uid?: number + gid?: number + processUid?: number + processGid?: number + umask?: number + preserve: boolean + unlink: boolean + cache: Map<string, boolean> + cwd: string + mode: number + noChmod: boolean +} + +export type MkdirError = + | NodeJS.ErrnoException + | CwdError + | SymlinkError + +const cGet = (cache: Map<string, boolean>, key: string) => + cache.get(normalizeWindowsPath(key)) +const cSet = ( + cache: Map<string, boolean>, + key: string, + val: boolean, +) => cache.set(normalizeWindowsPath(key), val) + +const checkCwd = ( + dir: string, + cb: (er?: null | MkdirError) => any, +) => { + fs.stat(dir, (er, st) => { + if (er || !st.isDirectory()) { + er = new CwdError( + dir, + (er as NodeJS.ErrnoException)?.code || 'ENOTDIR', + ) + } + cb(er) + }) +} + +/** + * Wrapper around mkdirp for tar's needs. + * + * The main purpose is to avoid creating directories if we know that + * they already exist (and track which ones exist for this purpose), + * and prevent entries from being extracted into symlinked folders, + * if `preservePaths` is not set. + */ +export const mkdir = ( + dir: string, + opt: MkdirOptions, + cb: (er?: null | MkdirError, made?: string) => void, +) => { + dir = normalizeWindowsPath(dir) + + // if there's any overlap between mask and mode, + // then we'll need an explicit chmod + const umask = opt.umask ?? 0o22 + const mode = opt.mode | 0o0700 + const needChmod = (mode & umask) !== 0 + + const uid = opt.uid + const gid = opt.gid + const doChown = + typeof uid === 'number' && + typeof gid === 'number' && + (uid !== opt.processUid || gid !== opt.processGid) + + const preserve = opt.preserve + const unlink = opt.unlink + const cache = opt.cache + const cwd = normalizeWindowsPath(opt.cwd) + + const done = (er?: null | MkdirError, created?: string) => { + if (er) { + cb(er) + } else { + cSet(cache, dir, true) + if (created && doChown) { + chownr(created, uid, gid, er => + done(er as NodeJS.ErrnoException), + ) + } else if (needChmod) { + fs.chmod(dir, mode, cb) + } else { + cb() + } + } + } + + if (cache && cGet(cache, dir) === true) { + return done() + } + + if (dir === cwd) { + return checkCwd(dir, done) + } + + if (preserve) { + return mkdirp(dir, { mode }).then( + made => done(null, made ?? undefined), // oh, ts + done, + ) + } + + const sub = normalizeWindowsPath(path.relative(cwd, dir)) + const parts = sub.split('/') + mkdir_(cwd, parts, mode, cache, unlink, cwd, undefined, done) +} + +const mkdir_ = ( + base: string, + parts: string[], + mode: number, + cache: Map<string, boolean>, + unlink: boolean, + cwd: string, + created: string | undefined, + cb: (er?: null | MkdirError, made?: string) => void, +): void => { + if (!parts.length) { + return cb(null, created) + } + const p = parts.shift() + const part = normalizeWindowsPath(path.resolve(base + '/' + p)) + if (cGet(cache, part)) { + return mkdir_(part, parts, mode, cache, unlink, cwd, created, cb) + } + fs.mkdir( + part, + mode, + onmkdir(part, parts, mode, cache, unlink, cwd, created, cb), + ) +} + +const onmkdir = + ( + part: string, + parts: string[], + mode: number, + cache: Map<string, boolean>, + unlink: boolean, + cwd: string, + created: string | undefined, + cb: (er?: null | MkdirError, made?: string) => void, + ) => + (er?: null | NodeJS.ErrnoException) => { + if (er) { + fs.lstat(part, (statEr, st) => { + if (statEr) { + statEr.path = + statEr.path && normalizeWindowsPath(statEr.path) + cb(statEr) + } else if (st.isDirectory()) { + mkdir_(part, parts, mode, cache, unlink, cwd, created, cb) + } else if (unlink) { + fs.unlink(part, er => { + if (er) { + return cb(er) + } + fs.mkdir( + part, + mode, + onmkdir( + part, + parts, + mode, + cache, + unlink, + cwd, + created, + cb, + ), + ) + }) + } else if (st.isSymbolicLink()) { + return cb( + new SymlinkError(part, part + '/' + parts.join('/')), + ) + } else { + cb(er) + } + }) + } else { + created = created || part + mkdir_(part, parts, mode, cache, unlink, cwd, created, cb) + } + } + +const checkCwdSync = (dir: string) => { + let ok = false + let code: string | undefined = undefined + try { + ok = fs.statSync(dir).isDirectory() + } catch (er) { + code = (er as NodeJS.ErrnoException)?.code + } finally { + if (!ok) { + throw new CwdError(dir, code ?? 'ENOTDIR') + } + } +} + +export const mkdirSync = (dir: string, opt: MkdirOptions) => { + dir = normalizeWindowsPath(dir) + // if there's any overlap between mask and mode, + // then we'll need an explicit chmod + const umask = opt.umask ?? 0o22 + const mode = opt.mode | 0o700 + const needChmod = (mode & umask) !== 0 + + const uid = opt.uid + const gid = opt.gid + const doChown = + typeof uid === 'number' && + typeof gid === 'number' && + (uid !== opt.processUid || gid !== opt.processGid) + + const preserve = opt.preserve + const unlink = opt.unlink + const cache = opt.cache + const cwd = normalizeWindowsPath(opt.cwd) + + const done = (created?: string | undefined) => { + cSet(cache, dir, true) + if (created && doChown) { + chownrSync(created, uid, gid) + } + if (needChmod) { + fs.chmodSync(dir, mode) + } + } + + if (cache && cGet(cache, dir) === true) { + return done() + } + + if (dir === cwd) { + checkCwdSync(cwd) + return done() + } + + if (preserve) { + return done(mkdirpSync(dir, mode) ?? undefined) + } + + const sub = normalizeWindowsPath(path.relative(cwd, dir)) + const parts = sub.split('/') + let created: string | undefined = undefined + for ( + let p = parts.shift(), part = cwd; + p && (part += '/' + p); + p = parts.shift() + ) { + part = normalizeWindowsPath(path.resolve(part)) + if (cGet(cache, part)) { + continue + } + + try { + fs.mkdirSync(part, mode) + created = created || part + cSet(cache, part, true) + } catch (er) { + const st = fs.lstatSync(part) + if (st.isDirectory()) { + cSet(cache, part, true) + continue + } else if (unlink) { + fs.unlinkSync(part) + fs.mkdirSync(part, mode) + created = created || part + cSet(cache, part, true) + continue + } else if (st.isSymbolicLink()) { + return new SymlinkError(part, part + '/' + parts.join('/')) + } + } + } + + return done(created) +} diff --git a/src/mode-fix.ts b/src/mode-fix.ts new file mode 100644 index 00000000..57bf9c98 --- /dev/null +++ b/src/mode-fix.ts @@ -0,0 +1,26 @@ +export const modeFix = (mode: number, isDir: boolean, portable: boolean) => { + mode &= 0o7777 + + // in portable mode, use the minimum reasonable umask + // if this system creates files with 0o664 by default + // (as some linux distros do), then we'll write the + // archive with 0o644 instead. Also, don't ever create + // a file that is not readable/writable by the owner. + if (portable) { + mode = (mode | 0o600) & ~0o22 + } + + // if dirs are readable, then they should be listable + if (isDir) { + if (mode & 0o400) { + mode |= 0o100 + } + if (mode & 0o40) { + mode |= 0o10 + } + if (mode & 0o4) { + mode |= 0o1 + } + } + return mode +} diff --git a/src/normalize-unicode.ts b/src/normalize-unicode.ts new file mode 100644 index 00000000..61dacf06 --- /dev/null +++ b/src/normalize-unicode.ts @@ -0,0 +1,12 @@ +// warning: extremely hot code path. +// This has been meticulously optimized for use +// within npm install on large package trees. +// Do not edit without careful benchmarking. +const normalizeCache = Object.create(null) +const { hasOwnProperty } = Object.prototype +export const normalizeUnicode = (s: string) => { + if (!hasOwnProperty.call(normalizeCache, s)) { + normalizeCache[s] = s.normalize('NFD') + } + return normalizeCache[s] +} diff --git a/src/normalize-windows-path.ts b/src/normalize-windows-path.ts new file mode 100644 index 00000000..e452009b --- /dev/null +++ b/src/normalize-windows-path.ts @@ -0,0 +1,12 @@ +// on windows, either \ or / are valid directory separators. +// on unix, \ is a valid character in filenames. +// so, on windows, and only on windows, we replace all \ chars with /, +// so that we can use / as our one and only directory separator char. + +const platform = + process.env.TESTING_TAR_FAKE_PLATFORM || process.platform + +export const normalizeWindowsPath = + platform !== 'win32' + ? (p: string) => p + : (p: string) => p && p.replace(/\\/g, '/') diff --git a/src/options.ts b/src/options.ts new file mode 100644 index 00000000..4449b718 --- /dev/null +++ b/src/options.ts @@ -0,0 +1,473 @@ +// turn tar(1) style args like `C` into the more verbose things like `cwd` + +import { type GzipOptions, type ZlibOptions } from 'minizlib' +import { type Stats } from 'node:fs' +import { type ReadEntry } from './read-entry.js' +import { type WarnData } from './warn-method.js' + +const argmap = new Map<keyof TarOptionsWithAliases, keyof TarOptions>( + [ + ['C', 'cwd'], + ['f', 'file'], + ['z', 'gzip'], + ['P', 'preservePaths'], + ['U', 'unlink'], + ['strip-components', 'strip'], + ['stripComponents', 'strip'], + ['keep-newer', 'newer'], + ['keepNewer', 'newer'], + ['keep-newer-files', 'newer'], + ['keepNewerFiles', 'newer'], + ['k', 'keep'], + ['keep-existing', 'keep'], + ['keepExisting', 'keep'], + ['m', 'noMtime'], + ['no-mtime', 'noMtime'], + ['p', 'preserveOwner'], + ['L', 'follow'], + ['h', 'follow'], + ], +) + +/** + * The options that can be provided to tar commands. + * + * Note that some of these are only relevant for certain commands, since + * they are specific to reading or writing. + * + * Aliases are provided in the {@link TarOptionsWithAliases} type. + */ +export interface TarOptions { + /** + * Perform all I/O operations synchronously. If the stream is ended + * immediately, then it will be processed entirely synchronously. + */ + sync?: boolean + + /** + * The tar file to be read and/or written. When this is set, a stream + * is not returned. Asynchronous commands will return a promise indicating + * when the operation is completed, and synchronous commands will return + * immediately. + */ + file?: string + + /** + * Treat warnings as crash-worthy errors. Defaults false. + */ + strict?: boolean + + /** + * The effective current working directory for this tar command + */ + cwd?: string + + /** + * When creating a tar archive, this can be used to compress it as well. + * Set to `true` to use the default gzip options, or customize them as + * needed. + * + * When reading, if this is unset, then the compression status will be + * inferred from the archive data. This is generally best, unless you are + * sure of the compression settings in use to create the archive, and want to + * fail if the archive doesn't match expectations. + */ + gzip?: boolean | GzipOptions + + /** + * When creating archives, preserve absolute and `..` paths in the archive, + * rather than sanitizing them under the cwd. + * + * When extracting, allow absolute paths, paths containing `..`, and + * extracting through symbolic links. By default, the root `/` is stripped + * from absolute paths (eg, turning `/x/y/z` into `x/y/z`), paths containing + * `..` are not extracted, and any file whose location would be modified by a + * symbolic link is not extracted. + * + * **WARNING** This is almost always unsafe, and must NEVER be used on + * archives from untrusted sources, such as user input, and every entry must + * be validated to ensure it is safe to write. Even if the input is not + * malicious, mistakes can cause a lot of damage! + */ + preservePaths?: boolean + + /** + * When extracting, unlink files before creating them. Without this option, + * tar overwrites existing files, which preserves existing hardlinks. With + * this option, existing hardlinks will be broken, as will any symlink that + * would affect the location of an extracted file. + */ + unlink?: boolean + + /** + * When extracting, strip the specified number of path portions from the + * entry path. For example, with `{strip: 2}`, the entry `a/b/c/d` would be + * extracted to `{cwd}/c/d`. + */ + strip?: number + + /** + * When extracting, keep the existing file on disk if it's newer than the + * file in the archive. + */ + newer?: boolean + + /** + * When extracting, do not overwrite existing files at all. + */ + keep?: boolean + + /** + * When extracting, do not set the `mtime` value for extracted entries to + * match the `mtime` in the archive. + * + * When creating archives, do not store the `mtime` value in the entry. Note + * that this prevents properly using other mtime-based features (such as + * `tar.update` or the `newer` option) with the resulting archive. + */ + noMtime?: boolean + + /** + * Set the `uid` and `gid` of extracted entries to the `uid` and `gid` fields + * in the archive. Defaults to true when run as root, and false otherwise. + * + * If false, then files and directories will be set with the owner and group + * of the user running the process. This is similar to `-p` in `tar(1)`, but + * ACLs and other system-specific data is never unpacked in this + * implementation, and modes are set by default already. + */ + preserveOwner?: boolean + + /** + * Pack the targets of symbolic links rather than the link itself. + */ + follow?: boolean + + /** + * Set to `true` or an object with settings for `zlib.BrotliCompress()` to + * create a brotli-compressed archive + */ + brotli?: boolean | ZlibOptions + + /** + * A function that is called with `(path, stat)` when creating an archive, or + * `(path, entry)` when unpacking. Return true to process the file/entry, or + * false to exclude it. + */ + filter?: (path: string, entry: Stats | ReadEntry) => boolean + + /** + * A function that gets called for any warning encountered. + * + * Note: if `strict` is set, then the warning will throw, and this method + * will not be called. + */ + onwarn?: (code: string, message: string, data: WarnData) => any + + /** + * When unpacking, force all created files and directories, and all + * implicitly created directories, to be owned by the specified user id, + * regardless of the `uid` field in the archive. + * + * Cannot be used along with `preserveOwner`. Requires also setting the `gid` + * option. + */ + uid?: number + + /** + * When unpacking, force all created files and directories, and all + * implicitly created directories, to be owned by the specified group id, + * regardless of the `gid` field in the archive. + * + * Cannot be used along with `preserveOwner`. Requires also setting the `uid` + * option. + */ + gid?: number + + /** + * When extracting, provide a function that takes an `entry` object, and + * returns a stream, or any falsey value. If a stream is provided, then that + * stream's data will be written instead of the contents of the archive + * entry. If a falsey value is provided, then the entry is written to disk as + * normal. + * + * To exclude items from extraction, use the `filter` option. + * + * Note that using an asynchronous stream type with the `transform` option + * will cause undefined behavior in synchronous extractions. + * [MiniPass](http://npm.im/minipass)-based streams are designed for this use + * case. + */ + transform?: (entry: ReadEntry) => any + + /** + * The maximum depth of subfolders to extract into. This defaults to 1024. + * Anything deeper than the limit will raise a warning and skip the entry. + * Set to `Infinity` to remove the limitation. + */ + maxDepth?: number + + /** + * Do not call `chmod()` to ensure that extracted files match the entry's + * mode field. This also suppresses the call to `process.umask()` to + * determine the default umask value, since tar will extract with whatever + * mode is provided, and let the process `umask` apply normally. + */ + noChmod?: boolean + + /** + * When parsing/listing archives, `entry` streams are by default resumed + * (set into "flowing" mode) immediately after the call to `onentry()`. + * Set to suppress this behavior. + * + * Note that when this is set, the stream will never complete until the + * data is consumed somehow. + */ + noResume?: boolean + + /** + * When extracting or listing archives, this method will be called with + * each entry that is not excluded by a `filter`. + * + * Important when listing archives synchronously from a file, because there + * is otherwise no way to interact with the data! + */ + onentry?: (entry: ReadEntry) => any + + /** + * When creating archives, omit any metadata that is system-specific: + * `ctime`, `atime`, `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and + * `nlink`. Note that `mtime` is still included, because this is necessary + * for other time-based operations such as `tar.update`. Additionally, `mode` + * is set to a "reasonable default" for mose unix systems, based on an + * effective `umask` of `0o22`. + * + * This also defaults the `portable` option in the gzip configs when creating + * a compressed archive, in order to produce deterministic archives that are + * not operating-system specific. + */ + portable?: boolean + + /** + * When creating archives, do not recursively archive the contents of + * directories. By default, archiving a directory archives all of its + * contents as well. + */ + noDirRecurse?: boolean + + /** + * Suppress Pax extended headers. Note that this means long paths and + * linkpaths will be truncated, and large or negative numeric values may be + * interpreted incorrectly. + */ + noPax?: boolean + + /** + * Set to a `Date` object to force a specific `mtime` value for everything + * written to an archive. + * + * Overridden by `noMtime`. + */ + mtime?: Date + + /** + * A path portion to prefix onto the entries added to an archive. + */ + prefix?: string + + /** + * The mode to set on any created file archive, defaults to 0o666 + * masked by the process umask, often resulting in 0o644. + */ + mode?: number + + ////////////////////////// + // internal options + + /** + * A cache of mtime values, to avoid having to stat the same file repeatedly. + * @internal + */ + mtimeCache?: Map<string, Date> + + /** + * maximum buffer size for `fs.read()` operations. + * + * @internal + */ + maxReadSize?: number + + /** + * Filter modes of entries being unpacked, like `process.umask()` + * + * @internal + */ + umask?: number + + /** + * default mode for directories + * + * @internal + */ + dmode?: number + + /** + * default mode for files + * + * @internal + */ + fmode?: number + + /** + * Map that tracks which directories already exist, for extraction + * + * @internal + */ + dirCache?: Map<string, boolean> + /** + * maximum supported size of meta entries. Defaults to 1MB + * + * @internal + */ + maxMetaEntrySize?: number + + /** + * A Map object containing the device and inode value for any file whose + * `nlink` value is greater than 1, to identify hard links when creating + * archives. + * + * @internal + */ + linkCache?: Map<LinkCacheKey, string> + + /** + * A map object containing the results of `fs.readdir()` calls. + * + * @internal + */ + readdirCache?: Map<string, string[]> + + /** + * A cache of all `lstat` results, for use in creating archives. + * + * @internal + */ + statCache?: Map<string, Stats> + + /** + * Number of concurrent jobs to run when creating archives. + * + * Defaults to 4. + * + * @internal + */ + jobs?: number + + /** + * Automatically set to true on Windows systems. + * + * When unpacking, causes behavior where filenames containing `<|>?:` + * characters are converted to windows-compatible escape sequences in the + * created filesystem entries. + * + * When packing, causes behavior where paths replace `\` with `/`, and + * filenames containing the windows-compatible escaped forms of `<|>?:` are + * converted to actual `<|>?:` characters in the archive. + * + * @internal + */ + win32?: boolean + + /** + * For `WriteEntry` objects, the absolute path to the entry on the + * filesystem. By default, this is `resolve(cwd, entry.path)`, but it can be + * overridden explicitly. + * + * @internal + */ + absolute?: string + + /** + * Used with Parser stream interface, to attach and take over when the + * stream is completely parsed. If this is set, then the prefinish, + * finish, and end events will not fire, and are the responsibility of + * the ondone method to emit properly. + * + * @internal + */ + ondone?: () => void + + /** + * Mostly for testing, but potentially useful in some cases. + * Forcibly trigger a chown on every entry, no matter what. + */ + forceChown?: boolean +} + +export type TarOptionsSync = TarOptions & { sync: true } +export type TarOptionsFile = TarOptions & { file: string } +export type TarOptionsSyncFile = TarOptionsSync & TarOptionsFile + +export type LinkCacheKey = `${number}:${number}` + +export interface TarOptionsWithAliases extends TarOptions { + C?: TarOptions['cwd'] + f?: TarOptions['file'] + z?: TarOptions['gzip'] + P?: TarOptions['preservePaths'] + U?: TarOptions['unlink'] + 'strip-components'?: TarOptions['strip'] + stripComponents?: TarOptions['strip'] + 'keep-newer'?: TarOptions['newer'] + keepNewer?: TarOptions['newer'] + 'keep-newer-files'?: TarOptions['newer'] + keepNewerFiles?: TarOptions['newer'] + k?: TarOptions['keep'] + 'keep-existing'?: TarOptions['keep'] + keepExisting?: TarOptions['keep'] + m?: TarOptions['noMtime'] + 'no-mtime'?: TarOptions['noMtime'] + p?: TarOptions['preserveOwner'] + L?: TarOptions['follow'] + h?: TarOptions['follow'] +} + +export type TarOptionsWithAliasesSync = TarOptionsWithAliases & { + sync: true +} +export type TarOptionsWithAliasesFile = TarOptionsWithAliases & { + file: string +} +export type TarOptionsWithAliasesSyncFile = + TarOptionsWithAliasesSync & TarOptionsWithAliasesFile + +export const isSyncFile = (o: TarOptions): o is TarOptionsSyncFile => + !!o.sync && !!o.file +export const isSync = (o: TarOptions): o is TarOptionsSync => + !!o.sync +export const isFile = (o: TarOptions): o is TarOptionsFile => + !!o.file + +const dealiasKey = ( + k: keyof TarOptionsWithAliases, +): keyof TarOptions => { + const d = argmap.get(k) + if (d) return d + return k as keyof TarOptions +} + +export const dealias = ( + opt: TarOptionsWithAliases = {}, +): TarOptions => { + if (!opt) return {} + const result: Record<string, any> = {} + for (const [key, v] of Object.entries(opt) as [ + keyof TarOptionsWithAliases, + any, + ][]) { + // TS doesn't know that aliases are going to always be the same type + const k = dealiasKey(key) + result[k] = v + } + return result as TarOptions +} diff --git a/src/pack.ts b/src/pack.ts new file mode 100644 index 00000000..4dc7e3b5 --- /dev/null +++ b/src/pack.ts @@ -0,0 +1,500 @@ +// A readable tar stream creator +// Technically, this is a transform stream that you write paths into, +// and tar format comes out of. +// The `add()` method is like `write()` but returns this, +// and end() return `this` as well, so you can +// do `new Pack(opt).add('files').add('dir').end().pipe(output) +// You could also do something like: +// streamOfPaths().pipe(new Pack()).pipe(new fs.WriteStream('out.tar')) + +import fs, { type Stats } from 'fs' +import { Minipass } from 'minipass' +import { BrotliCompress, Gzip } from 'minizlib' +import path from 'path' +import { normalizeWindowsPath } from './normalize-windows-path.js' +import { dealias, LinkCacheKey, TarOptions } from './options.js' +import { ReadEntry } from './read-entry.js' +import { + warnMethod, + type WarnData, + type Warner, +} from './warn-method.js' +import { + WriteEntry, + WriteEntrySync, + WriteEntryTar, +} from './write-entry.js' + +export class PackJob { + path: string + absolute: string + entry?: WriteEntry | WriteEntryTar + stat?: Stats + readdir?: string[] + pending: boolean = false + ignore: boolean = false + piped: boolean = false + + constructor(path: string, absolute: string) { + this.path = path || './' + this.absolute = absolute + } +} + +const EOF = Buffer.alloc(1024) +const ONSTAT = Symbol('onStat') +const ENDED = Symbol('ended') +const QUEUE = Symbol('queue') +const CURRENT = Symbol('current') +const PROCESS = Symbol('process') +const PROCESSING = Symbol('processing') +const PROCESSJOB = Symbol('processJob') +const JOBS = Symbol('jobs') +const JOBDONE = Symbol('jobDone') +const ADDFSENTRY = Symbol('addFSEntry') +const ADDTARENTRY = Symbol('addTarEntry') +const STAT = Symbol('stat') +const READDIR = Symbol('readdir') +const ONREADDIR = Symbol('onreaddir') +const PIPE = Symbol('pipe') +const ENTRY = Symbol('entry') +const ENTRYOPT = Symbol('entryOpt') +const WRITEENTRYCLASS = Symbol('writeEntryClass') +const WRITE = Symbol('write') +const ONDRAIN = Symbol('ondrain') + +export class Pack extends Minipass implements Warner { + opt: TarOptions + file: string + cwd: string + maxReadSize?: number + preservePaths: boolean + strict: boolean + noPax: boolean + prefix: string + linkCache: Map<LinkCacheKey, string> + statCache: Map<string, Stats> + readdirCache: Map<string, string[]> + portable: boolean + zip?: Gzip | BrotliCompress + noDirRecurse: boolean + follow: boolean + noMtime: boolean + mtime?: Date + filter: Exclude<TarOptions['filter'], undefined> + jobs: number; + + [WRITEENTRYCLASS]: + | typeof WriteEntry + | typeof WriteEntrySync + [QUEUE]: PackJob[] = []; + [JOBS]: number = 0; + [PROCESSING]: boolean = false; + [ENDED]: boolean = false + + constructor(opt_: TarOptions = {}) { + super() + const opt = dealias(opt_) + this.opt = opt + this.file = opt.file || '' + this.cwd = opt.cwd || process.cwd() + this.maxReadSize = opt.maxReadSize + this.preservePaths = !!opt.preservePaths + this.strict = !!opt.strict + this.noPax = !!opt.noPax + this.prefix = normalizeWindowsPath(opt.prefix || '') + this.linkCache = opt.linkCache || new Map() + this.statCache = opt.statCache || new Map() + this.readdirCache = opt.readdirCache || new Map() + + this[WRITEENTRYCLASS] = WriteEntry + if (typeof opt.onwarn === 'function') { + this.on('warn', opt.onwarn) + } + + this.portable = !!opt.portable + + if (opt.gzip || opt.brotli) { + if (opt.gzip && opt.brotli) { + throw new TypeError('gzip and brotli are mutually exclusive') + } + if (opt.gzip) { + if (typeof opt.gzip !== 'object') { + opt.gzip = {} + } + if (this.portable) { + opt.gzip.portable = true + } + this.zip = new Gzip(opt.gzip) + } + if (opt.brotli) { + if (typeof opt.brotli !== 'object') { + opt.brotli = {} + } + this.zip = new BrotliCompress(opt.brotli) + } + const zip = this.zip as Gzip | BrotliCompress + zip.on('data', chunk => super.write(chunk)) + zip.on('end', () => super.end()) + zip.on('drain', () => this[ONDRAIN]()) + this.on('resume', () => zip.resume()) + } else { + this.on('drain', this[ONDRAIN]) + } + + this.noDirRecurse = !!opt.noDirRecurse + this.follow = !!opt.follow + this.noMtime = !!opt.noMtime + this.mtime = opt.mtime + + this.filter = + typeof opt.filter === 'function' ? opt.filter : () => true + + this[JOBS] = 0 + this.jobs = Number(opt.jobs) || 4 + this[PROCESSING] = false + this[ENDED] = false + } + + warn(code: string, message: string | Error, data: WarnData = {}) { + return warnMethod(this, code, message, data) + } + + [WRITE](chunk: Buffer) { + return super.write(chunk) + } + + add(path: string | ReadEntry) { + this.write(path) + return this + } + + end(cb?: () => void): this + end(path: string, cb?: () => void): this + end( + path: string, + encoding?: Minipass.Encoding | undefined, + cb?: () => void, + ): this + end( + path?: string | (() => void), + _encoding?: Minipass.Encoding | (() => void), + _cb?: () => void, + ) { + if (typeof path === 'string') { + this.write(path) + } + this[ENDED] = true + this[PROCESS]() + return this + } + + //@ts-ignore + write(path: string | ReadEntry) { + if (this[ENDED]) { + throw new Error('write after end') + } + + if (path instanceof ReadEntry) { + this[ADDTARENTRY](path) + } else { + this[ADDFSENTRY](path) + } + return this.flowing + } + + [ADDTARENTRY](p: ReadEntry) { + const absolute = normalizeWindowsPath( + path.resolve(this.cwd, p.path), + ) + // in this case, we don't have to wait for the stat + if (!this.filter(p.path, p)) { + p.resume() + } else { + const job = new PackJob(p.path, absolute) + job.entry = new WriteEntryTar(p, this[ENTRYOPT](job)) + job.entry.on('end', _ => this[JOBDONE](job)) + this[JOBS] += 1 + this[QUEUE].push(job) + } + + this[PROCESS]() + } + + [ADDFSENTRY](p: string) { + const absolute = normalizeWindowsPath(path.resolve(this.cwd, p)) + this[QUEUE].push(new PackJob(p, absolute)) + this[PROCESS]() + } + + [STAT](job: PackJob) { + job.pending = true + this[JOBS] += 1 + const stat = this.follow ? 'stat' : 'lstat' + fs[stat](job.absolute, (er, stat) => { + job.pending = false + this[JOBS] -= 1 + if (er) { + this.emit('error', er) + } else { + this[ONSTAT](job, stat) + } + }) + } + + [ONSTAT](job: PackJob, stat: Stats) { + this.statCache.set(job.absolute, stat) + job.stat = stat + + // now we have the stat, we can filter it. + if (!this.filter(job.path, stat)) { + job.ignore = true + } + + this[PROCESS]() + } + + [READDIR](job: PackJob) { + job.pending = true + this[JOBS] += 1 + fs.readdir(job.absolute, (er, entries) => { + job.pending = false + this[JOBS] -= 1 + if (er) { + return this.emit('error', er) + } + this[ONREADDIR](job, entries) + }) + } + + [ONREADDIR](job: PackJob, entries: string[]) { + this.readdirCache.set(job.absolute, entries) + job.readdir = entries + this[PROCESS]() + } + + [PROCESS]() { + if (this[PROCESSING]) { + return + } + + this[PROCESSING] = true + for ( + let j: PackJob | undefined, w = 0; + (j = this[QUEUE][w]) && this[JOBS] < this.jobs; + w ++ + ) { + this[PROCESSJOB](j) + if (j.ignore) { + this[QUEUE].splice(w, 1) + } + } + + this[PROCESSING] = false + + if (this[ENDED] && !this[QUEUE].length && this[JOBS] === 0) { + if (this.zip) { + this.zip.end(EOF) + } else { + super.write(EOF) + super.end() + } + } + } + + get [CURRENT]() { + return this[QUEUE] && this[QUEUE][0] + } + + [JOBDONE](_job: PackJob) { + this[QUEUE].shift() + this[JOBS] -= 1 + this[PROCESS]() + } + + [PROCESSJOB](job: PackJob) { + if (job.pending) { + return + } + + if (job.entry) { + if (job === this[CURRENT] && !job.piped) { + this[PIPE](job) + } + return + } + + if (!job.stat) { + const sc = this.statCache.get(job.absolute) + if (sc) { + this[ONSTAT](job, sc) + } else { + this[STAT](job) + } + } + if (!job.stat) { + return + } + + // filtered out! + if (job.ignore) { + return + } + + if ( + !this.noDirRecurse && + job.stat.isDirectory() && + !job.readdir + ) { + + const rc = this.readdirCache.get(job.absolute) + if ( rc) { + this[ONREADDIR](job, rc) + } else { + this[READDIR](job) + } + if (!job.readdir) { + return + } + } + + // we know it doesn't have an entry, because that got checked above + job.entry = this[ENTRY](job) + if (!job.entry) { + job.ignore = true + return + } + + if (job === this[CURRENT] && !job.piped) { + this[PIPE](job) + } + } + + [ENTRYOPT](job: PackJob): TarOptions { + return { + onwarn: (code, msg, data) => this.warn(code, msg, data), + noPax: this.noPax, + cwd: this.cwd, + absolute: job.absolute, + preservePaths: this.preservePaths, + maxReadSize: this.maxReadSize, + strict: this.strict, + portable: this.portable, + linkCache: this.linkCache, + statCache: this.statCache, + noMtime: this.noMtime, + mtime: this.mtime, + prefix: this.prefix, + } + } + + [ENTRY](job: PackJob) { + this[JOBS] += 1 + try { + const Cls = this[WRITEENTRYCLASS] + return new Cls(job.path, this[ENTRYOPT](job)) + .on('end', () => this[JOBDONE](job)) + .on('error', er => this.emit('error', er)) + } catch (er) { + this.emit('error', er) + } + } + + [ONDRAIN]() { + if (this[CURRENT] && this[CURRENT].entry) { + this[CURRENT].entry.resume() + } + } + + // like .pipe() but using super, because our write() is special + [PIPE](job: PackJob) { + job.piped = true + + if (job.readdir) { + job.readdir.forEach(entry => { + const p = job.path + const base = p === './' ? '' : p.replace(/\/*$/, '/') + this[ADDFSENTRY](base + entry) + }) + } + + const source = job.entry + const zip = this.zip + + /* c8 ignore start */ + if (!source) { + throw new Error('must have source before piping') + } + /* c8 ignore stop */ + + if (zip) { + source.on('data', chunk => { + if (!zip.write(chunk)) { + source.pause() + } + }) + } else { + source.on('data', chunk => { + if (!super.write(chunk)) { + source.pause() + } + }) + } + } + + pause() { + if (this.zip) { + this.zip.pause() + } + return super.pause() + } +} + +export class PackSync extends Pack { + constructor(opt: TarOptions) { + super(opt) + this[WRITEENTRYCLASS] = WriteEntrySync + } + + // pause/resume are no-ops in sync streams. + pause() {} + resume() {} + + [STAT](job: PackJob) { + const stat = this.follow ? 'statSync' : 'lstatSync' + this[ONSTAT](job, fs[stat](job.absolute)) + } + + [READDIR](job: PackJob) { + this[ONREADDIR](job, fs.readdirSync(job.absolute)) + } + + // gotta get it all in this tick + [PIPE](job: PackJob) { + const source = job.entry + /* c8 ignore start */ + if (!source) { + throw new Error('job without source') + } + /* c8 ignore stop */ + const zip = this.zip + + if (job.readdir) { + job.readdir.forEach(entry => { + const p = job.path + const base = p === './' ? '' : p.replace(/\/*$/, '/') + this[ADDFSENTRY](base + entry) + }) + } + + if (zip) { + source.on('data', chunk => { + zip.write(chunk) + }) + } else { + source.on('data', chunk => { + super[WRITE](chunk) + }) + } + } +} diff --git a/src/parse.ts b/src/parse.ts new file mode 100644 index 00000000..7912fef0 --- /dev/null +++ b/src/parse.ts @@ -0,0 +1,629 @@ +// this[BUFFER] is the remainder of a chunk if we're waiting for +// the full 512 bytes of a header to come in. We will Buffer.concat() +// it to the next write(), which is a mem copy, but a small one. +// +// this[QUEUE] is a Yallist of entries that haven't been emitted +// yet this can only get filled up if the user keeps write()ing after +// a write() returns false, or does a write() with more than one entry +// +// We don't buffer chunks, we always parse them and either create an +// entry, or push it into the active entry. The ReadEntry class knows +// to throw data away if .ignore=true +// +// Shift entry off the buffer when it emits 'end', and emit 'entry' for +// the next one in the list. +// +// At any time, we're pushing body chunks into the entry at WRITEENTRY, +// and waiting for 'end' on the entry at READENTRY +// +// ignored entries get .resume() called on them straight away + +import { EventEmitter as EE } from 'events' +import { BrotliDecompress, Unzip } from 'minizlib' +import { Header } from './header.js' +import { TarOptions } from './options.js' +import { Pax } from './pax.js' +import { ReadEntry } from './read-entry.js' +import { + warnMethod, + type WarnData, + type Warner, +} from './warn-method.js' + +const maxMetaEntrySize = 1024 * 1024 +const gzipHeader = Buffer.from([0x1f, 0x8b]) + +const STATE = Symbol('state') +const WRITEENTRY = Symbol('writeEntry') +const READENTRY = Symbol('readEntry') +const NEXTENTRY = Symbol('nextEntry') +const PROCESSENTRY = Symbol('processEntry') +const EX = Symbol('extendedHeader') +const GEX = Symbol('globalExtendedHeader') +const META = Symbol('meta') +const EMITMETA = Symbol('emitMeta') +const BUFFER = Symbol('buffer') +const QUEUE = Symbol('queue') +const ENDED = Symbol('ended') +const EMITTEDEND = Symbol('emittedEnd') +const EMIT = Symbol('emit') +const UNZIP = Symbol('unzip') +const CONSUMECHUNK = Symbol('consumeChunk') +const CONSUMECHUNKSUB = Symbol('consumeChunkSub') +const CONSUMEBODY = Symbol('consumeBody') +const CONSUMEMETA = Symbol('consumeMeta') +const CONSUMEHEADER = Symbol('consumeHeader') +const CONSUMING = Symbol('consuming') +const BUFFERCONCAT = Symbol('bufferConcat') +const MAYBEEND = Symbol('maybeEnd') +const WRITING = Symbol('writing') +const ABORTED = Symbol('aborted') +const DONE = Symbol('onDone') +const SAW_VALID_ENTRY = Symbol('sawValidEntry') +const SAW_NULL_BLOCK = Symbol('sawNullBlock') +const SAW_EOF = Symbol('sawEOF') +const CLOSESTREAM = Symbol('closeStream') + +const noop = () => true + +export type State = 'begin' | 'header' | 'ignore' | 'meta' | 'body' + +export class Parser extends EE implements Warner { + file: string + strict: boolean + maxMetaEntrySize: number + filter: Exclude<TarOptions['filter'], undefined> + brotli?: TarOptions['brotli'] + + writable: true = true + readable: false = false; + + [QUEUE]: (ReadEntry | [string | symbol, any, any])[] = []; + [BUFFER]?: Buffer; + [READENTRY]?: ReadEntry; + [WRITEENTRY]?: ReadEntry; + [STATE]: State = 'begin'; + [META]: string = ''; + [EX]?: Pax; + [GEX]?: Pax; + [ENDED]: boolean = false; + [UNZIP]?: false | Unzip | BrotliDecompress; + [ABORTED]: boolean = false; + [SAW_VALID_ENTRY]?: boolean; + [SAW_NULL_BLOCK]: boolean = false; + [SAW_EOF]: boolean = false; + [WRITING]: boolean = false; + [CONSUMING]: boolean = false; + [EMITTEDEND]: boolean = false + + constructor(opt: TarOptions = {}) { + super() + + this.file = opt.file || '' + + // these BADARCHIVE errors can't be detected early. listen on DONE. + this.on(DONE, () => { + if ( + this[STATE] === 'begin' || + this[SAW_VALID_ENTRY] === false + ) { + // either less than 1 block of data, or all entries were invalid. + // Either way, probably not even a tarball. + this.warn('TAR_BAD_ARCHIVE', 'Unrecognized archive format') + } + }) + + if (opt.ondone) { + this.on(DONE, opt.ondone) + } else { + this.on(DONE, () => { + this.emit('prefinish') + this.emit('finish') + this.emit('end') + }) + } + + this.strict = !!opt.strict + this.maxMetaEntrySize = opt.maxMetaEntrySize || maxMetaEntrySize + this.filter = typeof opt.filter === 'function' ? opt.filter : noop + // Unlike gzip, brotli doesn't have any magic bytes to identify it + // Users need to explicitly tell us they're extracting a brotli file + // Or we infer from the file extension + const isTBR = + opt.file && + (opt.file.endsWith('.tar.br') || opt.file.endsWith('.tbr')) + // if it's a tbr file it MIGHT be brotli, but we don't know until + // we look at it and verify it's not a valid tar file. + this.brotli = + !opt.gzip && opt.brotli !== undefined + ? opt.brotli + : isTBR + ? undefined + : false + + // have to set this so that streams are ok piping into it + this.on('end', () => this[CLOSESTREAM]()) + + if (typeof opt.onwarn === 'function') { + this.on('warn', opt.onwarn) + } + if (typeof opt.onentry === 'function') { + this.on('entry', opt.onentry) + } + } + + warn( + code: string, + message: string | Error, + data: WarnData = {}, + ): void { + warnMethod(this, code, message, data) + } + + [CONSUMEHEADER](chunk: Buffer, position: number) { + if (this[SAW_VALID_ENTRY] === null) { + this[SAW_VALID_ENTRY] = false + } + let header + try { + header = new Header(chunk, position, this[EX], this[GEX]) + } catch (er) { + return this.warn('TAR_ENTRY_INVALID', er as Error) + } + + if (header.nullBlock) { + if (this[SAW_NULL_BLOCK]) { + this[SAW_EOF] = true + // ending an archive with no entries. pointless, but legal. + if (this[STATE] === 'begin') { + this[STATE] = 'header' + } + this[EMIT]('eof') + } else { + this[SAW_NULL_BLOCK] = true + this[EMIT]('nullBlock') + } + } else { + this[SAW_NULL_BLOCK] = false + if (!header.cksumValid) { + this.warn('TAR_ENTRY_INVALID', 'checksum failure', { header }) + } else if (!header.path) { + this.warn('TAR_ENTRY_INVALID', 'path is required', { header }) + } else { + const type = header.type + if (/^(Symbolic)?Link$/.test(type) && !header.linkpath) { + this.warn('TAR_ENTRY_INVALID', 'linkpath required', { + header, + }) + } else if ( + !/^(Symbolic)?Link$/.test(type) && + header.linkpath + ) { + this.warn('TAR_ENTRY_INVALID', 'linkpath forbidden', { + header, + }) + } else { + const entry = (this[WRITEENTRY] = new ReadEntry( + header, + this[EX], + this[GEX], + )) + + // we do this for meta & ignored entries as well, because they + // are still valid tar, or else we wouldn't know to ignore them + if (!this[SAW_VALID_ENTRY]) { + if (entry.remain) { + // this might be the one! + const onend = () => { + if (!entry.invalid) { + this[SAW_VALID_ENTRY] = true + } + } + entry.on('end', onend) + } else { + this[SAW_VALID_ENTRY] = true + } + } + + if (entry.meta) { + if (entry.size > this.maxMetaEntrySize) { + entry.ignore = true + this[EMIT]('ignoredEntry', entry) + this[STATE] = 'ignore' + entry.resume() + } else if (entry.size > 0) { + this[META] = '' + entry.on('data', c => (this[META] += c)) + this[STATE] = 'meta' + } + } else { + this[EX] = undefined + entry.ignore = + entry.ignore || !this.filter(entry.path, entry) + + if (entry.ignore) { + // probably valid, just not something we care about + this[EMIT]('ignoredEntry', entry) + this[STATE] = entry.remain ? 'ignore' : 'header' + entry.resume() + } else { + if (entry.remain) { + this[STATE] = 'body' + } else { + this[STATE] = 'header' + entry.end() + } + + if (!this[READENTRY]) { + this[QUEUE].push(entry) + this[NEXTENTRY]() + } else { + this[QUEUE].push(entry) + } + } + } + } + } + } + } + + [CLOSESTREAM]() { + queueMicrotask(() => this.emit('close')) + } + + [PROCESSENTRY](entry?: ReadEntry | [string | symbol, any, any]) { + let go = true + + if (!entry) { + this[READENTRY] = undefined + go = false + } else if (Array.isArray(entry)) { + const [ev, ...args]: [string | symbol, any, any] = entry + this.emit(ev, ...args) + } else { + this[READENTRY] = entry + this.emit('entry', entry) + if (!entry.emittedEnd) { + entry.on('end', () => this[NEXTENTRY]()) + go = false + } + } + + return go + } + + [NEXTENTRY]() { + do {} while (this[PROCESSENTRY](this[QUEUE].shift())) + + if (!this[QUEUE].length) { + // At this point, there's nothing in the queue, but we may have an + // entry which is being consumed (readEntry). + // If we don't, then we definitely can handle more data. + // If we do, and either it's flowing, or it has never had any data + // written to it, then it needs more. + // The only other possibility is that it has returned false from a + // write() call, so we wait for the next drain to continue. + const re = this[READENTRY] + const drainNow = !re || re.flowing || re.size === re.remain + if (drainNow) { + if (!this[WRITING]) { + this.emit('drain') + } + } else { + re.once('drain', () => this.emit('drain')) + } + } + } + + [CONSUMEBODY](chunk: Buffer, position: number) { + // write up to but no more than writeEntry.blockRemain + const entry = this[WRITEENTRY] + /* c8 ignore start */ + if (!entry) { + throw new Error('attempt to consume body without entry??') + } + /* c8 ignore stop */ + const br = entry.blockRemain ?? 0 + const c = + br >= chunk.length && position === 0 + ? chunk + : chunk.subarray(position, position + br) + + entry.write(c) + + if (!entry.blockRemain) { + this[STATE] = 'header' + this[WRITEENTRY] = undefined + entry.end() + } + + return c.length + } + + [CONSUMEMETA](chunk: Buffer, position: number) { + const entry = this[WRITEENTRY] + const ret = this[CONSUMEBODY](chunk, position) + + // if we finished, then the entry is reset + if (!this[WRITEENTRY] && entry) { + this[EMITMETA](entry) + } + + return ret + } + + [EMIT](ev: string | symbol, data?: any, extra?: any) { + if (!this[QUEUE].length && !this[READENTRY]) { + this.emit(ev, data, extra) + } else { + this[QUEUE].push([ev, data, extra]) + } + } + + [EMITMETA](entry: ReadEntry) { + this[EMIT]('meta', this[META]) + switch (entry.type) { + case 'ExtendedHeader': + case 'OldExtendedHeader': + this[EX] = Pax.parse(this[META], this[EX], false) + break + + case 'GlobalExtendedHeader': + this[GEX] = Pax.parse(this[META], this[GEX], true) + break + + case 'NextFileHasLongPath': + case 'OldGnuLongPath': { + const ex = this[EX] ?? Object.create(null) + this[EX] = ex + ex.path = this[META].replace(/\0.*/, '') + break + } + + case 'NextFileHasLongLinkpath': { + const ex = this[EX] || Object.create(null) + this[EX] = ex + ex.linkpath = this[META].replace(/\0.*/, '') + break + } + + /* istanbul ignore next */ + default: + throw new Error('unknown meta: ' + entry.type) + } + } + + abort(error: Error) { + this[ABORTED] = true + this.emit('abort', error) + // always throws, even in non-strict mode + this.warn('TAR_ABORT', error, { recoverable: false }) + } + + write(chunk: Buffer) { + if (this[ABORTED]) { + return + } + + // first write, might be gzipped + const needSniff = + this[UNZIP] === undefined || + (this.brotli === undefined && this[UNZIP] === false) + if (needSniff && chunk) { + if (this[BUFFER]) { + chunk = Buffer.concat([this[BUFFER], chunk]) + this[BUFFER] = undefined + } + if (chunk.length < gzipHeader.length) { + this[BUFFER] = chunk + return true + } + + // look for gzip header + for ( + let i = 0; + this[UNZIP] === null && i < gzipHeader.length; + i++ + ) { + if (chunk[i] !== gzipHeader[i]) { + this[UNZIP] = false + } + } + + const maybeBrotli = this.brotli === undefined + if (this[UNZIP] === false && maybeBrotli) { + // read the first header to see if it's a valid tar file. If so, + // we can safely assume that it's not actually brotli, despite the + // .tbr or .tar.br file extension. + // if we ended before getting a full chunk, yes, def brotli + if (chunk.length < 512) { + if (this[ENDED]) { + this.brotli = true + } else { + this[BUFFER] = chunk + return true + } + } else { + // if it's tar, it's pretty reliably not brotli, chances of + // that happening are astronomical. + try { + new Header(chunk.subarray(0, 512)) + this.brotli = false + } catch (_) { + this.brotli = true + } + } + } + + if ( + this[UNZIP] === null || + (this[UNZIP] === false && this.brotli) + ) { + const ended = this[ENDED] + this[ENDED] = false + this[UNZIP] = + this[UNZIP] === undefined + ? new Unzip({}) + : new BrotliDecompress({}) + this[UNZIP].on('data', chunk => this[CONSUMECHUNK](chunk)) + this[UNZIP].on('error', er => this.abort(er as Error)) + this[UNZIP].on('end', () => { + this[ENDED] = true + this[CONSUMECHUNK]() + }) + this[WRITING] = true + const ret = this[UNZIP][ended ? 'end' : 'write'](chunk) + this[WRITING] = false + return ret + } + } + + this[WRITING] = true + if (this[UNZIP]) { + this[UNZIP].write(chunk) + } else { + this[CONSUMECHUNK](chunk) + } + this[WRITING] = false + + // return false if there's a queue, or if the current entry isn't flowing + const ret = this[QUEUE].length + ? false + : this[READENTRY] + ? this[READENTRY].flowing + : true + + // if we have no queue, then that means a clogged READENTRY + if (!ret && !this[QUEUE].length) { + this[READENTRY]?.once('drain', () => this.emit('drain')) + } + + return ret + } + + [BUFFERCONCAT](c: Buffer) { + if (c && !this[ABORTED]) { + this[BUFFER] = this[BUFFER] + ? Buffer.concat([this[BUFFER], c]) + : c + } + } + + [MAYBEEND]() { + if ( + this[ENDED] && + !this[EMITTEDEND] && + !this[ABORTED] && + !this[CONSUMING] + ) { + this[EMITTEDEND] = true + const entry = this[WRITEENTRY] + if (entry && entry.blockRemain) { + // truncated, likely a damaged file + const have = this[BUFFER] ? this[BUFFER].length : 0 + this.warn( + 'TAR_BAD_ARCHIVE', + `Truncated input (needed ${entry.blockRemain} more bytes, only ${have} available)`, + { entry }, + ) + if (this[BUFFER]) { + entry.write(this[BUFFER]) + } + entry.end() + } + this[EMIT](DONE) + } + } + + [CONSUMECHUNK](chunk?: Buffer) { + if (this[CONSUMING] && chunk) { + this[BUFFERCONCAT](chunk) + } else if (!chunk && !this[BUFFER]) { + this[MAYBEEND]() + } else if (chunk) { + this[CONSUMING] = true + if (this[BUFFER]) { + this[BUFFERCONCAT](chunk) + const c = this[BUFFER] + this[BUFFER] = undefined + this[CONSUMECHUNKSUB](c) + } else { + this[CONSUMECHUNKSUB](chunk) + } + + while ( + this[BUFFER] && + (this[BUFFER] as Buffer)?.length >= 512 && + !this[ABORTED] && + !this[SAW_EOF] + ) { + const c = this[BUFFER] + this[BUFFER] = undefined + this[CONSUMECHUNKSUB](c) + } + this[CONSUMING] = false + } + + if (!this[BUFFER] || this[ENDED]) { + this[MAYBEEND]() + } + } + + [CONSUMECHUNKSUB](chunk: Buffer) { + // we know that we are in CONSUMING mode, so anything written goes into + // the buffer. Advance the position and put any remainder in the buffer. + let position = 0 + const length = chunk.length + while ( + position + 512 <= length && + !this[ABORTED] && + !this[SAW_EOF] + ) { + switch (this[STATE]) { + case 'begin': + case 'header': + this[CONSUMEHEADER](chunk, position) + position += 512 + break + + case 'ignore': + case 'body': + position += this[CONSUMEBODY](chunk, position) + break + + case 'meta': + position += this[CONSUMEMETA](chunk, position) + break + + /* istanbul ignore next */ + default: + throw new Error('invalid state: ' + this[STATE]) + } + } + + if (position < length) { + if (this[BUFFER]) { + this[BUFFER] = Buffer.concat([ + chunk.subarray(position), + this[BUFFER], + ]) + } else { + this[BUFFER] = chunk.subarray(position) + } + } + } + + end(chunk?: Buffer) { + if (!this[ABORTED]) { + if (this[UNZIP]) { + if (chunk) this[UNZIP].write(chunk) + this[UNZIP].end() + } else { + this[ENDED] = true + if (this.brotli === undefined) + chunk = chunk || Buffer.alloc(0) + if (chunk) this.write(chunk) + } + } + } +} diff --git a/src/path-reservations.ts b/src/path-reservations.ts new file mode 100644 index 00000000..711e9ee2 --- /dev/null +++ b/src/path-reservations.ts @@ -0,0 +1,192 @@ +// A path exclusive reservation system +// reserve([list, of, paths], fn) +// When the fn is first in line for all its paths, it +// is called with a cb that clears the reservation. +// +// Used by async unpack to avoid clobbering paths in use, +// while still allowing maximal safe parallelization. + +import { join } from 'node:path' +import { normalizeUnicode } from './normalize-unicode.js' +import { stripTrailingSlashes } from './strip-trailing-slashes.js' + +const platform = + process.env.TESTING_TAR_FAKE_PLATFORM || process.platform +const isWindows = platform === 'win32' + +export type Reservation = { + paths: string[] + dirs: Set<string> +} + +export type Handler = (clear: () => void) => void + +// return a set of parent dirs for a given path +// '/a/b/c/d' -> ['/', '/a', '/a/b', '/a/b/c', '/a/b/c/d'] +const getDirs = (path: string) => { + const dirs = path + .split('/') + .slice(0, -1) + .reduce((set: string[], path) => { + const s = set[set.length - 1] + if (s !== undefined) { + path = join(s, path) + } + set.push(path || '/') + return set + }, []) + return dirs +} + +export class PathReservations { + // path => [function or Set] + // A Set object means a directory reservation + // A fn is a direct reservation on that path + #queues = new Map<string, (Handler | Set<Handler>)[]>() + + // fn => {paths:[path,...], dirs:[path, ...]} + #reservations = new Map<Handler, Reservation>() + + // functions currently running + #running = new Set<Handler>() + + reserve(paths: string[], fn: Handler) { + paths = isWindows + ? ['win32 parallelization disabled'] + : paths.map(p => { + // don't need normPath, because we skip this entirely for windows + return stripTrailingSlashes( + join(normalizeUnicode(p)), + ).toLowerCase() + }) + + const dirs = new Set<string>( + paths.map(path => getDirs(path)).reduce((a, b) => a.concat(b)), + ) + this.#reservations.set(fn, { dirs, paths }) + for (const p of paths) { + const q = this.#queues.get(p) + if (!q) { + this.#queues.set(p, [fn]) + } else { + q.push(fn) + } + } + for (const dir of dirs) { + const q = this.#queues.get(dir) + if (!q) { + this.#queues.set(dir, [new Set([fn])]) + } else { + const l = q[q.length - 1] + if (l instanceof Set) { + l.add(fn) + } else { + q.push(new Set([fn])) + } + } + } + return this.#run(fn) + } + + // return the queues for each path the function cares about + // fn => {paths, dirs} + #getQueues(fn: Handler): { + paths: Handler[][] + dirs: (Handler | Set<Handler>)[][] + } { + const res = this.#reservations.get(fn) + /* istanbul ignore if - unpossible */ + if (!res) { + throw new Error('function does not have any path reservations') + } + return { + paths: res.paths.map((path: string) => + this.#queues.get(path), + ) as Handler[][], + dirs: [...res.dirs].map(path => this.#queues.get(path)) as ( + | Handler + | Set<Handler> + )[][], + } + } + + // check if fn is first in line for all its paths, and is + // included in the first set for all its dir queues + check(fn: Handler) { + const { paths, dirs } = this.#getQueues(fn) + return ( + paths.every(q => q && q[0] === fn) && + dirs.every(q => q && q[0] instanceof Set && q[0].has(fn)) + ) + } + + // run the function if it's first in line and not already running + #run(fn: Handler) { + if (this.#running.has(fn) || !this.check(fn)) { + return false + } + this.#running.add(fn) + fn(() => this.#clear(fn)) + return true + } + + #clear(fn: Handler) { + if (!this.#running.has(fn)) { + return false + } + const res = this.#reservations.get(fn) + /* c8 ignore start */ + if (!res) { + throw new Error('invalid reservation') + } + /* c8 ignore stop */ + const { paths, dirs } = res + + const next = new Set<Handler>() + for (const path of paths) { + const q = this.#queues.get(path) + /* c8 ignore start */ + if (!q || q?.[0] !== fn) { + continue + } + /* c8 ignore stop */ + const q0 = q[1] + if (!q0) { + this.#queues.delete(path) + continue + } + q.shift() + if (typeof q0 === 'function') { + next.add(q0) + } else { + for (const f of q0) { + next.add(f) + } + } + } + + for (const dir of dirs) { + const q = this.#queues.get(dir) + const q0 = q?.[0] + if (!(q0 instanceof Set) || !q) continue + if (q0.size === 1 && q.length === 1) { + this.#queues.delete(dir) + continue + } else if (q0.size === 1) { + q.shift() + // next one must be a function, + // or else the Set would've been reused + const n = q[0] + if (typeof n === 'function') { + next.add(n) + } + } else { + q0.delete(fn) + } + } + + this.#running.delete(fn) + next.forEach(fn => this.#run(fn)) + return true + } +} diff --git a/src/pax.ts b/src/pax.ts new file mode 100644 index 00000000..7c542c95 --- /dev/null +++ b/src/pax.ts @@ -0,0 +1,181 @@ +import { basename } from 'node:path' +import { Header, HeaderData } from './header.js' + +export class Pax implements HeaderData { + atime?: Date + mtime?: Date + ctime?: Date + + charset?: string + comment?: string + + gid?: number + uid?: number + + gname?: string + uname?: string + linkpath?: string + dev?: number + ino?: number + nlink?: number + path?: string + size?: number + mode?: number + + global: boolean + + constructor(obj: HeaderData, global: boolean = false) { + this.atime = obj.atime + this.charset = obj.charset + this.comment = obj.comment + this.gid = obj.gid + this.gname = obj.gname + this.linkpath = obj.linkpath + this.mtime = obj.mtime + this.path = obj.path + this.size = obj.size + this.uid = obj.uid + this.uname = obj.uname + this.dev = obj.dev + this.ino = obj.ino + this.nlink = obj.nlink + this.global = global + } + + encode() { + const body = this.encodeBody() + if (body === '') { + return Buffer.allocUnsafe(0) + } + + const bodyLen = Buffer.byteLength(body) + // round up to 512 bytes + // add 512 for header + const bufLen = 512 * Math.ceil(1 + bodyLen / 512) + const buf = Buffer.allocUnsafe(bufLen) + + // 0-fill the header section, it might not hit every field + for (let i = 0; i < 512; i++) { + buf[i] = 0 + } + + new Header({ + // XXX split the path + // then the path should be PaxHeader + basename, but less than 99, + // prepend with the dirname + path: ('PaxHeader/' + basename(this.path || '')).slice(0, 99), + mode: this.mode || 0o644, + uid: this.uid, + gid: this.gid, + size: bodyLen, + mtime: this.mtime, + type: this.global ? 'GlobalExtendedHeader' : 'ExtendedHeader', + linkpath: '', + uname: this.uname || '', + gname: this.gname || '', + devmaj: 0, + devmin: 0, + atime: this.atime, + ctime: this.ctime, + }).encode(buf) + + buf.write(body, 512, bodyLen, 'utf8') + + // null pad after the body + for (let i = bodyLen + 512; i < buf.length; i++) { + buf[i] = 0 + } + + return buf + } + + encodeBody() { + return ( + this.encodeField('path') + + this.encodeField('ctime') + + this.encodeField('atime') + + this.encodeField('dev') + + this.encodeField('ino') + + this.encodeField('nlink') + + this.encodeField('charset') + + this.encodeField('comment') + + this.encodeField('gid') + + this.encodeField('gname') + + this.encodeField('linkpath') + + this.encodeField('mtime') + + this.encodeField('size') + + this.encodeField('uid') + + this.encodeField('uname') + ) + } + + encodeField(field: keyof Pax): string { + if (this[field] === undefined) { + return '' + } + const r = this[field] + const v = r instanceof Date ? r.getTime() / 1000 : r + const s = + ' ' + + (field === 'dev' || field === 'ino' || field === 'nlink' + ? 'SCHILY.' + : '') + + field + + '=' + + v + + '\n' + const byteLen = Buffer.byteLength(s) + // the digits includes the length of the digits in ascii base-10 + // so if it's 9 characters, then adding 1 for the 9 makes it 10 + // which makes it 11 chars. + let digits = Math.floor(Math.log(byteLen) / Math.log(10)) + 1 + if (byteLen + digits >= Math.pow(10, digits)) { + digits += 1 + } + const len = digits + byteLen + return len + s + } + + static parse(str: string, ex?: HeaderData, g: boolean = false) { + return new Pax(merge(parseKV(str), ex), g) + } +} + +const merge = (a: HeaderData, b?: HeaderData) => + b ? Object.assign({}, b, a) : a + +const parseKV = (str: string) => + str + .replace(/\n$/, '') + .split('\n') + .reduce(parseKVLine, Object.create(null)) + +const parseKVLine = (set: Record<string, any>, line: string) => { + const n = parseInt(line, 10) + + // XXX Values with \n in them will fail this. + // Refactor to not be a naive line-by-line parse. + if (n !== Buffer.byteLength(line) + 1) { + return set + } + + line = line.slice((n + ' ').length) + const kv = line.split('=') + const r = kv.shift() + + /* c8 ignore next */ + if (!r) throw new Error('fell of key/value list somehow') + + const k = r.replace(/^SCHILY\.(dev|ino|nlink)/, '$1') + if (!k) { + return set + } + + const v = kv.join('=') + set[k] = /^([A-Z]+\.)?([mac]|birth|creation)time$/.test(k) + ? new Date(Number(v) * 1000) + : /^[0-9]+$/.test(v) + ? +v + : v + return set +} diff --git a/src/read-entry.ts b/src/read-entry.ts new file mode 100644 index 00000000..98260ee7 --- /dev/null +++ b/src/read-entry.ts @@ -0,0 +1,151 @@ +import { Minipass } from 'minipass' +import { Header } from './header.js' +import { normalizeWindowsPath } from './normalize-windows-path.js' +import { Pax } from './pax.js' +import { EntryTypeName } from './types.js' + +export class ReadEntry extends Minipass<Buffer, Buffer> { + extended?: Pax + globalExtended?: Pax + header: Header + startBlockSize: number + blockRemain: number + remain: number + type: EntryTypeName + meta: boolean = false + ignore: boolean = false + path: string + mode?: number + uid?: number + gid?: number + uname?: string + gname?: string + size: number = 0 + mtime?: Date + atime?: Date + ctime?: Date + linkpath?: string + + dev?: number + ino?: number + nlink?: number + invalid: boolean = false + absolute?: string + unsupported: boolean = false + + constructor(header: Header, ex?: Pax, gex?: Pax) { + super({}) + // read entries always start life paused. this is to avoid the + // situation where Minipass's auto-ending empty streams results + // in an entry ending before we're ready for it. + this.pause() + this.extended = ex + this.globalExtended = gex + this.header = header + this.remain = header.size ?? 0 + this.startBlockSize = 512 * Math.ceil(this.remain / 512) + this.blockRemain = this.startBlockSize + this.type = header.type + switch (this.type) { + case 'File': + case 'OldFile': + case 'Link': + case 'SymbolicLink': + case 'CharacterDevice': + case 'BlockDevice': + case 'Directory': + case 'FIFO': + case 'ContiguousFile': + case 'GNUDumpDir': + break + + case 'NextFileHasLongLinkpath': + case 'NextFileHasLongPath': + case 'OldGnuLongPath': + case 'GlobalExtendedHeader': + case 'ExtendedHeader': + case 'OldExtendedHeader': + this.meta = true + break + + // NOTE: gnutar and bsdtar treat unrecognized types as 'File' + // it may be worth doing the same, but with a warning. + default: + this.ignore = true + } + + /* c8 ignore start */ + if (!header.path) { + throw new Error('no path provided for tar.ReadEntry') + } + /* c8 ignore stop */ + + this.path = normalizeWindowsPath(header.path) as string + this.mode = header.mode + if (this.mode) { + this.mode = this.mode & 0o7777 + } + this.uid = header.uid + this.gid = header.gid + this.uname = header.uname + this.gname = header.gname + this.size = this.remain + this.mtime = header.mtime + this.atime = header.atime + this.ctime = header.ctime + this.linkpath = header.linkpath + ? normalizeWindowsPath(header.linkpath) + : undefined + this.uname = header.uname + this.gname = header.gname + + if (ex) { + this.#slurp(ex) + } + if (gex) { + this.#slurp(gex, true) + } + } + + write(data: Buffer) { + const writeLen = data.length + if (writeLen > this.blockRemain) { + throw new Error('writing more to entry than is appropriate') + } + + const r = this.remain + const br = this.blockRemain + this.remain = Math.max(0, r - writeLen) + this.blockRemain = Math.max(0, br - writeLen) + if (this.ignore) { + return true + } + + if (r >= writeLen) { + return super.write(data) + } + + // r < writeLen + return super.write(data.subarray(0, r)) + } + + #slurp(ex: Pax, gex: boolean = false) { + if (ex.path) ex.path = normalizeWindowsPath(ex.path) + if (ex.linkpath) ex.linkpath = normalizeWindowsPath(ex.linkpath) + Object.assign( + this, + Object.fromEntries( + Object.entries(ex).filter(([k, v]) => { + // we slurp in everything except for the path attribute in + // a global extended header, because that's weird. Also, any + // null/undefined values are ignored. + return !( + v === null || + v === undefined || + (k === 'path' && gex) + ) + }), + ), + ) + } +} diff --git a/src/replace.ts b/src/replace.ts new file mode 100644 index 00000000..1d45445d --- /dev/null +++ b/src/replace.ts @@ -0,0 +1,317 @@ +// tar -r +import { WriteStream, WriteStreamSync } from '@isaacs/fs-minipass' +import { Minipass } from 'minipass' +import fs from 'node:fs' +import path from 'node:path' +import { Header } from './header.js' +import { list } from './list.js' +import { + dealias, + isFile, + isSyncFile, + TarOptionsFile, + TarOptionsSyncFile, + TarOptionsWithAliases, + TarOptionsWithAliasesFile, + TarOptionsWithAliasesSyncFile, +} from './options.js' +import { Pack, PackSync } from './pack.js' + +// starting at the head of the file, read a Header +// If the checksum is invalid, that's our position to start writing +// If it is, jump forward by the specified size (round up to 512) +// and try again. +// Write the new Pack stream starting there. + +export function replace( + opt: TarOptionsWithAliasesSyncFile, + files?: string[], +): void +export function replace( + opt: TarOptionsWithAliasesFile, + files?: string[], + cb?: () => any, +): Promise<void> +export function replace( + opt: TarOptionsWithAliasesFile, + cb: () => any, +): Promise<void> +export function replace( + opt_: TarOptionsWithAliases, + files?: string[] | (() => any), + cb?: () => any, +): void | Promise<void> { + const opt = dealias(opt_) + + if (!isFile(opt)) { + throw new TypeError('file is required') + } + + if ( + opt.gzip || + opt.brotli || + opt.file.endsWith('.br') || + opt.file.endsWith('.tbr') + ) { + throw new TypeError('cannot append to compressed archives') + } + + if (!files || !Array.isArray(files) || !files.length) { + throw new TypeError('no files or directories specified') + } + + files = Array.from(files) + + return isSyncFile(opt) + ? replaceSync(opt, files) + : replace_(opt, files, cb) +} + +const replaceSync = (opt: TarOptionsSyncFile, files: string[]) => { + const p = new PackSync(opt) + + let threw = true + let fd + let position + + try { + try { + fd = fs.openSync(opt.file, 'r+') + } catch (er) { + if ((er as NodeJS.ErrnoException)?.code === 'ENOENT') { + fd = fs.openSync(opt.file, 'w+') + } else { + throw er + } + } + + const st = fs.fstatSync(fd) + const headBuf = Buffer.alloc(512) + + POSITION: for ( + position = 0; + position < st.size; + position += 512 + ) { + for (let bufPos = 0, bytes = 0; bufPos < 512; bufPos += bytes) { + bytes = fs.readSync( + fd, + headBuf, + bufPos, + headBuf.length - bufPos, + position + bufPos, + ) + + if ( + position === 0 && + headBuf[0] === 0x1f && + headBuf[1] === 0x8b + ) { + throw new Error('cannot append to compressed archives') + } + + if (!bytes) { + break POSITION + } + } + + const h = new Header(headBuf) + if (!h.cksumValid) { + break + } + const entryBlockSize = 512 * Math.ceil((h.size || 0) / 512) + if (position + entryBlockSize + 512 > st.size) { + break + } + // the 512 for the header we just parsed will be added as well + // also jump ahead all the blocks for the body + position += entryBlockSize + if (opt.mtimeCache && h.mtime) { + opt.mtimeCache.set(String(h.path), h.mtime) + } + } + threw = false + + streamSync(opt, p, position, fd, files) + } finally { + if (threw) { + try { + fs.closeSync(fd as number) + } catch (er) {} + } + } +} + +const streamSync = ( + opt: TarOptionsSyncFile, + p: Pack, + position: number, + fd: number, + files: string[], +) => { + const stream = new WriteStreamSync(opt.file, { + fd: fd, + start: position, + }) + p.pipe(stream as unknown as Minipass.Writable) + addFilesSync(p, files) +} + +const replace_ = ( + opt: TarOptionsFile, + files: string[], + cb?: () => void, +): Promise<void> => { + files = Array.from(files) + const p = new Pack(opt) + + const getPos = ( + fd: number, + size: number, + cb_: (er?: null | Error, pos?: number) => void, + ) => { + const cb = (er?: Error | null, pos?: number) => { + if (er) { + fs.close(fd, _ => cb_(er)) + } else { + cb_(null, pos) + } + } + + let position = 0 + if (size === 0) { + return cb(null, 0) + } + + let bufPos = 0 + const headBuf = Buffer.alloc(512) + const onread = (er?: null | Error, bytes?: number): void => { + if (er || typeof bytes === 'undefined') { + return cb(er) + } + bufPos += bytes + if (bufPos < 512 && bytes) { + return fs.read( + fd, + headBuf, + bufPos, + headBuf.length - bufPos, + position + bufPos, + onread, + ) + } + + if ( + position === 0 && + headBuf[0] === 0x1f && + headBuf[1] === 0x8b + ) { + return cb(new Error('cannot append to compressed archives')) + } + + // truncated header + if (bufPos < 512) { + return cb(null, position) + } + + const h = new Header(headBuf) + if (!h.cksumValid) { + return cb(null, position) + } + + const entryBlockSize = 512 * Math.ceil((h.size ?? 0) / 512) + if (position + entryBlockSize + 512 > size) { + return cb(null, position) + } + + position += entryBlockSize + 512 + if (position >= size) { + return cb(null, position) + } + + if (opt.mtimeCache && h.mtime) { + opt.mtimeCache.set(String(h.path), h.mtime) + } + bufPos = 0 + fs.read(fd, headBuf, 0, 512, position, onread) + } + fs.read(fd, headBuf, 0, 512, position, onread) + } + + const promise = new Promise<void>((resolve, reject) => { + p.on('error', reject) + let flag = 'r+' + const onopen = ( + er?: NodeJS.ErrnoException | null, + fd?: number, + ) => { + if (er && er.code === 'ENOENT' && flag === 'r+') { + flag = 'w+' + return fs.open(opt.file, flag, onopen) + } + + if (er || !fd) { + return reject(er) + } + + fs.fstat(fd, (er, st) => { + if (er) { + return fs.close(fd, () => reject(er)) + } + + getPos(fd, st.size, (er, position) => { + if (er) { + return reject(er) + } + const stream = new WriteStream(opt.file, { + fd: fd, + start: position, + }) + p.pipe(stream as unknown as Minipass.Writable) + stream.on('error', reject) + stream.on('close', resolve) + addFilesAsync(p, files) + }) + }) + } + fs.open(opt.file, flag, onopen) + }) + + return cb ? promise.then(cb, cb) : promise +} + +const addFilesSync = (p: Pack, files: string[]) => { + files.forEach(file => { + if (file.charAt(0) === '@') { + list({ + file: path.resolve(p.cwd, file.slice(1)), + sync: true, + noResume: true, + onentry: entry => p.add(entry), + }) + } else { + p.add(file) + } + }) + p.end() +} + +const addFilesAsync = async ( + p: Pack, + files: string[], + i = 0, +): Promise<void> => { + for (; i < files.length; i++) { + const file = String(files[i]) + if (file.charAt(0) === '@') { + return list({ + file: path.resolve(String(p.cwd), file.slice(1)), + noResume: true, + onentry: entry => p.add(entry), + }).then(_ => addFilesAsync(p, files)) + } else { + p.add(file) + } + } + p.end() +} diff --git a/src/strip-absolute-path.ts b/src/strip-absolute-path.ts new file mode 100644 index 00000000..f127e329 --- /dev/null +++ b/src/strip-absolute-path.ts @@ -0,0 +1,27 @@ +// unix absolute paths are also absolute on win32, so we use this for both +import { win32 } from 'node:path' +const { isAbsolute, parse } = win32 + +// returns [root, stripped] +// Note that windows will think that //x/y/z/a has a "root" of //x/y, and in +// those cases, we want to sanitize it to x/y/z/a, not z/a, so we strip / +// explicitly if it's the first character. +// drive-specific relative paths on Windows get their root stripped off even +// though they are not absolute, so `c:../foo` becomes ['c:', '../foo'] +export const stripAbsolutePath = (path: string) => { + let r = '' + + let parsed = parse(path) + while (isAbsolute(path) || parsed.root) { + // windows will think that //x/y/z has a "root" of //x/y/ + // but strip the //?/C:/ off of //?/C:/path + const root = + path.charAt(0) === '/' && path.slice(0, 4) !== '//?/' + ? '/' + : parsed.root + path = path.slice(root.length) + r += root + parsed = parse(path) + } + return [r, path] +} diff --git a/src/strip-trailing-slashes.ts b/src/strip-trailing-slashes.ts new file mode 100644 index 00000000..b2a111ac --- /dev/null +++ b/src/strip-trailing-slashes.ts @@ -0,0 +1,13 @@ +// warning: extremely hot code path. +// This has been meticulously optimized for use +// within npm install on large package trees. +// Do not edit without careful benchmarking. +export const stripTrailingSlashes = (str: string) => { + let i = str.length - 1 + let slashesStart = -1 + while (i > -1 && str.charAt(i) === '/') { + slashesStart = i + i-- + } + return slashesStart === -1 ? str : str.slice(0, slashesStart) +} diff --git a/src/symlink-error.ts b/src/symlink-error.ts new file mode 100644 index 00000000..c237cb94 --- /dev/null +++ b/src/symlink-error.ts @@ -0,0 +1,14 @@ +export class SymlinkError extends Error { + path: string + symlink: string + syscall: 'symlink' = 'symlink' + code: 'TAR_SYMLINK_ERROR' = 'TAR_SYMLINK_ERROR' + constructor (symlink: string, path: string) { + super('Cannot extract through symbolic link') + this.symlink = symlink + this.path = path + } + get name() { + return 'SymlinkError' + } +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..080995a6 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,97 @@ +export const isCode = (c: string): c is EntryTypeCode => + name.has(c as EntryTypeCode) + +export const isName = (c: string): c is EntryTypeName => + code.has(c as EntryTypeName) + +export type EntryTypeCode = + | '0' + | '' + | '1' + | '2' + | '3' + | '4' + | '5' + | '6' + | '7' + | 'g' + | 'x' + | 'A' + | 'D' + | 'I' + | 'K' + | 'L' + | 'M' + | 'N' + | 'S' + | 'V' + | 'X' + +export type EntryTypeName = + | 'File' + | 'OldFile' + | 'Link' + | 'SymbolicLink' + | 'CharacterDevice' + | 'BlockDevice' + | 'Directory' + | 'FIFO' + | 'ContiguousFile' + | 'GlobalExtendedHeader' + | 'ExtendedHeader' + | 'SolarisACL' + | 'GNUDumpDir' + | 'Inode' + | 'NextFileHasLongLinkpath' + | 'NextFileHasLongPath' + | 'ContinuationFile' + | 'OldGnuLongPath' + | 'SparseFile' + | 'TapeVolumeHeader' + | 'OldExtendedHeader' + +// map types from key to human-friendly name +export const name = new Map<EntryTypeCode, EntryTypeName>([ + ['0', 'File'], + // same as File + ['', 'OldFile'], + ['1', 'Link'], + ['2', 'SymbolicLink'], + // Devices and FIFOs aren't fully supported + // they are parsed, but skipped when unpacking + ['3', 'CharacterDevice'], + ['4', 'BlockDevice'], + ['5', 'Directory'], + ['6', 'FIFO'], + // same as File + ['7', 'ContiguousFile'], + // pax headers + ['g', 'GlobalExtendedHeader'], + ['x', 'ExtendedHeader'], + // vendor-specific stuff + // skip + ['A', 'SolarisACL'], + // like 5, but with data, which should be skipped + ['D', 'GNUDumpDir'], + // metadata only, skip + ['I', 'Inode'], + // data = link path of next file + ['K', 'NextFileHasLongLinkpath'], + // data = path of next file + ['L', 'NextFileHasLongPath'], + // skip + ['M', 'ContinuationFile'], + // like L + ['N', 'OldGnuLongPath'], + // skip + ['S', 'SparseFile'], + // skip + ['V', 'TapeVolumeHeader'], + // like x + ['X', 'OldExtendedHeader'], +]) + +// map the other direction +export const code = new Map<EntryTypeName, EntryTypeCode>( + Array.from(name).map(kv => [kv[1], kv[0]]), +) diff --git a/src/unpack.ts b/src/unpack.ts new file mode 100644 index 00000000..064bbcf9 --- /dev/null +++ b/src/unpack.ts @@ -0,0 +1,1101 @@ +// the PEND/UNPEND stuff tracks whether we're ready to emit end/close yet. +// but the path reservations are required to avoid race conditions where +// parallelized unpack ops may mess with one another, due to dependencies +// (like a Link depending on its target) or destructive operations (like +// clobbering an fs object to create one of a different type.) + +import * as fsm from '@isaacs/fs-minipass' +import assert from 'node:assert' +import { randomBytes } from 'node:crypto' +import fs, { type Stats } from 'node:fs' +import path from 'node:path' +import { getWriteFlag } from './get-write-flag.js' +import { mkdir, MkdirError, mkdirSync } from './mkdir.js' +import { normalizeUnicode } from './normalize-unicode.js' +import { normalizeWindowsPath } from './normalize-windows-path.js' +import { Parser } from './parse.js' +import { stripAbsolutePath } from './strip-absolute-path.js' +import { stripTrailingSlashes } from './strip-trailing-slashes.js' +import * as wc from './winchars.js' + +import { TarOptions } from './options.js' +import { PathReservations } from './path-reservations.js' +import { ReadEntry } from './read-entry.js' +import { WarnData } from './warn-method.js' + +const ONENTRY = Symbol('onEntry') +const CHECKFS = Symbol('checkFs') +const CHECKFS2 = Symbol('checkFs2') +const PRUNECACHE = Symbol('pruneCache') +const ISREUSABLE = Symbol('isReusable') +const MAKEFS = Symbol('makeFs') +const FILE = Symbol('file') +const DIRECTORY = Symbol('directory') +const LINK = Symbol('link') +const SYMLINK = Symbol('symlink') +const HARDLINK = Symbol('hardlink') +const UNSUPPORTED = Symbol('unsupported') +const CHECKPATH = Symbol('checkPath') +const MKDIR = Symbol('mkdir') +const ONERROR = Symbol('onError') +const PENDING = Symbol('pending') +const PEND = Symbol('pend') +const UNPEND = Symbol('unpend') +const ENDED = Symbol('ended') +const MAYBECLOSE = Symbol('maybeClose') +const SKIP = Symbol('skip') +const DOCHOWN = Symbol('doChown') +const UID = Symbol('uid') +const GID = Symbol('gid') +const CHECKED_CWD = Symbol('checkedCwd') +const platform = + process.env.TESTING_TAR_FAKE_PLATFORM || process.platform +const isWindows = platform === 'win32' +const DEFAULT_MAX_DEPTH = 1024 + +// Unlinks on Windows are not atomic. +// +// This means that if you have a file entry, followed by another +// file entry with an identical name, and you cannot re-use the file +// (because it's a hardlink, or because unlink:true is set, or it's +// Windows, which does not have useful nlink values), then the unlink +// will be committed to the disk AFTER the new file has been written +// over the old one, deleting the new file. +// +// To work around this, on Windows systems, we rename the file and then +// delete the renamed file. It's a sloppy kludge, but frankly, I do not +// know of a better way to do this, given windows' non-atomic unlink +// semantics. +// +// See: https://github.com/npm/node-tar/issues/183 +/* istanbul ignore next */ +const unlinkFile = ( + path: string, + cb: (er?: Error | null) => void, +) => { + if (!isWindows) { + return fs.unlink(path, cb) + } + + const name = path + '.DELETE.' + randomBytes(16).toString('hex') + fs.rename(path, name, er => { + if (er) { + return cb(er) + } + fs.unlink(name, cb) + }) +} + +/* istanbul ignore next */ +const unlinkFileSync = (path: string) => { + if (!isWindows) { + return fs.unlinkSync(path) + } + + const name = path + '.DELETE.' + randomBytes(16).toString('hex') + fs.renameSync(path, name) + fs.unlinkSync(name) +} + +// this.gid, entry.gid, this.processUid +const uint32 = ( + a: number | undefined, + b: number | undefined, + c: number | undefined, +) => + a !== undefined && a === a >>> 0 + ? a + : b !== undefined && b === b >>> 0 + ? b + : c + +// clear the cache if it's a case-insensitive unicode-squashing match. +// we can't know if the current file system is case-sensitive or supports +// unicode fully, so we check for similarity on the maximally compatible +// representation. Err on the side of pruning, since all it's doing is +// preventing lstats, and it's not the end of the world if we get a false +// positive. +// Note that on windows, we always drop the entire cache whenever a +// symbolic link is encountered, because 8.3 filenames are impossible +// to reason about, and collisions are hazards rather than just failures. +const cacheKeyNormalize = (path: string) => + stripTrailingSlashes( + normalizeWindowsPath(normalizeUnicode(path)), + ).toLowerCase() + +// remove all cache entries matching ${abs}/** +const pruneCache = (cache: Map<string, boolean>, abs: string) => { + abs = cacheKeyNormalize(abs) + for (const path of cache.keys()) { + const pnorm = cacheKeyNormalize(path) + if (pnorm === abs || pnorm.indexOf(abs + '/') === 0) { + cache.delete(path) + } + } +} + +const dropCache = (cache: Map<string, boolean>) => { + for (const key of cache.keys()) { + cache.delete(key) + } +} + +export class Unpack extends Parser { + [ENDED]: boolean = false; + [CHECKED_CWD]: boolean = false; + [PENDING]: number = 0 + + reservations: PathReservations = new PathReservations() + transform?: TarOptions['transform'] + writable: true = true + readable: false = false + dirCache: Exclude<TarOptions['dirCache'], undefined> + uid?: number + gid?: number + setOwner: boolean + preserveOwner: boolean + processGid?: number + processUid?: number + maxDepth: number + forceChown: boolean + win32: boolean + newer: boolean + keep: boolean + noMtime: boolean + preservePaths: boolean + unlink: boolean + cwd: string + strip: number + processUmask: number + umask: number + dmode: number + fmode: number + noChmod: boolean + + constructor(opt: TarOptions = {}) { + opt.ondone = () => { + this[ENDED] = true + this[MAYBECLOSE]() + } + + super(opt) + + this.transform = opt.transform + + this.dirCache = opt.dirCache || new Map() + this.noChmod = !!opt.noChmod + + if (typeof opt.uid === 'number' || typeof opt.gid === 'number') { + // need both or neither + if ( + typeof opt.uid !== 'number' || + typeof opt.gid !== 'number' + ) { + throw new TypeError( + 'cannot set owner without number uid and gid', + ) + } + if (opt.preserveOwner) { + throw new TypeError( + 'cannot preserve owner in archive and also set owner explicitly', + ) + } + this.uid = opt.uid + this.gid = opt.gid + this.setOwner = true + } else { + this.uid = undefined + this.gid = undefined + this.setOwner = false + } + + // default true for root + if ( + opt.preserveOwner === undefined && + typeof opt.uid !== 'number' + ) { + this.preserveOwner = !!( + process.getuid && process.getuid() === 0 + ) + } else { + this.preserveOwner = !!opt.preserveOwner + } + + this.processUid = + (this.preserveOwner || this.setOwner) && process.getuid + ? process.getuid() + : undefined + this.processGid = + (this.preserveOwner || this.setOwner) && process.getgid + ? process.getgid() + : undefined + + // prevent excessively deep nesting of subfolders + // set to `Infinity` to remove this restriction + this.maxDepth = + typeof opt.maxDepth === 'number' + ? opt.maxDepth + : DEFAULT_MAX_DEPTH + + // mostly just for testing, but useful in some cases. + // Forcibly trigger a chown on every entry, no matter what + this.forceChown = opt.forceChown === true + + // turn ><?| in filenames into 0xf000-higher encoded forms + this.win32 = !!opt.win32 || isWindows + + // do not unpack over files that are newer than what's in the archive + this.newer = !!opt.newer + + // do not unpack over ANY files + this.keep = !!opt.keep + + // do not set mtime/atime of extracted entries + this.noMtime = !!opt.noMtime + + // allow .., absolute path entries, and unpacking through symlinks + // without this, warn and skip .., relativize absolutes, and error + // on symlinks in extraction path + this.preservePaths = !!opt.preservePaths + + // unlink files and links before writing. This breaks existing hard + // links, and removes symlink directories rather than erroring + this.unlink = !!opt.unlink + + this.cwd = normalizeWindowsPath( + path.resolve(opt.cwd || process.cwd()), + ) + this.strip = Number(opt.strip) || 0 + // if we're not chmodding, then we don't need the process umask + this.processUmask = opt.noChmod ? 0 : process.umask() + this.umask = + typeof opt.umask === 'number' ? opt.umask : this.processUmask + + // default mode for dirs created as parents + this.dmode = opt.dmode || 0o0777 & ~this.umask + this.fmode = opt.fmode || 0o0666 & ~this.umask + + this.on('entry', entry => this[ONENTRY](entry)) + } + + // a bad or damaged archive is a warning for Parser, but an error + // when extracting. Mark those errors as unrecoverable, because + // the Unpack contract cannot be met. + warn(code: string, msg: string | Error, data: WarnData = {}) { + if (code === 'TAR_BAD_ARCHIVE' || code === 'TAR_ABORT') { + data.recoverable = false + } + return super.warn(code, msg, data) + } + + [MAYBECLOSE]() { + if (this[ENDED] && this[PENDING] === 0) { + this.emit('prefinish') + this.emit('finish') + this.emit('end') + } + } + + [CHECKPATH](entry: ReadEntry) { + const p = normalizeWindowsPath(entry.path) + const parts = p.split('/') + + if (this.strip) { + if (parts.length < this.strip) { + return false + } + if (entry.type === 'Link') { + const linkparts = normalizeWindowsPath( + String(entry.linkpath), + ).split('/') + if (linkparts.length >= this.strip) { + entry.linkpath = linkparts.slice(this.strip).join('/') + } else { + return false + } + } + parts.splice(0, this.strip) + entry.path = parts.join('/') + } + + if (isFinite(this.maxDepth) && parts.length > this.maxDepth) { + this.warn('TAR_ENTRY_ERROR', 'path excessively deep', { + entry, + path: p, + depth: parts.length, + maxDepth: this.maxDepth, + }) + return false + } + + if (!this.preservePaths) { + if ( + parts.includes('..') || + (isWindows && /^[a-z]:\.\.$/i.test(parts[0] ?? '')) + ) { + this.warn('TAR_ENTRY_ERROR', `path contains '..'`, { + entry, + path: p, + }) + return false + } + + // strip off the root + const [root, stripped] = stripAbsolutePath(p) + if (root) { + entry.path = String(stripped) + this.warn( + 'TAR_ENTRY_INFO', + `stripping ${root} from absolute path`, + { + entry, + path: p, + }, + ) + } + } + + if (path.isAbsolute(entry.path)) { + entry.absolute = normalizeWindowsPath(path.resolve(entry.path)) + } else { + entry.absolute = normalizeWindowsPath( + path.resolve(this.cwd, entry.path), + ) + } + + // if we somehow ended up with a path that escapes the cwd, and we are + // not in preservePaths mode, then something is fishy! This should have + // been prevented above, so ignore this for coverage. + /* istanbul ignore if - defense in depth */ + if ( + !this.preservePaths && + typeof entry.absolute === 'string' && + entry.absolute.indexOf(this.cwd + '/') !== 0 && + entry.absolute !== this.cwd + ) { + this.warn('TAR_ENTRY_ERROR', 'path escaped extraction target', { + entry, + path: normalizeWindowsPath(entry.path), + resolvedPath: entry.absolute, + cwd: this.cwd, + }) + return false + } + + // an archive can set properties on the extraction directory, but it + // may not replace the cwd with a different kind of thing entirely. + if ( + entry.absolute === this.cwd && + entry.type !== 'Directory' && + entry.type !== 'GNUDumpDir' + ) { + return false + } + + // only encode : chars that aren't drive letter indicators + if (this.win32) { + const { root: aRoot } = path.win32.parse(String(entry.absolute)) + entry.absolute = + aRoot + wc.encode(String(entry.absolute).slice(aRoot.length)) + const { root: pRoot } = path.win32.parse(entry.path) + entry.path = pRoot + wc.encode(entry.path.slice(pRoot.length)) + } + + return true + } + + [ONENTRY](entry: ReadEntry) { + if (!this[CHECKPATH](entry)) { + return entry.resume() + } + + assert.equal(typeof entry.absolute, 'string') + + switch (entry.type) { + case 'Directory': + case 'GNUDumpDir': + if (entry.mode) { + entry.mode = entry.mode | 0o700 + } + + // eslint-disable-next-line no-fallthrough + case 'File': + case 'OldFile': + case 'ContiguousFile': + case 'Link': + case 'SymbolicLink': + return this[CHECKFS](entry) + + case 'CharacterDevice': + case 'BlockDevice': + case 'FIFO': + default: + return this[UNSUPPORTED](entry) + } + } + + [ONERROR](er: Error, entry: ReadEntry) { + // Cwd has to exist, or else nothing works. That's serious. + // Other errors are warnings, which raise the error in strict + // mode, but otherwise continue on. + if (er.name === 'CwdError') { + this.emit('error', er) + } else { + this.warn('TAR_ENTRY_ERROR', er, { entry }) + this[UNPEND]() + entry.resume() + } + } + + [MKDIR]( + dir: string, + mode: number, + cb: (er?: null | MkdirError, made?: string) => void, + ) { + mkdir( + normalizeWindowsPath(dir), + { + uid: this.uid, + gid: this.gid, + processUid: this.processUid, + processGid: this.processGid, + umask: this.processUmask, + preserve: this.preservePaths, + unlink: this.unlink, + cache: this.dirCache, + cwd: this.cwd, + mode: mode, + noChmod: this.noChmod, + }, + cb, + ) + } + + [DOCHOWN](entry: ReadEntry) { + // in preserve owner mode, chown if the entry doesn't match process + // in set owner mode, chown if setting doesn't match process + return ( + this.forceChown || + (this.preserveOwner && + ((typeof entry.uid === 'number' && + entry.uid !== this.processUid) || + (typeof entry.gid === 'number' && + entry.gid !== this.processGid))) || + (typeof this.uid === 'number' && + this.uid !== this.processUid) || + (typeof this.gid === 'number' && this.gid !== this.processGid) + ) + } + + [UID](entry: ReadEntry) { + return uint32(this.uid, entry.uid, this.processUid) + } + + [GID](entry: ReadEntry) { + return uint32(this.gid, entry.gid, this.processGid) + } + + [FILE](entry: ReadEntry, fullyDone: () => void) { + const mode = + typeof entry.mode === 'number' + ? entry.mode & 0o7777 + : this.fmode + const stream = new fsm.WriteStream(String(entry.absolute), { + // slight lie, but it can be numeric flags + flags: getWriteFlag(entry.size) as string, + mode: mode, + autoClose: false, + }) + stream.on('error', (er: Error) => { + if (stream.fd) { + fs.close(stream.fd, () => {}) + } + + // flush all the data out so that we aren't left hanging + // if the error wasn't actually fatal. otherwise the parse + // is blocked, and we never proceed. + stream.write = () => true + this[ONERROR](er, entry) + fullyDone() + }) + + let actions = 1 + const done = (er?: null | Error) => { + if (er) { + /* istanbul ignore else - we should always have a fd by now */ + if (stream.fd) { + fs.close(stream.fd, () => {}) + } + + this[ONERROR](er, entry) + fullyDone() + return + } + + if (--actions === 0) { + if (stream.fd !== undefined) { + fs.close(stream.fd, er => { + if (er) { + this[ONERROR](er, entry) + } else { + this[UNPEND]() + } + fullyDone() + }) + } + } + } + + stream.on('finish', () => { + // if futimes fails, try utimes + // if utimes fails, fail with the original error + // same for fchown/chown + const abs = String(entry.absolute) + const fd = stream.fd + + if (typeof fd === 'number' && entry.mtime && !this.noMtime) { + actions++ + const atime = entry.atime || new Date() + const mtime = entry.mtime + fs.futimes(fd, atime, mtime, er => + er + ? fs.utimes(abs, atime, mtime, er2 => done(er2 && er)) + : done(), + ) + } + + if (typeof fd === 'number' && this[DOCHOWN](entry)) { + actions++ + const uid = this[UID](entry) + const gid = this[GID](entry) + if (typeof uid === 'number' && typeof gid === 'number') { + fs.fchown(fd, uid, gid, er => + er + ? fs.chown(abs, uid, gid, er2 => done(er2 && er)) + : done(), + ) + } + } + + done() + }) + + const tx = this.transform ? this.transform(entry) || entry : entry + if (tx !== entry) { + tx.on('error', (er: Error) => { + this[ONERROR](er, entry) + fullyDone() + }) + entry.pipe(tx) + } + tx.pipe(stream) + } + + [DIRECTORY](entry: ReadEntry, fullyDone: () => void) { + const mode = + typeof entry.mode === 'number' + ? entry.mode & 0o7777 + : this.dmode + this[MKDIR](String(entry.absolute), mode, er => { + if (er) { + this[ONERROR](er, entry) + fullyDone() + return + } + + let actions = 1 + const done = () => { + if (--actions === 0) { + fullyDone() + this[UNPEND]() + entry.resume() + } + } + + if (entry.mtime && !this.noMtime) { + actions++ + fs.utimes( + String(entry.absolute), + entry.atime || new Date(), + entry.mtime, + done, + ) + } + + if (this[DOCHOWN](entry)) { + actions++ + fs.chown( + String(entry.absolute), + Number(this[UID](entry)), + Number(this[GID](entry)), + done, + ) + } + + done() + }) + } + + [UNSUPPORTED](entry: ReadEntry) { + entry.unsupported = true + this.warn( + 'TAR_ENTRY_UNSUPPORTED', + `unsupported entry type: ${entry.type}`, + { entry }, + ) + entry.resume() + } + + [SYMLINK](entry: ReadEntry, done: () => void) { + this[LINK](entry, String(entry.linkpath), 'symlink', done) + } + + [HARDLINK](entry: ReadEntry, done: () => void) { + const linkpath = normalizeWindowsPath( + path.resolve(this.cwd, String(entry.linkpath)), + ) + this[LINK](entry, linkpath, 'link', done) + } + + [PEND]() { + this[PENDING]++ + } + + [UNPEND]() { + this[PENDING]-- + this[MAYBECLOSE]() + } + + [SKIP](entry: ReadEntry) { + this[UNPEND]() + entry.resume() + } + + // Check if we can reuse an existing filesystem entry safely and + // overwrite it, rather than unlinking and recreating + // Windows doesn't report a useful nlink, so we just never reuse entries + [ISREUSABLE](entry: ReadEntry, st: Stats) { + return ( + entry.type === 'File' && + !this.unlink && + st.isFile() && + st.nlink <= 1 && + !isWindows + ) + } + + // check if a thing is there, and if so, try to clobber it + [CHECKFS](entry: ReadEntry) { + this[PEND]() + const paths = [entry.path] + if (entry.linkpath) { + paths.push(entry.linkpath) + } + this.reservations.reserve(paths, done => + this[CHECKFS2](entry, done), + ) + } + + [PRUNECACHE](entry: ReadEntry) { + // if we are not creating a directory, and the path is in the dirCache, + // then that means we are about to delete the directory we created + // previously, and it is no longer going to be a directory, and neither + // is any of its children. + // If a symbolic link is encountered, all bets are off. There is no + // reasonable way to sanitize the cache in such a way we will be able to + // avoid having filesystem collisions. If this happens with a non-symlink + // entry, it'll just fail to unpack, but a symlink to a directory, using an + // 8.3 shortname or certain unicode attacks, can evade detection and lead + // to arbitrary writes to anywhere on the system. + if (entry.type === 'SymbolicLink') { + dropCache(this.dirCache) + } else if (entry.type !== 'Directory') { + pruneCache(this.dirCache, String(entry.absolute)) + } + } + + [CHECKFS2](entry: ReadEntry, fullyDone: (er?: Error) => void) { + this[PRUNECACHE](entry) + + const done = (er?: Error) => { + this[PRUNECACHE](entry) + fullyDone(er) + } + + const checkCwd = () => { + this[MKDIR](this.cwd, this.dmode, er => { + if (er) { + this[ONERROR](er, entry) + done() + return + } + this[CHECKED_CWD] = true + start() + }) + } + + const start = () => { + if (entry.absolute !== this.cwd) { + const parent = normalizeWindowsPath( + path.dirname(String(entry.absolute)), + ) + if (parent !== this.cwd) { + return this[MKDIR](parent, this.dmode, er => { + if (er) { + this[ONERROR](er, entry) + done() + return + } + afterMakeParent() + }) + } + } + afterMakeParent() + } + + const afterMakeParent = () => { + fs.lstat(String(entry.absolute), (lstatEr, st) => { + if ( + st && + (this.keep || + (this.newer && st.mtime > (entry.mtime ?? st.mtime))) + ) { + this[SKIP](entry) + done() + return + } + if (lstatEr || this[ISREUSABLE](entry, st)) { + return this[MAKEFS](null, entry, done) + } + + if (st.isDirectory()) { + if (entry.type === 'Directory') { + const needChmod = + !this.noChmod && + entry.mode && + (st.mode & 0o7777) !== entry.mode + const afterChmod = (er?: Error | null | undefined) => + this[MAKEFS](er ?? null, entry, done) + if (!needChmod) { + return afterChmod() + } + return fs.chmod( + String(entry.absolute), + Number(entry.mode), + afterChmod, + ) + } + // Not a dir entry, have to remove it. + // NB: the only way to end up with an entry that is the cwd + // itself, in such a way that == does not detect, is a + // tricky windows absolute path with UNC or 8.3 parts (and + // preservePaths:true, or else it will have been stripped). + // In that case, the user has opted out of path protections + // explicitly, so if they blow away the cwd, c'est la vie. + if (entry.absolute !== this.cwd) { + return fs.rmdir( + String(entry.absolute), + (er?: null | Error) => + this[MAKEFS](er ?? null, entry, done), + ) + } + } + + // not a dir, and not reusable + // don't remove if the cwd, we want that error + if (entry.absolute === this.cwd) { + return this[MAKEFS](null, entry, done) + } + + unlinkFile(String(entry.absolute), er => + this[MAKEFS](er ?? null, entry, done), + ) + }) + } + + if (this[CHECKED_CWD]) { + start() + } else { + checkCwd() + } + } + + [MAKEFS]( + er: null | undefined | Error, + entry: ReadEntry, + done: () => void, + ) { + if (er) { + this[ONERROR](er, entry) + done() + return + } + + switch (entry.type) { + case 'File': + case 'OldFile': + case 'ContiguousFile': + return this[FILE](entry, done) + + case 'Link': + return this[HARDLINK](entry, done) + + case 'SymbolicLink': + return this[SYMLINK](entry, done) + + case 'Directory': + case 'GNUDumpDir': + return this[DIRECTORY](entry, done) + } + } + + [LINK]( + entry: ReadEntry, + linkpath: string, + link: 'link' | 'symlink', + done: () => void, + ) { + // XXX: get the type ('symlink' or 'junction') for windows + fs[link](linkpath, String(entry.absolute), er => { + if (er) { + this[ONERROR](er, entry) + } else { + this[UNPEND]() + entry.resume() + } + done() + }) + } +} + +const callSync = (fn: () => any) => { + try { + return [null, fn()] + } catch (er) { + return [er, null] + } +} + +export class UnpackSync extends Unpack { + [MAKEFS](er: null | Error | undefined, entry: ReadEntry) { + return super[MAKEFS](er, entry, () => {}) + } + + [CHECKFS](entry: ReadEntry) { + this[PRUNECACHE](entry) + + if (!this[CHECKED_CWD]) { + const er = this[MKDIR](this.cwd, this.dmode) + if (er) { + return this[ONERROR](er as Error, entry) + } + this[CHECKED_CWD] = true + } + + // don't bother to make the parent if the current entry is the cwd, + // we've already checked it. + if (entry.absolute !== this.cwd) { + const parent = normalizeWindowsPath( + path.dirname(String(entry.absolute)), + ) + if (parent !== this.cwd) { + const mkParent = this[MKDIR](parent, this.dmode) + if (mkParent) { + return this[ONERROR](mkParent as Error, entry) + } + } + } + + const [lstatEr, st] = callSync(() => + fs.lstatSync(String(entry.absolute)), + ) + if ( + st && + (this.keep || + (this.newer && st.mtime > (entry.mtime ?? st.mtime))) + ) { + return this[SKIP](entry) + } + + if (lstatEr || this[ISREUSABLE](entry, st)) { + return this[MAKEFS](null, entry) + } + + if (st.isDirectory()) { + if (entry.type === 'Directory') { + const needChmod = + !this.noChmod && + entry.mode && + (st.mode & 0o7777) !== entry.mode + const [er] = needChmod + ? callSync(() => { + fs.chmodSync(String(entry.absolute), Number(entry.mode)) + }) + : [] + return this[MAKEFS](er, entry) + } + // not a dir entry, have to remove it + const [er] = callSync(() => + fs.rmdirSync(String(entry.absolute)), + ) + this[MAKEFS](er, entry) + } + + // not a dir, and not reusable. + // don't remove if it's the cwd, since we want that error. + const [er] = + entry.absolute === this.cwd + ? [] + : callSync(() => unlinkFileSync(String(entry.absolute))) + this[MAKEFS](er, entry) + } + + [FILE](entry: ReadEntry, done: () => void) { + const mode = + typeof entry.mode === 'number' + ? entry.mode & 0o7777 + : this.fmode + + const oner = (er?: null | Error | undefined) => { + let closeError + try { + fs.closeSync(fd) + } catch (e) { + closeError = e + } + if (er || closeError) { + this[ONERROR]((er as Error) || closeError, entry) + } + done() + } + + let fd: number + try { + fd = fs.openSync( + String(entry.absolute), + getWriteFlag(entry.size), + mode, + ) + } catch (er) { + return oner(er as Error) + } + const tx = this.transform ? this.transform(entry) || entry : entry + if (tx !== entry) { + tx.on('error', (er: Error) => this[ONERROR](er, entry)) + entry.pipe(tx) + } + + tx.on('data', (chunk: Buffer) => { + try { + fs.writeSync(fd, chunk, 0, chunk.length) + } catch (er) { + oner(er as Error) + } + }) + + tx.on('end', () => { + let er = null + // try both, falling futimes back to utimes + // if either fails, handle the first error + if (entry.mtime && !this.noMtime) { + const atime = entry.atime || new Date() + const mtime = entry.mtime + try { + fs.futimesSync(fd, atime, mtime) + } catch (futimeser) { + try { + fs.utimesSync(String(entry.absolute), atime, mtime) + } catch (utimeser) { + er = futimeser + } + } + } + + if (this[DOCHOWN](entry)) { + const uid = this[UID](entry) + const gid = this[GID](entry) + + try { + fs.fchownSync(fd, Number(uid), Number(gid)) + } catch (fchowner) { + try { + fs.chownSync(String(entry.absolute), Number(uid), Number(gid)) + } catch (chowner) { + er = er || fchowner + } + } + } + + oner(er as Error) + }) + } + + [DIRECTORY](entry: ReadEntry, done: () => void) { + const mode = + typeof entry.mode === 'number' + ? entry.mode & 0o7777 + : this.dmode + const er = this[MKDIR](String(entry.absolute), mode) + if (er) { + this[ONERROR](er as Error, entry) + done() + return + } + if (entry.mtime && !this.noMtime) { + try { + fs.utimesSync( + String(entry.absolute), + entry.atime || new Date(), + entry.mtime, + ) + } catch (er) {} + } + if (this[DOCHOWN](entry)) { + try { + fs.chownSync( + String(entry.absolute), + Number(this[UID](entry)), + Number(this[GID](entry)), + ) + } catch (er) {} + } + done() + entry.resume() + } + + [MKDIR](dir: string, mode: number) { + try { + return mkdirSync(normalizeWindowsPath(dir), { + uid: this.uid, + gid: this.gid, + processUid: this.processUid, + processGid: this.processGid, + umask: this.processUmask, + preserve: this.preservePaths, + unlink: this.unlink, + cache: this.dirCache, + cwd: this.cwd, + mode: mode, + noChmod: this.noChmod, + }) + } catch (er) { + return er + } + } + + [LINK]( + entry: ReadEntry, + linkpath: string, + link: 'link' | 'symlink', + done: () => void, + ) { + const ls: `${typeof link}Sync` = `${link}Sync` + try { + fs[ls](linkpath, String(entry.absolute)) + done() + entry.resume() + } catch (er) { + return this[ONERROR](er as Error, entry) + } + } +} diff --git a/src/update.ts b/src/update.ts new file mode 100644 index 00000000..a049efd5 --- /dev/null +++ b/src/update.ts @@ -0,0 +1,62 @@ +// tar -u + +import { + dealias, + isFile, + type TarOptionsWithAliases, +} from './options.js' + +import { replace as r } from './replace.js' + +// just call tar.r with the filter and mtimeCache + +export const update = ( + opt_: TarOptionsWithAliases, + files: string[], + cb?: (er?: Error) => any, +) => { + const opt = dealias(opt_) + + if (!isFile(opt)) { + throw new TypeError('file is required') + } + + if ( + opt.gzip || + opt.brotli || + opt.file.endsWith('.br') || + opt.file.endsWith('.tbr') + ) { + throw new TypeError('cannot append to compressed archives') + } + + if (!files || !Array.isArray(files) || !files.length) { + throw new TypeError('no files or directories specified') + } + + files = Array.from(files) + mtimeFilter(opt) + + return r(opt, files, cb) +} + +const mtimeFilter = (opt: TarOptionsWithAliases) => { + const filter = opt.filter + + if (!opt.mtimeCache) { + opt.mtimeCache = new Map() + } + + opt.filter = filter + ? (path, stat) => + filter(path, stat) && + !( + (opt.mtimeCache?.get(path) ?? stat.mtime ?? 0) > + (stat.mtime ?? 0) + ) + : (path, stat) => + !( + (opt.mtimeCache?.get(path) ?? stat.mtime ?? 0) > + (stat.mtime ?? 0) + ) +} diff --git a/src/warn-method.ts b/src/warn-method.ts new file mode 100644 index 00000000..7f2b83e1 --- /dev/null +++ b/src/warn-method.ts @@ -0,0 +1,59 @@ +/** has a warn method */ +export type Warner = { + warn(code: string, message: string | Error, data: any): void + file?: string + cwd?: string + strict?: boolean + + emit( + event: 'warn', + code: string, + message: string, + data?: WarnData, + ): void + emit(event: 'error', error: TarError): void +} + +export type WarnData = { + file?: string + cwd?: string + code?: string + tarCode?: string + recoverable?: boolean + [k: string]: any +} + +export type TarError = Error & WarnData + +export const warnMethod = ( + self: Warner, + code: string, + message: string | Error, + data: WarnData = {}, +) => { + if (self.file) { + data.file = self.file + } + if (self.cwd) { + data.cwd = self.cwd + } + data.code = + (message instanceof Error && + (message as NodeJS.ErrnoException).code) || + code + data.tarCode = code + if (!self.strict && data.recoverable !== false) { + if (message instanceof Error) { + data = Object.assign(message, data) + message = message.message + } + self.emit('warn', code, message, data) + } else if (message instanceof Error) { + self.emit('error', Object.assign(message, data)) + } else { + self.emit( + 'error', + Object.assign(new Error(`${code}: ${message}`), data), + ) + } +} diff --git a/src/winchars.ts b/src/winchars.ts new file mode 100644 index 00000000..b8edeb36 --- /dev/null +++ b/src/winchars.ts @@ -0,0 +1,16 @@ +// When writing files on Windows, translate the characters to their +// 0xf000 higher-encoded versions. + +const raw = ['|', '<', '>', '?', ':'] + +const win = raw.map(char => + String.fromCharCode(0xf000 + char.charCodeAt(0)), +) + +const toWin = new Map(raw.map((char, i) => [char, win[i]])) +const toRaw = new Map(win.map((char, i) => [char, raw[i]])) + +export const encode = (s: string) => + raw.reduce((s, c) => s.split(c).join(toWin.get(c)), s) +export const decode = (s: string) => + win.reduce((s, c) => s.split(c).join(toRaw.get(c)), s) diff --git a/src/write-entry.ts b/src/write-entry.ts new file mode 100644 index 00000000..f9910c6d --- /dev/null +++ b/src/write-entry.ts @@ -0,0 +1,733 @@ +import fs, { type Stats } from 'fs' +import { Minipass } from 'minipass' +import path from 'path' +import { Header } from './header.js' +import { modeFix } from './mode-fix.js' +import { normalizeWindowsPath } from './normalize-windows-path.js' +import { + dealias, + LinkCacheKey, + TarOptions, + TarOptionsWithAliases, +} from './options.js' +import { Pax } from './pax.js' +import { ReadEntry } from './read-entry.js' +import { stripAbsolutePath } from './strip-absolute-path.js' +import { stripTrailingSlashes } from './strip-trailing-slashes.js' +import { EntryTypeName } from './types.js' +import { WarnData, Warner, warnMethod } from './warn-method.js' +import * as winchars from './winchars.js' + +const prefixPath = (path: string, prefix?: string) => { + if (!prefix) { + return normalizeWindowsPath(path) + } + path = normalizeWindowsPath(path).replace(/^\.(\/|$)/, '') + return stripTrailingSlashes(prefix) + '/' + path +} + +const maxReadSize = 16 * 1024 * 1024 + +const PROCESS = Symbol('process') +const FILE = Symbol('file') +const DIRECTORY = Symbol('directory') +const SYMLINK = Symbol('symlink') +const HARDLINK = Symbol('hardlink') +const HEADER = Symbol('header') +const READ = Symbol('read') +const LSTAT = Symbol('lstat') +const ONLSTAT = Symbol('onlstat') +const ONREAD = Symbol('onread') +const ONREADLINK = Symbol('onreadlink') +const OPENFILE = Symbol('openfile') +const ONOPENFILE = Symbol('onopenfile') +const CLOSE = Symbol('close') +const MODE = Symbol('mode') +const AWAITDRAIN = Symbol('awaitDrain') +const ONDRAIN = Symbol('ondrain') +const PREFIX = Symbol('prefix') + +export class WriteEntry extends Minipass<Buffer> implements Warner { + path: string + portable: boolean + myuid: number = (process.getuid && process.getuid()) || 0 + // until node has builtin pwnam functions, this'll have to do + myuser: string = process.env.USER || '' + maxReadSize: number + linkCache: Exclude<TarOptions['linkCache'], undefined> + statCache: Exclude<TarOptions['statCache'], undefined> + preservePaths: boolean + cwd: string + strict: boolean + mtime?: Date + noPax: boolean + noMtime: boolean + prefix?: string + fd?: number + + blockLen: number = 0 + blockRemain: number = 0 + buf?: Buffer + pos: number = 0 + remain: number = 0 + length: number = 0 + offset: number = 0 + + win32: boolean + absolute: string + + header?: Header + type?: EntryTypeName | 'Unsupported' + linkpath?: string + stat?: Stats + /* c8 ignore start */ + + #hadError: boolean = false + + constructor(p: string, opt_: TarOptionsWithAliases = {}) { + const opt = dealias(opt_) + super() + this.path = normalizeWindowsPath(p) + // suppress atime, ctime, uid, gid, uname, gname + this.portable = !!opt.portable + this.maxReadSize = opt.maxReadSize || maxReadSize + this.linkCache = opt.linkCache || new Map() + this.statCache = opt.statCache || new Map() + this.preservePaths = !!opt.preservePaths + this.cwd = normalizeWindowsPath(opt.cwd || process.cwd()) + this.strict = !!opt.strict + this.noPax = !!opt.noPax + this.noMtime = !!opt.noMtime + this.mtime = opt.mtime + this.prefix = opt.prefix + ? normalizeWindowsPath(opt.prefix) + : undefined + + if (typeof opt.onwarn === 'function') { + this.on('warn', opt.onwarn) + } + + let pathWarn = false + if (!this.preservePaths) { + const [root, stripped] = stripAbsolutePath(this.path) + if (root && typeof stripped === 'string') { + this.path = stripped + pathWarn = !!root + } + } + + this.win32 = !!opt.win32 || process.platform === 'win32' + if (this.win32) { + // force the \ to / normalization, since we might not *actually* + // be on windows, but want \ to be considered a path separator. + this.path = winchars.decode(this.path.replace(/\\/g, '/')) + p = p.replace(/\\/g, '/') + } + + this.absolute = normalizeWindowsPath( + opt.absolute || path.resolve(this.cwd, p), + ) + + if (this.path === '') { + this.path = './' + } + + if (pathWarn) { + this.warn( + 'TAR_ENTRY_INFO', + `stripping ${pathWarn} from absolute path`, + { + entry: this, + path: pathWarn + this.path, + }, + ) + } + + const cs = this.statCache.get(this.absolute) + if (cs) { + this[ONLSTAT](cs) + } else { + this[LSTAT]() + } + } + + warn(code: string, message: string | Error, data: WarnData = {}) { + return warnMethod(this, code, message, data) + } + + emit(ev: string, ...data: any[]) { + if (ev === 'error') { + this.#hadError = true + } + return super.emit(ev, ...data) + } + + [LSTAT]() { + fs.lstat(this.absolute, (er, stat) => { + if (er) { + return this.emit('error', er) + } + this[ONLSTAT](stat) + }) + } + + [ONLSTAT](stat: Stats) { + this.statCache.set(this.absolute, stat) + this.stat = stat + if (!stat.isFile()) { + stat.size = 0 + } + this.type = getType(stat) + this.emit('stat', stat) + this[PROCESS]() + } + + [PROCESS]() { + switch (this.type) { + case 'File': + return this[FILE]() + case 'Directory': + return this[DIRECTORY]() + case 'SymbolicLink': + return this[SYMLINK]() + // unsupported types are ignored. + default: + return this.end() + } + } + + [MODE](mode: number) { + return modeFix(mode, this.type === 'Directory', this.portable) + } + + [PREFIX](path: string) { + return prefixPath(path, this.prefix) + } + + [HEADER]() { + /* c8 ignore start */ + if (!this.stat) { + throw new Error('cannot write header before stat') + } + /* c8 ignore stop */ + + if (this.type === 'Directory' && this.portable) { + this.noMtime = true + } + + this.header = new Header({ + path: this[PREFIX](this.path), + // only apply the prefix to hard links. + linkpath: + this.type === 'Link' && this.linkpath !== undefined + ? this[PREFIX](this.linkpath) + : this.linkpath, + // only the permissions and setuid/setgid/sticky bitflags + // not the higher-order bits that specify file type + mode: this[MODE](this.stat.mode), + uid: this.portable ? undefined : this.stat.uid, + gid: this.portable ? undefined : this.stat.gid, + size: this.stat.size, + mtime: this.noMtime ? undefined : this.mtime || this.stat.mtime, + type: this.type === 'Unsupported' ? undefined : this.type, + uname: this.portable + ? undefined + : this.stat.uid === this.myuid + ? this.myuser + : '', + atime: this.portable ? undefined : this.stat.atime, + ctime: this.portable ? undefined : this.stat.ctime, + }) + + if (this.header.encode() && !this.noPax) { + super.write( + new Pax({ + atime: this.portable ? undefined : this.header.atime, + ctime: this.portable ? undefined : this.header.ctime, + gid: this.portable ? undefined : this.header.gid, + mtime: this.noMtime + ? undefined + : this.mtime || this.header.mtime, + path: this[PREFIX](this.path), + linkpath: + this.type === 'Link' && this.linkpath !== undefined + ? this[PREFIX](this.linkpath) + : this.linkpath, + size: this.header.size, + uid: this.portable ? undefined : this.header.uid, + uname: this.portable ? undefined : this.header.uname, + dev: this.portable ? undefined : this.stat.dev, + ino: this.portable ? undefined : this.stat.ino, + nlink: this.portable ? undefined : this.stat.nlink, + }).encode(), + ) + } + const block = this.header?.block + /* c8 ignore start */ + if (!block) { + throw new Error('failed to encode header') + } + /* c8 ignore stop */ + super.write(block) + } + + [DIRECTORY]() { + /* c8 ignore start */ + if (!this.stat) { + throw new Error('cannot create directory entry without stat') + } + /* c8 ignore stop */ + if (this.path.slice(-1) !== '/') { + this.path += '/' + } + this.stat.size = 0 + this[HEADER]() + this.end() + } + + [SYMLINK]() { + fs.readlink(this.absolute, (er, linkpath) => { + if (er) { + return this.emit('error', er) + } + this[ONREADLINK](linkpath) + }) + } + + [ONREADLINK](linkpath: string) { + this.linkpath = normalizeWindowsPath(linkpath) + this[HEADER]() + this.end() + } + + [HARDLINK](linkpath: string) { + /* c8 ignore start */ + if (!this.stat) { + throw new Error('cannot create link entry without stat') + } + /* c8 ignore stop */ + this.type = 'Link' + this.linkpath = normalizeWindowsPath( + path.relative(this.cwd, linkpath), + ) + this.stat.size = 0 + this[HEADER]() + this.end() + } + + [FILE]() { + /* c8 ignore start */ + if (!this.stat) { + throw new Error('cannot create file entry without stat') + } + /* c8 ignore stop */ + if (this.stat.nlink > 1) { + const linkKey = + `${this.stat.dev}:${this.stat.ino}` as LinkCacheKey + const linkpath = this.linkCache.get(linkKey) + if (linkpath?.indexOf(this.cwd) === 0) { + return this[HARDLINK](linkpath) + } + this.linkCache.set(linkKey, this.absolute) + } + + this[HEADER]() + if (this.stat.size === 0) { + return this.end() + } + + this[OPENFILE]() + } + + [OPENFILE]() { + fs.open(this.absolute, 'r', (er, fd) => { + if (er) { + return this.emit('error', er) + } + this[ONOPENFILE](fd) + }) + } + + [ONOPENFILE](fd: number) { + this.fd = fd + if (this.#hadError) { + return this[CLOSE]() + } + /* c8 ignore start */ + if (!this.stat) { + throw new Error('should stat before calling onopenfile') + } + /* c8 ignore start */ + + this.blockLen = 512 * Math.ceil(this.stat.size / 512) + this.blockRemain = this.blockLen + const bufLen = Math.min(this.blockLen, this.maxReadSize) + this.buf = Buffer.allocUnsafe(bufLen) + this.offset = 0 + this.pos = 0 + this.remain = this.stat.size + this.length = this.buf.length + this[READ]() + } + + [READ]() { + const { fd, buf, offset, length, pos } = this + if (fd === undefined || buf === undefined) { + throw new Error('cannot read file without first opening') + } + fs.read(fd, buf, offset, length, pos, (er, bytesRead) => { + if (er) { + // ignoring the error from close(2) is a bad practice, but at + // this point we already have an error, don't need another one + return this[CLOSE](() => this.emit('error', er)) + } + this[ONREAD](bytesRead) + }) + } + + [CLOSE](cb: (er?: null | Error | NodeJS.ErrnoException) => any = () => {}) { + if (this.fd !== undefined) fs.close(this.fd, cb) + } + + [ONREAD](bytesRead: number) { + if (bytesRead <= 0 && this.remain > 0) { + const er = Object.assign( + new Error('encountered unexpected EOF'), + { + path: this.absolute, + syscall: 'read', + code: 'EOF', + }, + ) + return this[CLOSE](() => this.emit('error', er)) + } + + if (bytesRead > this.remain) { + const er = Object.assign( + new Error('did not encounter expected EOF'), + { + path: this.absolute, + syscall: 'read', + code: 'EOF', + }, + ) + return this[CLOSE](() => this.emit('error', er)) + } + + /* c8 ignore start */ + if (!this.buf) { + throw new Error('should have created buffer prior to reading') + } + /* c8 ignore stop */ + + // null out the rest of the buffer, if we could fit the block padding + // at the end of this loop, we've incremented bytesRead and this.remain + // to be incremented up to the blockRemain level, as if we had expected + // to get a null-padded file, and read it until the end. then we will + // decrement both remain and blockRemain by bytesRead, and know that we + // reached the expected EOF, without any null buffer to append. + if (bytesRead === this.remain) { + for ( + let i = bytesRead; + i < this.length && bytesRead < this.blockRemain; + i++ + ) { + this.buf[i + this.offset] = 0 + bytesRead++ + this.remain++ + } + } + + const writeBuf = + this.offset === 0 && bytesRead === this.buf.length + ? this.buf + : this.buf.subarray(this.offset, this.offset + bytesRead) + + const flushed = this.write(writeBuf) + if (!flushed) { + this[AWAITDRAIN](() => this[ONDRAIN]()) + } else { + this[ONDRAIN]() + } + } + + [AWAITDRAIN](cb: () => any) { + this.once('drain', cb) + } + + write(writeBuf: Buffer) { + if (this.blockRemain < writeBuf.length) { + const er = Object.assign( + new Error('writing more data than expected'), + { + path: this.absolute, + }, + ) + return this.emit('error', er) + } + this.remain -= writeBuf.length + this.blockRemain -= writeBuf.length + this.pos += writeBuf.length + this.offset += writeBuf.length + return super.write(writeBuf) + } + + [ONDRAIN]() { + if (!this.remain) { + if (this.blockRemain) { + super.write(Buffer.alloc(this.blockRemain)) + } + return this[CLOSE](er => + er ? this.emit('error', er) : this.end(), + ) + } + + /* c8 ignore start */ + if (!this.buf) { + throw new Error('buffer lost somehow in ONDRAIN') + } + /* c8 ignore stop */ + + if (this.offset >= this.length) { + // if we only have a smaller bit left to read, alloc a smaller buffer + // otherwise, keep it the same length it was before. + this.buf = Buffer.allocUnsafe( + Math.min(this.blockRemain, this.buf.length), + ) + this.offset = 0 + } + this.length = this.buf.length - this.offset + this[READ]() + } +} + +export class WriteEntrySync extends WriteEntry implements Warner { + [LSTAT]() { + this[ONLSTAT](fs.lstatSync(this.absolute)) + } + + [SYMLINK]() { + this[ONREADLINK](fs.readlinkSync(this.absolute)) + } + + [OPENFILE]() { + this[ONOPENFILE](fs.openSync(this.absolute, 'r')) + } + + [READ]() { + let threw = true + try { + const { fd, buf, offset, length, pos } = this + /* c8 ignore start */ + if (fd === undefined || buf === undefined) { + throw new Error('fd and buf must be set in READ method') + } + /* c8 ignore stop */ + const bytesRead = fs.readSync(fd, buf, offset, length, pos) + this[ONREAD](bytesRead) + threw = false + } finally { + // ignoring the error from close(2) is a bad practice, but at + // this point we already have an error, don't need another one + if (threw) { + try { + this[CLOSE](() => {}) + } catch (er) {} + } + } + } + + [AWAITDRAIN](cb: () => any) { + cb() + } + + [CLOSE](cb: (er?: null | Error | NodeJS.ErrnoException) => any = () => {}) { + if (this.fd !== undefined) fs.closeSync(this.fd) + cb() + } +} + +export class WriteEntryTar + extends Minipass<Buffer> + implements Warner +{ + blockLen: number = 0 + blockRemain: number = 0 + buf: number = 0 + pos: number = 0 + remain: number = 0 + length: number = 0 + preservePaths: boolean + portable: boolean + strict: boolean + noPax: boolean + noMtime: boolean + readEntry: ReadEntry + type: EntryTypeName + prefix?: string + path: string + mode?: number + uid?: number + gid?: number + uname?: string + gname?: string + header?: Header + mtime?: Date + atime?: Date + ctime?: Date + linkpath?: string + size: number + + warn(code: string, message: string | Error, data: WarnData = {}) { + return warnMethod(this, code, message, data) + } + + constructor( + readEntry: ReadEntry, + opt_: TarOptionsWithAliases = {}, + ) { + const opt = dealias(opt_) + super() + this.preservePaths = !!opt.preservePaths + this.portable = !!opt.portable + this.strict = !!opt.strict + this.noPax = !!opt.noPax + this.noMtime = !!opt.noMtime + + this.readEntry = readEntry + this.type = readEntry.type + if (this.type === 'Directory' && this.portable) { + this.noMtime = true + } + + this.prefix = opt.prefix + + this.path = normalizeWindowsPath(readEntry.path) + this.mode = + readEntry.mode !== undefined + ? this[MODE](readEntry.mode) + : undefined + this.uid = this.portable ? undefined : readEntry.uid + this.gid = this.portable ? undefined : readEntry.gid + this.uname = this.portable ? undefined : readEntry.uname + this.gname = this.portable ? undefined : readEntry.gname + this.size = readEntry.size + this.mtime = this.noMtime + ? undefined + : opt.mtime || readEntry.mtime + this.atime = this.portable ? undefined : readEntry.atime + this.ctime = this.portable ? undefined : readEntry.ctime + this.linkpath = + readEntry.linkpath !== undefined + ? normalizeWindowsPath(readEntry.linkpath) + : undefined + + if (typeof opt.onwarn === 'function') { + this.on('warn', opt.onwarn) + } + + let pathWarn: false | string = false + if (!this.preservePaths) { + const [root, stripped] = stripAbsolutePath(this.path) + if (root && typeof stripped === 'string') { + this.path = stripped + pathWarn = root + } + } + + this.remain = readEntry.size + this.blockRemain = readEntry.startBlockSize + + this.header = new Header({ + path: this[PREFIX](this.path), + linkpath: + this.type === 'Link' && this.linkpath !== undefined + ? this[PREFIX](this.linkpath) + : this.linkpath, + // only the permissions and setuid/setgid/sticky bitflags + // not the higher-order bits that specify file type + mode: this.mode, + uid: this.portable ? undefined : this.uid, + gid: this.portable ? undefined : this.gid, + size: this.size, + mtime: this.noMtime ? undefined : this.mtime, + type: this.type, + uname: this.portable ? undefined : this.uname, + atime: this.portable ? undefined : this.atime, + ctime: this.portable ? undefined : this.ctime, + }) + + if (pathWarn) { + this.warn( + 'TAR_ENTRY_INFO', + `stripping ${pathWarn} from absolute path`, + { + entry: this, + path: pathWarn + this.path, + }, + ) + } + + if (this.header.encode() && !this.noPax) { + super.write( + new Pax({ + atime: this.portable ? undefined : this.atime, + ctime: this.portable ? undefined : this.ctime, + gid: this.portable ? undefined : this.gid, + mtime: this.noMtime ? undefined : this.mtime, + path: this[PREFIX](this.path), + linkpath: + this.type === 'Link' && this.linkpath !== undefined + ? this[PREFIX](this.linkpath) + : this.linkpath, + size: this.size, + uid: this.portable ? undefined : this.uid, + uname: this.portable ? undefined : this.uname, + dev: this.portable ? undefined : this.readEntry.dev, + ino: this.portable ? undefined : this.readEntry.ino, + nlink: this.portable ? undefined : this.readEntry.nlink, + }).encode(), + ) + } + + const b = this.header?.block + /* c8 ignore start */ + if (!b) throw new Error('failed to encode header') + /* c8 ignore stop */ + super.write(b) + readEntry.pipe(this) + } + + [PREFIX](path: string) { + return prefixPath(path, this.prefix) + } + + [MODE](mode: number) { + return modeFix(mode, this.type === 'Directory', this.portable) + } + + write(data: Buffer) { + const writeLen = data.length + if (writeLen > this.blockRemain) { + throw new Error('writing more to entry than is appropriate') + } + this.blockRemain -= writeLen + return super.write(data) + } + + end() { + if (this.blockRemain) { + super.write(Buffer.alloc(this.blockRemain)) + } + return super.end() + } +} + +const getType = (stat: Stats): EntryTypeName | 'Unsupported' => + stat.isFile() + ? 'File' + : stat.isDirectory() + ? 'Directory' + : stat.isSymbolicLink() + ? 'SymbolicLink' + : 'Unsupported' From 9522a698f9c70be24720a73f927908e35a51242c Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Tue, 9 Apr 2024 23:40:42 -0700 Subject: [PATCH 61/96] finish typescript/esm port --- map.js | 15 +- package.json | 9 +- scripts/generate-parse-fixtures.js | 21 +- src/create.ts | 11 +- src/cwd-error.ts | 2 +- src/extract.ts | 2 +- src/get-write-flag.ts | 22 +- src/header.ts | 30 +- src/list.ts | 6 +- src/mkdir.ts | 2 + src/options.ts | 14 +- src/pack.ts | 126 +- src/parse.ts | 21 +- src/path-reservations.ts | 6 +- src/pax.ts | 21 +- src/read-entry.ts | 4 + src/replace.ts | 8 +- src/symlink-error.ts | 2 +- src/types.ts | 1 + src/unpack.ts | 22 +- src/update.ts | 4 + src/write-entry.ts | 27 +- .../test/normalize-unicode.js.test.cjs | 22 +- test/create.js | 235 ++- test/cwd-error.js | 10 + test/extract.js | 236 ++- test/fixtures/make-tar.js | 26 + .../parse/bad-cksum--filter-strict.json | 9 +- test/fixtures/parse/bad-cksum--filter.json | 9 +- .../bad-cksum--meta-250-filter-strict.json | 9 +- .../parse/bad-cksum--meta-250-filter.json | 9 +- .../parse/bad-cksum--meta-250-strict.json | 9 +- test/fixtures/parse/bad-cksum--meta-250.json | 9 +- test/fixtures/parse/bad-cksum--strict.json | 9 +- test/fixtures/parse/bad-cksum.json | 9 +- .../body-byte-counts--filter-strict.json | 36 +- .../parse/body-byte-counts--filter.json | 36 +- ...y-byte-counts--meta-250-filter-strict.json | 36 +- .../body-byte-counts--meta-250-filter.json | 36 +- .../body-byte-counts--meta-250-strict.json | 36 +- .../parse/body-byte-counts--meta-250.json | 36 +- .../parse/body-byte-counts--strict.json | 36 +- test/fixtures/parse/body-byte-counts.json | 36 +- test/fixtures/parse/dir--filter-strict.json | 9 +- test/fixtures/parse/dir--filter.json | 9 +- .../parse/dir--meta-250-filter-strict.json | 9 +- test/fixtures/parse/dir--meta-250-filter.json | 9 +- test/fixtures/parse/dir--meta-250-strict.json | 9 +- test/fixtures/parse/dir--meta-250.json | 9 +- test/fixtures/parse/dir--strict.json | 9 +- test/fixtures/parse/dir.json | 9 +- .../parse/emptypax--filter-strict.json | 28 +- test/fixtures/parse/emptypax--filter.json | 28 +- .../emptypax--meta-250-filter-strict.json | 28 +- .../parse/emptypax--meta-250-filter.json | 28 +- .../parse/emptypax--meta-250-strict.json | 28 +- test/fixtures/parse/emptypax--meta-250.json | 28 +- test/fixtures/parse/emptypax--strict.json | 28 +- test/fixtures/parse/emptypax.json | 28 +- test/fixtures/parse/file--filter-strict.json | 9 +- test/fixtures/parse/file--filter.json | 9 +- .../parse/file--meta-250-filter-strict.json | 9 +- .../fixtures/parse/file--meta-250-filter.json | 9 +- .../fixtures/parse/file--meta-250-strict.json | 9 +- test/fixtures/parse/file--meta-250.json | 9 +- test/fixtures/parse/file--strict.json | 9 +- test/fixtures/parse/file.json | 9 +- .../parse/global-header--filter-strict.json | 22 +- .../fixtures/parse/global-header--filter.json | 22 +- ...global-header--meta-250-filter-strict.json | 22 +- .../parse/global-header--meta-250-filter.json | 22 +- .../parse/global-header--meta-250-strict.json | 22 +- .../parse/global-header--meta-250.json | 22 +- .../fixtures/parse/global-header--strict.json | 22 +- test/fixtures/parse/global-header.json | 22 +- test/fixtures/parse/links--filter-strict.json | 25 +- test/fixtures/parse/links--filter.json | 25 +- .../parse/links--meta-250-filter-strict.json | 25 +- .../parse/links--meta-250-filter.json | 25 +- .../parse/links--meta-250-strict.json | 25 +- test/fixtures/parse/links--meta-250.json | 25 +- test/fixtures/parse/links--strict.json | 25 +- .../parse/links-invalid--filter-strict.json | 8 +- .../fixtures/parse/links-invalid--filter.json | 8 +- ...links-invalid--meta-250-filter-strict.json | 8 +- .../parse/links-invalid--meta-250-filter.json | 8 +- .../parse/links-invalid--meta-250-strict.json | 8 +- .../parse/links-invalid--meta-250.json | 8 +- .../fixtures/parse/links-invalid--strict.json | 8 +- test/fixtures/parse/links-invalid.json | 8 +- .../parse/links-strip--filter-strict.json | 42 +- test/fixtures/parse/links-strip--filter.json | 42 +- .../links-strip--meta-250-filter-strict.json | 42 +- .../parse/links-strip--meta-250-filter.json | 42 +- .../parse/links-strip--meta-250-strict.json | 42 +- .../fixtures/parse/links-strip--meta-250.json | 42 +- test/fixtures/parse/links-strip--strict.json | 42 +- test/fixtures/parse/links-strip.json | 42 +- test/fixtures/parse/links.json | 25 +- .../parse/long-paths--filter-strict.json | 338 +--- test/fixtures/parse/long-paths--filter.json | 338 +--- .../long-paths--meta-250-filter-strict.json | 335 +--- .../parse/long-paths--meta-250-filter.json | 335 +--- .../parse/long-paths--meta-250-strict.json | 335 +--- test/fixtures/parse/long-paths--meta-250.json | 335 +--- test/fixtures/parse/long-paths--strict.json | 338 +--- test/fixtures/parse/long-paths.json | 338 +--- .../parse/long-pax--filter-strict.json | 21 +- test/fixtures/parse/long-pax--filter.json | 21 +- .../long-pax--meta-250-filter-strict.json | 18 +- .../parse/long-pax--meta-250-filter.json | 18 +- .../parse/long-pax--meta-250-strict.json | 18 +- test/fixtures/parse/long-pax--meta-250.json | 18 +- test/fixtures/parse/long-pax--strict.json | 21 +- test/fixtures/parse/long-pax.json | 21 +- .../next-file-has-long--filter-strict.json | 15 +- .../parse/next-file-has-long--filter.json | 15 +- ...file-has-long--meta-250-filter-strict.json | 15 +- .../next-file-has-long--meta-250-filter.json | 15 +- .../next-file-has-long--meta-250-strict.json | 15 +- .../parse/next-file-has-long--meta-250.json | 15 +- .../parse/next-file-has-long--strict.json | 15 +- test/fixtures/parse/next-file-has-long.json | 15 +- .../parse/null-byte--filter-strict.json | 25 +- test/fixtures/parse/null-byte--filter.json | 25 +- .../null-byte--meta-250-filter-strict.json | 25 +- .../parse/null-byte--meta-250-filter.json | 25 +- .../parse/null-byte--meta-250-strict.json | 25 +- test/fixtures/parse/null-byte--meta-250.json | 25 +- test/fixtures/parse/null-byte--strict.json | 25 +- test/fixtures/parse/null-byte.json | 25 +- ...ling-slash-corner-case--filter-strict.json | 37 +- .../trailing-slash-corner-case--filter.json | 37 +- ...h-corner-case--meta-250-filter-strict.json | 37 +- ...ng-slash-corner-case--meta-250-filter.json | 37 +- ...ng-slash-corner-case--meta-250-strict.json | 37 +- .../trailing-slash-corner-case--meta-250.json | 37 +- .../trailing-slash-corner-case--strict.json | 37 +- .../parse/trailing-slash-corner-case.json | 37 +- test/fixtures/parse/utf8--filter-strict.json | 57 +- test/fixtures/parse/utf8--filter.json | 57 +- .../parse/utf8--meta-250-filter-strict.json | 57 +- .../fixtures/parse/utf8--meta-250-filter.json | 57 +- .../fixtures/parse/utf8--meta-250-strict.json | 57 +- test/fixtures/parse/utf8--meta-250.json | 57 +- test/fixtures/parse/utf8--strict.json | 57 +- test/fixtures/parse/utf8.json | 57 +- test/get-write-flag.js | 86 +- test/header.js | 579 +++--- test/high-level-opt.js | 42 - test/index.js | 13 +- test/large-numbers.js | 7 +- test/list.js | 158 +- test/load-all.js | 24 +- test/make-tar.js | 27 - test/map.js | 12 +- test/mode-fix.js | 27 +- test/normalize-unicode.js | 38 +- test/normalize-windows-path.js | 28 +- test/options.js | 65 + test/pack.js | 739 ++++--- test/parse.js | 649 ++++--- test/path-reservations.js | 52 +- test/pax.js | 200 +- test/read-entry.js | 120 +- test/replace.js | 31 +- test/strip-absolute-path.js | 40 +- test/strip-trailing-slashes.js | 10 +- test/symlink-error.js | 11 + test/types.js | 10 +- test/unpack.js | 1701 ++++++++++------- test/update.js | 29 +- test/{warn-mixin.js => warn-method.js} | 13 +- test/winchars.js | 5 +- test/write-entry.js | 673 ++++--- 175 files changed, 4341 insertions(+), 7377 deletions(-) create mode 100644 test/cwd-error.js create mode 100644 test/fixtures/make-tar.js delete mode 100644 test/high-level-opt.js delete mode 100644 test/make-tar.js create mode 100644 test/options.js create mode 100644 test/symlink-error.js rename test/{warn-mixin.js => warn-method.js} (81%) diff --git a/map.js b/map.js index 1d7e33ae..e7ef1050 100644 --- a/map.js +++ b/map.js @@ -1,9 +1,12 @@ -const { basename } = require('path') +import { basename } from 'path' const map = test => - test === 'index.js' || test === 'map.js' ? test - : test === 'unpack.js' ? ['lib/unpack.js', 'lib/mkdir.js'] - : test === 'load-all.js' ? [] - : `lib/${test}` + test === 'map.js' + ? test + : test === 'unpack.js' + ? ['src/unpack.ts', 'src/mkdir.ts'] + : test === 'load-all.js' + ? [] + : `src/${test.replace(/js$/, 'ts')}` -module.exports = test => map(basename(test)) +export default test => map(basename(test)) diff --git a/package.json b/package.json index 7cfcb4f5..57eaf9a1 100644 --- a/package.json +++ b/package.json @@ -25,17 +25,18 @@ "chownr": "^3.0.0", "minipass": "^5.0.0", "minizlib": "^3.0.1", - "mkdirp": "^3.0.1" + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" }, "devDependencies": { "chmodr": "^1.2.0", "end-of-stream": "^1.4.3", "events-to-array": "^2.0.3", "mutate-fs": "^2.1.1", - "nock": "^13.2.9", + "nock": "^13.5.4", "prettier": "^3.2.5", - "rimraf": "^3.0.2", - "tap": "^16.0.1", + "rimraf": "^5.0.5", + "tap": "^18.7.2", "tshy": "^1.13.1", "typedoc": "^0.25.13" }, diff --git a/scripts/generate-parse-fixtures.js b/scripts/generate-parse-fixtures.js index b46e8bd7..ff7d864f 100644 --- a/scripts/generate-parse-fixtures.js +++ b/scripts/generate-parse-fixtures.js @@ -1,9 +1,12 @@ -'use strict' -const Parse = require('../lib/parse.js') -const fs = require('fs') -const path = require('path') -const tardir = path.resolve(__dirname, '../test/fixtures/tars') -const parsedir = path.resolve(__dirname, '../test/fixtures/parse') +import { Parser } from '../dist/esm/parse.js' +import fs from 'fs' +import path, {dirname, resolve} from 'path' +import {fileURLToPath} from 'url' +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +const tardir = resolve(__dirname, '../test/fixtures/tars') +const parsedir = resolve(__dirname, '../test/fixtures/parse') const maxMetaOpt = [250, null] const filterOpt = [true, false] const strictOpt = [true, false] @@ -16,9 +19,9 @@ const makeTest = (tarfile, tardata, maxMeta, filter, strict) => { const tail = (o ? '-' + o : '') + '.json' const eventsfile = parsedir + '/' + path.basename(tarfile, '.tar') + tail - const p = new Parse({ + const p = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, + filter: filter ? (_path, entry) => entry.size % 2 !== 0 : null, strict: strict, }) const events = [] @@ -70,7 +73,7 @@ const makeTest = (tarfile, tardata, maxMeta, filter, strict) => { p.on('entry', pushEntry('entry')) p.on('ignoredEntry', pushEntry('ignoredEntry')) - p.on('warn', (code, message, data) => events.push(['warn', code, message])) + p.on('warn', (code, message, _data) => events.push(['warn', code, message])) p.on('error', er => events.push(['error', { message: er.message, code: er.code, diff --git a/src/create.ts b/src/create.ts index b97eb2e8..85b27c38 100644 --- a/src/create.ts +++ b/src/create.ts @@ -130,16 +130,17 @@ const addFilesSync = (p: PackSync, files: string[]) => { const addFilesAsync = async ( p: Pack, files: string[], - i = 0, ): Promise<void> => { - for (; i < files.length; i++) { + for (let i = 0; i < files.length; i++) { const file = String(files[i]) if (file.charAt(0) === '@') { - return list({ + await list({ file: path.resolve(String(p.cwd), file.slice(1)), noResume: true, - onentry: entry => p.add(entry), - }).then(_ => addFilesAsync(p, files)) + onentry: entry => { + p.add(entry) + }, + }) } else { p.add(file) } diff --git a/src/cwd-error.ts b/src/cwd-error.ts index 7a708ed4..bdc48046 100644 --- a/src/cwd-error.ts +++ b/src/cwd-error.ts @@ -4,7 +4,7 @@ export class CwdError extends Error { syscall: 'chdir' = 'chdir' constructor(path: string, code: string) { - super(code + ": Cannot cd into '" + path + "'") + super(`${code}: Cannot cd into '${path}'`) this.path = path this.code = code } diff --git a/src/extract.ts b/src/extract.ts index f79f9408..b3cb3b0b 100644 --- a/src/extract.ts +++ b/src/extract.ts @@ -132,7 +132,7 @@ const extractFileSync = (opt: TarOptionsSyncFile) => { const extractFile = ( opt: TarOptionsFile, - cb: () => void = () => {}, + cb?: () => void, ) => { const u = new Unpack(opt) const readSize = opt.maxReadSize || 16 * 1024 * 1024 diff --git a/src/get-write-flag.ts b/src/get-write-flag.ts index db358591..bd8842dc 100644 --- a/src/get-write-flag.ts +++ b/src/get-write-flag.ts @@ -5,21 +5,19 @@ // library is used for is extracting tarballs of many // relatively small files in npm packages and the like, // it can be a big boost on Windows platforms. -// Only supported in Node v12.9.0 and above. + +import fs from 'fs' + const platform = process.env.__FAKE_PLATFORM__ || process.platform const isWindows = platform === 'win32' -const g = globalThis as typeof globalThis & { - __FAKE_TESTING_FS__: typeof import('fs') -} -const fs = g.__FAKE_TESTING_FS__ || require('fs') -/* istanbul ignore next */ -const { - O_CREAT, - O_TRUNC, - O_WRONLY, - UV_FS_O_FILEMAP = 0, -} = fs.constants +/* c8 ignore start */ +const { O_CREAT, O_TRUNC, O_WRONLY } = fs.constants +const UV_FS_O_FILEMAP = + Number(process.env.__FAKE_FS_O_FILENAME__) || + fs.constants.UV_FS_O_FILEMAP || + 0 +/* c8 ignore stop */ const fMapEnabled = isWindows && !!UV_FS_O_FILEMAP const fMapLimit = 512 * 1024 diff --git a/src/header.ts b/src/header.ts index b9efbda6..e648876e 100644 --- a/src/header.ts +++ b/src/header.ts @@ -15,7 +15,7 @@ export type HeaderData = { gid?: number size?: number cksum?: number - type?: EntryTypeCode | EntryTypeName + type?: EntryTypeName | 'Unsupported' linkpath?: string uname?: string gname?: string @@ -46,7 +46,7 @@ export class Header implements HeaderData { gid?: number size?: number cksum?: number - #type: EntryTypeCode = '0' + #type: EntryTypeCode | 'Unsupported' = 'Unsupported' linkpath?: string uname?: string gname?: string @@ -101,10 +101,8 @@ export class Header implements HeaderData { // old tar versions marked dirs as a file with a trailing / const t = decString(buf, off + 156, 1) - if (types.isCode(t)) this.#type = t - else this.#type = '0' - if (this.#type === '') { - this.#type = '0' + if (types.isCode(t)) { + this.#type = t || '0' } if (this.#type === '0' && this.path.slice(-1) === '/') { this.#type = '5' @@ -126,8 +124,10 @@ export class Header implements HeaderData { ) { this.uname = decString(buf, off + 265, 32) this.gname = decString(buf, off + 297, 32) + /* c8 ignore start */ this.devmaj = decNumber(buf, off + 329, 8) ?? 0 this.devmin = decNumber(buf, off + 337, 8) ?? 0 + /* c8 ignore stop */ if (buf[off + 475] !== 0) { // definitely a prefix, definitely >130 chars. const prefix = decString(buf, off + 345, 155) @@ -152,7 +152,7 @@ export class Header implements HeaderData { } this.cksumValid = sum === this.cksum - if (this.cksum === null && sum === 8 * 0x20) { + if (this.cksum === undefined && sum === 8 * 0x20) { this.nullBlock = true } } @@ -180,6 +180,10 @@ export class Header implements HeaderData { buf = this.block = Buffer.alloc(512) } + if (this.#type === 'Unsupported') { + this.#type = '0' + } + if (!(buf.length >= off + 512)) { throw new Error('need 512 bytes for header') } @@ -244,16 +248,20 @@ export class Header implements HeaderData { } get type(): EntryTypeName { - return types.name.get(this.#type) as EntryTypeName + return ( + this.#type === 'Unsupported' + ? this.#type + : types.name.get(this.#type) + ) as EntryTypeName } - get typeKey(): EntryTypeCode { + get typeKey(): EntryTypeCode | 'Unsupported' { return this.#type } - set type(type: EntryTypeCode | EntryTypeName) { + set type(type: EntryTypeCode | EntryTypeName | 'Unsupported') { const c = String(types.code.get(type as EntryTypeName)) - if (types.isCode(c)) { + if (types.isCode(c) || c === 'Unsupported') { this.#type = c } else if (types.isCode(type)) { this.#type = type diff --git a/src/list.ts b/src/list.ts index a31a4397..7ba43143 100644 --- a/src/list.ts +++ b/src/list.ts @@ -8,6 +8,7 @@ import { isSyncFile, TarOptions, TarOptionsFile, + TarOptionsSyncFile, TarOptionsWithAliases, TarOptionsWithAliasesFile, TarOptionsWithAliasesSync, @@ -126,7 +127,7 @@ const filesFilter = (opt: TarOptions, files: string[]) => { : file => mapHas(stripTrailingSlashes(file)) } -const listFileSync = (opt: TarOptionsWithAliasesSyncFile) => { +const listFileSync = (opt: TarOptionsSyncFile) => { const p = list_(opt) const file = opt.file let threw = true @@ -152,12 +153,13 @@ const listFileSync = (opt: TarOptionsWithAliasesSyncFile) => { if (threw && fd) { try { fs.closeSync(fd) + /* c8 ignore next */ } catch (er) {} } } } -const listFile = (opt: TarOptionsFile, cb?: () => void) => { +const listFile = (opt: TarOptionsFile, cb?: () => void): Promise<void> => { const parse = new Parser(opt) const readSize = opt.maxReadSize || 16 * 1024 * 1024 diff --git a/src/mkdir.ts b/src/mkdir.ts index 6c84654b..cf98d1ac 100644 --- a/src/mkdir.ts +++ b/src/mkdir.ts @@ -65,6 +65,7 @@ export const mkdir = ( // if there's any overlap between mask and mode, // then we'll need an explicit chmod + /* c8 ignore next */ const umask = opt.umask ?? 0o22 const mode = opt.mode | 0o0700 const needChmod = (mode & umask) !== 0 @@ -215,6 +216,7 @@ export const mkdirSync = (dir: string, opt: MkdirOptions) => { dir = normalizeWindowsPath(dir) // if there's any overlap between mask and mode, // then we'll need an explicit chmod + /* c8 ignore next */ const umask = opt.umask ?? 0o22 const mode = opt.mode | 0o700 const needChmod = (mode & umask) !== 0 diff --git a/src/options.ts b/src/options.ts index 4449b718..a612f142 100644 --- a/src/options.ts +++ b/src/options.ts @@ -435,18 +435,18 @@ export interface TarOptionsWithAliases extends TarOptions { export type TarOptionsWithAliasesSync = TarOptionsWithAliases & { sync: true } -export type TarOptionsWithAliasesFile = TarOptionsWithAliases & { - file: string -} +export type TarOptionsWithAliasesFile = + | (TarOptionsWithAliases & { + file: string + }) + | (TarOptionsWithAliases & { f: string }) export type TarOptionsWithAliasesSyncFile = TarOptionsWithAliasesSync & TarOptionsWithAliasesFile export const isSyncFile = (o: TarOptions): o is TarOptionsSyncFile => !!o.sync && !!o.file -export const isSync = (o: TarOptions): o is TarOptionsSync => - !!o.sync -export const isFile = (o: TarOptions): o is TarOptionsFile => - !!o.file +export const isSync = (o: TarOptions): o is TarOptionsSync => !!o.sync +export const isFile = (o: TarOptions): o is TarOptionsFile => !!o.file const dealiasKey = ( k: keyof TarOptionsWithAliases, diff --git a/src/pack.ts b/src/pack.ts index 4dc7e3b5..07d6500f 100644 --- a/src/pack.ts +++ b/src/pack.ts @@ -8,17 +8,6 @@ // streamOfPaths().pipe(new Pack()).pipe(new fs.WriteStream('out.tar')) import fs, { type Stats } from 'fs' -import { Minipass } from 'minipass' -import { BrotliCompress, Gzip } from 'minizlib' -import path from 'path' -import { normalizeWindowsPath } from './normalize-windows-path.js' -import { dealias, LinkCacheKey, TarOptions } from './options.js' -import { ReadEntry } from './read-entry.js' -import { - warnMethod, - type WarnData, - type Warner, -} from './warn-method.js' import { WriteEntry, WriteEntrySync, @@ -34,13 +23,23 @@ export class PackJob { pending: boolean = false ignore: boolean = false piped: boolean = false - constructor(path: string, absolute: string) { this.path = path || './' this.absolute = absolute } } +import { Minipass } from 'minipass' +import * as zlib from 'minizlib' +//@ts-ignore +import { Yallist } from 'yallist' +import { ReadEntry } from './read-entry.js' +import { + warnMethod, + type WarnData, + type Warner, +} from './warn-method.js' + const EOF = Buffer.alloc(1024) const ONSTAT = Symbol('onStat') const ENDED = Symbol('ended') @@ -63,20 +62,24 @@ const WRITEENTRYCLASS = Symbol('writeEntryClass') const WRITE = Symbol('write') const ONDRAIN = Symbol('ondrain') +import path from 'path' +import { normalizeWindowsPath } from './normalize-windows-path.js' +import { TarOptions } from './options.js' + export class Pack extends Minipass implements Warner { opt: TarOptions - file: string cwd: string maxReadSize?: number preservePaths: boolean strict: boolean noPax: boolean prefix: string - linkCache: Map<LinkCacheKey, string> - statCache: Map<string, Stats> - readdirCache: Map<string, string[]> + linkCache: Exclude<TarOptions['linkCache'], undefined> + statCache: Exclude<TarOptions['statCache'], undefined> + file: string portable: boolean - zip?: Gzip | BrotliCompress + zip?: zlib.BrotliCompress | zlib.Gzip + readdirCache: Exclude<TarOptions['readdirCache'], undefined> noDirRecurse: boolean follow: boolean noMtime: boolean @@ -84,17 +87,14 @@ export class Pack extends Minipass implements Warner { filter: Exclude<TarOptions['filter'], undefined> jobs: number; - [WRITEENTRYCLASS]: - | typeof WriteEntry - | typeof WriteEntrySync - [QUEUE]: PackJob[] = []; + [WRITEENTRYCLASS]: typeof WriteEntry | typeof WriteEntrySync; + [QUEUE]: Yallist<PackJob>; [JOBS]: number = 0; [PROCESSING]: boolean = false; [ENDED]: boolean = false - constructor(opt_: TarOptions = {}) { + constructor(opt: TarOptions = {}) { super() - const opt = dealias(opt_) this.opt = opt this.file = opt.file || '' this.cwd = opt.cwd || process.cwd() @@ -125,15 +125,17 @@ export class Pack extends Minipass implements Warner { if (this.portable) { opt.gzip.portable = true } - this.zip = new Gzip(opt.gzip) + this.zip = new zlib.Gzip(opt.gzip) } if (opt.brotli) { if (typeof opt.brotli !== 'object') { opt.brotli = {} } - this.zip = new BrotliCompress(opt.brotli) + this.zip = new zlib.BrotliCompress(opt.brotli) } - const zip = this.zip as Gzip | BrotliCompress + /* c8 ignore next */ + if (!this.zip) throw new Error('impossible') + const zip = this.zip zip.on('data', chunk => super.write(chunk)) zip.on('end', () => super.end()) zip.on('drain', () => this[ONDRAIN]()) @@ -145,21 +147,18 @@ export class Pack extends Minipass implements Warner { this.noDirRecurse = !!opt.noDirRecurse this.follow = !!opt.follow this.noMtime = !!opt.noMtime - this.mtime = opt.mtime + if (opt.mtime) this.mtime = opt.mtime this.filter = - typeof opt.filter === 'function' ? opt.filter : () => true + typeof opt.filter === 'function' ? opt.filter : _ => true + this[QUEUE] = new Yallist<PackJob>() this[JOBS] = 0 this.jobs = Number(opt.jobs) || 4 this[PROCESSING] = false this[ENDED] = false } - warn(code: string, message: string | Error, data: WarnData = {}) { - return warnMethod(this, code, message, data) - } - [WRITE](chunk: Buffer) { return super.write(chunk) } @@ -169,20 +168,10 @@ export class Pack extends Minipass implements Warner { return this } - end(cb?: () => void): this - end(path: string, cb?: () => void): this - end( - path: string, - encoding?: Minipass.Encoding | undefined, - cb?: () => void, - ): this - end( - path?: string | (() => void), - _encoding?: Minipass.Encoding | (() => void), - _cb?: () => void, - ) { - if (typeof path === 'string') { - this.write(path) + //@ts-ignore + end(path?: string | ReadEntry) { + if (path) { + this.add(path) } this[ENDED] = true this[PROCESS]() @@ -213,7 +202,7 @@ export class Pack extends Minipass implements Warner { } else { const job = new PackJob(p.path, absolute) job.entry = new WriteEntryTar(p, this[ENTRYOPT](job)) - job.entry.on('end', _ => this[JOBDONE](job)) + job.entry.on('end', () => this[JOBDONE](job)) this[JOBS] += 1 this[QUEUE].push(job) } @@ -280,13 +269,15 @@ export class Pack extends Minipass implements Warner { this[PROCESSING] = true for ( - let j: PackJob | undefined, w = 0; - (j = this[QUEUE][w]) && this[JOBS] < this.jobs; - w ++ + let w = this[QUEUE].head; + !!w && this[JOBS] < this.jobs; + w = w.next ) { - this[PROCESSJOB](j) - if (j.ignore) { - this[QUEUE].splice(w, 1) + this[PROCESSJOB](w.value) + if (w.value.ignore) { + const p = w.next + this[QUEUE].removeNode(w) + w.next = p } } @@ -303,7 +294,7 @@ export class Pack extends Minipass implements Warner { } get [CURRENT]() { - return this[QUEUE] && this[QUEUE][0] + return this[QUEUE] && this[QUEUE].head && this[QUEUE].head.value } [JOBDONE](_job: PackJob) { @@ -346,9 +337,8 @@ export class Pack extends Minipass implements Warner { job.stat.isDirectory() && !job.readdir ) { - const rc = this.readdirCache.get(job.absolute) - if ( rc) { + if (rc) { this[ONREADDIR](job, rc) } else { this[READDIR](job) @@ -391,8 +381,7 @@ export class Pack extends Minipass implements Warner { [ENTRY](job: PackJob) { this[JOBS] += 1 try { - const Cls = this[WRITEENTRYCLASS] - return new Cls(job.path, this[ENTRYOPT](job)) + return new this[WRITEENTRYCLASS](job.path, this[ENTRYOPT](job)) .on('end', () => this[JOBDONE](job)) .on('error', er => this.emit('error', er)) } catch (er) { @@ -420,11 +409,8 @@ export class Pack extends Minipass implements Warner { const source = job.entry const zip = this.zip - /* c8 ignore start */ - if (!source) { - throw new Error('must have source before piping') - } + if (!source) throw new Error('cannot pipe without source') /* c8 ignore stop */ if (zip) { @@ -448,6 +434,13 @@ export class Pack extends Minipass implements Warner { } return super.pause() } + warn( + code: string, + message: string | Error, + data: WarnData = {}, + ): void { + warnMethod(this, code, message, data) + } } export class PackSync extends Pack { @@ -472,11 +465,6 @@ export class PackSync extends Pack { // gotta get it all in this tick [PIPE](job: PackJob) { const source = job.entry - /* c8 ignore start */ - if (!source) { - throw new Error('job without source') - } - /* c8 ignore stop */ const zip = this.zip if (job.readdir) { @@ -487,6 +475,10 @@ export class PackSync extends Pack { }) } + /* c8 ignore start */ + if (!source) throw new Error('Cannot pipe without source') + /* c8 ignore stop */ + if (zip) { source.on('data', chunk => { zip.write(chunk) diff --git a/src/parse.ts b/src/parse.ts index 7912fef0..d0b0781e 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -20,6 +20,7 @@ import { EventEmitter as EE } from 'events' import { BrotliDecompress, Unzip } from 'minizlib' +import { Yallist } from 'yallist' import { Header } from './header.js' import { TarOptions } from './options.js' import { Pax } from './pax.js' @@ -78,7 +79,8 @@ export class Parser extends EE implements Warner { writable: true = true readable: false = false; - [QUEUE]: (ReadEntry | [string | symbol, any, any])[] = []; + [QUEUE]: Yallist<ReadEntry | [string | symbol, any, any]> = + new Yallist(); [BUFFER]?: Buffer; [READENTRY]?: ReadEntry; [WRITEENTRY]?: ReadEntry; @@ -161,7 +163,7 @@ export class Parser extends EE implements Warner { } [CONSUMEHEADER](chunk: Buffer, position: number) { - if (this[SAW_VALID_ENTRY] === null) { + if (this[SAW_VALID_ENTRY] === undefined) { this[SAW_VALID_ENTRY] = false } let header @@ -322,8 +324,8 @@ export class Parser extends EE implements Warner { if (!entry) { throw new Error('attempt to consume body without entry??') } - /* c8 ignore stop */ const br = entry.blockRemain ?? 0 + /* c8 ignore stop */ const c = br >= chunk.length && position === 0 ? chunk @@ -387,9 +389,10 @@ export class Parser extends EE implements Warner { break } - /* istanbul ignore next */ + /* c8 ignore start */ default: throw new Error('unknown meta: ' + entry.type) + /* c8 ignore stop */ } } @@ -422,7 +425,7 @@ export class Parser extends EE implements Warner { // look for gzip header for ( let i = 0; - this[UNZIP] === null && i < gzipHeader.length; + this[UNZIP] === undefined && i < gzipHeader.length; i++ ) { if (chunk[i] !== gzipHeader[i]) { @@ -456,7 +459,7 @@ export class Parser extends EE implements Warner { } if ( - this[UNZIP] === null || + this[UNZIP] === undefined || (this[UNZIP] === false && this.brotli) ) { const ended = this[ENDED] @@ -595,9 +598,10 @@ export class Parser extends EE implements Warner { position += this[CONSUMEMETA](chunk, position) break - /* istanbul ignore next */ + /* c8 ignore start */ default: throw new Error('invalid state: ' + this[STATE]) + /* c8 ignore stop */ } } @@ -616,13 +620,16 @@ export class Parser extends EE implements Warner { end(chunk?: Buffer) { if (!this[ABORTED]) { if (this[UNZIP]) { + /* c8 ignore start */ if (chunk) this[UNZIP].write(chunk) + /* c8 ignore stop */ this[UNZIP].end() } else { this[ENDED] = true if (this.brotli === undefined) chunk = chunk || Buffer.alloc(0) if (chunk) this.write(chunk) + this[MAYBEEND]() } } } diff --git a/src/path-reservations.ts b/src/path-reservations.ts index 711e9ee2..79407710 100644 --- a/src/path-reservations.ts +++ b/src/path-reservations.ts @@ -95,10 +95,11 @@ export class PathReservations { dirs: (Handler | Set<Handler>)[][] } { const res = this.#reservations.get(fn) - /* istanbul ignore if - unpossible */ + /* c8 ignore start */ if (!res) { throw new Error('function does not have any path reservations') } + /* c8 ignore stop */ return { paths: res.paths.map((path: string) => this.#queues.get(path), @@ -168,7 +169,8 @@ export class PathReservations { for (const dir of dirs) { const q = this.#queues.get(dir) const q0 = q?.[0] - if (!(q0 instanceof Set) || !q) continue + /* c8 ignore next - type safety only */ + if (!q || !(q0 instanceof Set)) continue if (q0.size === 1 && q.length === 1) { this.#queues.delete(dir) continue diff --git a/src/pax.ts b/src/pax.ts index 7c542c95..680c9234 100644 --- a/src/pax.ts +++ b/src/pax.ts @@ -28,18 +28,19 @@ export class Pax implements HeaderData { this.atime = obj.atime this.charset = obj.charset this.comment = obj.comment + this.ctime = obj.ctime + this.dev = obj.dev this.gid = obj.gid + this.global = global this.gname = obj.gname + this.ino = obj.ino this.linkpath = obj.linkpath this.mtime = obj.mtime + this.nlink = obj.nlink this.path = obj.path this.size = obj.size this.uid = obj.uid this.uname = obj.uname - this.dev = obj.dev - this.ino = obj.ino - this.nlink = obj.nlink - this.global = global } encode() { @@ -63,7 +64,9 @@ export class Pax implements HeaderData { // XXX split the path // then the path should be PaxHeader + basename, but less than 99, // prepend with the dirname - path: ('PaxHeader/' + basename(this.path || '')).slice(0, 99), + /* c8 ignore start */ + path: ('PaxHeader/' + basename(this.path ?? '')).slice(0, 99), + /* c8 ignore stop */ mode: this.mode || 0o644, uid: this.uid, gid: this.gid, @@ -163,14 +166,12 @@ const parseKVLine = (set: Record<string, any>, line: string) => { const kv = line.split('=') const r = kv.shift() - /* c8 ignore next */ - if (!r) throw new Error('fell of key/value list somehow') - - const k = r.replace(/^SCHILY\.(dev|ino|nlink)/, '$1') - if (!k) { + if (!r) { return set } + const k = r.replace(/^SCHILY\.(dev|ino|nlink)/, '$1') + const v = kv.join('=') set[k] = /^([A-Z]+\.)?([mac]|birth|creation)time$/.test(k) ? new Date(Number(v) * 1000) diff --git a/src/read-entry.ts b/src/read-entry.ts index 98260ee7..a4ca7eb7 100644 --- a/src/read-entry.ts +++ b/src/read-entry.ts @@ -42,7 +42,9 @@ export class ReadEntry extends Minipass<Buffer, Buffer> { this.extended = ex this.globalExtended = gex this.header = header + /* c8 ignore start */ this.remain = header.size ?? 0 + /* c8 ignore stop */ this.startBlockSize = 512 * Math.ceil(this.remain / 512) this.blockRemain = this.startBlockSize this.type = header.type @@ -93,9 +95,11 @@ export class ReadEntry extends Minipass<Buffer, Buffer> { this.mtime = header.mtime this.atime = header.atime this.ctime = header.ctime + /* c8 ignore start */ this.linkpath = header.linkpath ? normalizeWindowsPath(header.linkpath) : undefined + /* c8 ignore stop */ this.uname = header.uname this.gname = header.gname diff --git a/src/replace.ts b/src/replace.ts index 1d45445d..579b9b78 100644 --- a/src/replace.ts +++ b/src/replace.ts @@ -219,6 +219,7 @@ const replace_ = ( return cb(null, position) } + /* c8 ignore next */ const entryBlockSize = 512 * Math.ceil((h.size ?? 0) / 512) if (position + entryBlockSize + 512 > size) { return cb(null, position) @@ -299,16 +300,15 @@ const addFilesSync = (p: Pack, files: string[]) => { const addFilesAsync = async ( p: Pack, files: string[], - i = 0, ): Promise<void> => { - for (; i < files.length; i++) { + for (let i = 0; i < files.length; i++) { const file = String(files[i]) if (file.charAt(0) === '@') { - return list({ + await list({ file: path.resolve(String(p.cwd), file.slice(1)), noResume: true, onentry: entry => p.add(entry), - }).then(_ => addFilesAsync(p, files)) + }) } else { p.add(file) } diff --git a/src/symlink-error.ts b/src/symlink-error.ts index c237cb94..7aa5ea78 100644 --- a/src/symlink-error.ts +++ b/src/symlink-error.ts @@ -4,7 +4,7 @@ export class SymlinkError extends Error { syscall: 'symlink' = 'symlink' code: 'TAR_SYMLINK_ERROR' = 'TAR_SYMLINK_ERROR' constructor (symlink: string, path: string) { - super('Cannot extract through symbolic link') + super('TAR_SYMLINK_ERROR: Cannot extract through symbolic link') this.symlink = symlink this.path = path } diff --git a/src/types.ts b/src/types.ts index 080995a6..96b8f74b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -49,6 +49,7 @@ export type EntryTypeName = | 'SparseFile' | 'TapeVolumeHeader' | 'OldExtendedHeader' + | 'Unsupported' // map types from key to human-friendly name export const name = new Map<EntryTypeCode, EntryTypeName>([ diff --git a/src/unpack.ts b/src/unpack.ts index 064bbcf9..26e857cc 100644 --- a/src/unpack.ts +++ b/src/unpack.ts @@ -68,7 +68,7 @@ const DEFAULT_MAX_DEPTH = 1024 // semantics. // // See: https://github.com/npm/node-tar/issues/183 -/* istanbul ignore next */ +/* c8 ignore start */ const unlinkFile = ( path: string, cb: (er?: Error | null) => void, @@ -85,8 +85,9 @@ const unlinkFile = ( fs.unlink(name, cb) }) } +/* c8 ignore stop */ -/* istanbul ignore next */ +/* c8 ignore start */ const unlinkFileSync = (path: string) => { if (!isWindows) { return fs.unlinkSync(path) @@ -96,6 +97,7 @@ const unlinkFileSync = (path: string) => { fs.renameSync(path, name) fs.unlinkSync(name) } +/* c8 ignore stop */ // this.gid, entry.gid, this.processUid const uint32 = ( @@ -331,6 +333,7 @@ export class Unpack extends Parser { if (!this.preservePaths) { if ( parts.includes('..') || + /* c8 ignore next */ (isWindows && /^[a-z]:\.\.$/i.test(parts[0] ?? '')) ) { this.warn('TAR_ENTRY_ERROR', `path contains '..'`, { @@ -366,7 +369,7 @@ export class Unpack extends Parser { // if we somehow ended up with a path that escapes the cwd, and we are // not in preservePaths mode, then something is fishy! This should have // been prevented above, so ignore this for coverage. - /* istanbul ignore if - defense in depth */ + /* c8 ignore start - defense in depth */ if ( !this.preservePaths && typeof entry.absolute === 'string' && @@ -381,6 +384,7 @@ export class Unpack extends Parser { }) return false } + /* c8 ignore stop */ // an archive can set properties on the extraction directory, but it // may not replace the cwd with a different kind of thing entirely. @@ -522,10 +526,11 @@ export class Unpack extends Parser { let actions = 1 const done = (er?: null | Error) => { if (er) { - /* istanbul ignore else - we should always have a fd by now */ + /* c8 ignore start - we should always have a fd by now */ if (stream.fd) { fs.close(stream.fd, () => {}) } + /* c8 ignore stop */ this[ONERROR](er, entry) fullyDone() @@ -758,6 +763,7 @@ export class Unpack extends Parser { if ( st && (this.keep || + /* c8 ignore next */ (this.newer && st.mtime > (entry.mtime ?? st.mtime))) ) { this[SKIP](entry) @@ -912,6 +918,7 @@ export class UnpackSync extends Unpack { if ( st && (this.keep || + /* c8 ignore next */ (this.newer && st.mtime > (entry.mtime ?? st.mtime))) ) { return this[SKIP](entry) @@ -1019,7 +1026,11 @@ export class UnpackSync extends Unpack { fs.fchownSync(fd, Number(uid), Number(gid)) } catch (fchowner) { try { - fs.chownSync(String(entry.absolute), Number(uid), Number(gid)) + fs.chownSync( + String(entry.absolute), + Number(uid), + Number(gid), + ) } catch (chowner) { er = er || fchowner } @@ -1048,6 +1059,7 @@ export class UnpackSync extends Unpack { entry.atime || new Date(), entry.mtime, ) + /* c8 ignore next */ } catch (er) {} } if (this[DOCHOWN](entry)) { diff --git a/src/update.ts b/src/update.ts index a049efd5..d30b2daa 100644 --- a/src/update.ts +++ b/src/update.ts @@ -51,12 +51,16 @@ const mtimeFilter = (opt: TarOptionsWithAliases) => { ? (path, stat) => filter(path, stat) && !( + /* c8 ignore start */ (opt.mtimeCache?.get(path) ?? stat.mtime ?? 0) > (stat.mtime ?? 0) + /* c8 ignore stop */ ) : (path, stat) => !( + /* c8 ignore start */ (opt.mtimeCache?.get(path) ?? stat.mtime ?? 0) > (stat.mtime ?? 0) + /* c8 ignore stop */ ) } diff --git a/src/write-entry.ts b/src/write-entry.ts index f9910c6d..5d728585 100644 --- a/src/write-entry.ts +++ b/src/write-entry.ts @@ -80,7 +80,7 @@ export class WriteEntry extends Minipass<Buffer> implements Warner { type?: EntryTypeName | 'Unsupported' linkpath?: string stat?: Stats - /* c8 ignore start */ + /* c8 ignore start */ #hadError: boolean = false @@ -107,12 +107,12 @@ export class WriteEntry extends Minipass<Buffer> implements Warner { this.on('warn', opt.onwarn) } - let pathWarn = false + let pathWarn: string | boolean = false if (!this.preservePaths) { const [root, stripped] = stripAbsolutePath(this.path) if (root && typeof stripped === 'string') { this.path = stripped - pathWarn = !!root + pathWarn = root } } @@ -229,6 +229,7 @@ export class WriteEntry extends Minipass<Buffer> implements Warner { gid: this.portable ? undefined : this.stat.gid, size: this.stat.size, mtime: this.noMtime ? undefined : this.mtime || this.stat.mtime, + /* c8 ignore next */ type: this.type === 'Unsupported' ? undefined : this.type, uname: this.portable ? undefined @@ -385,7 +386,11 @@ export class WriteEntry extends Minipass<Buffer> implements Warner { }) } - [CLOSE](cb: (er?: null | Error | NodeJS.ErrnoException) => any = () => {}) { + /* c8 ignore start */ + [CLOSE]( + cb: (er?: null | Error | NodeJS.ErrnoException) => any = () => {}, + ) { + /* c8 ignore stop */ if (this.fd !== undefined) fs.close(this.fd, cb) } @@ -541,7 +546,11 @@ export class WriteEntrySync extends WriteEntry implements Warner { cb() } - [CLOSE](cb: (er?: null | Error | NodeJS.ErrnoException) => any = () => {}) { + /* c8 ignore start */ + [CLOSE]( + cb: (er?: null | Error | NodeJS.ErrnoException) => any = () => {}, + ) { + /* c8 ignore stop */ if (this.fd !== undefined) fs.closeSync(this.fd) cb() } @@ -595,7 +604,13 @@ export class WriteEntryTar this.noMtime = !!opt.noMtime this.readEntry = readEntry - this.type = readEntry.type + const { type } = readEntry + /* c8 ignore start */ + if (type === 'Unsupported') { + throw new Error('writing entry that should be ignored') + } + /* c8 ignore stop */ + this.type = type if (this.type === 'Directory' && this.portable) { this.noMtime = true } diff --git a/tap-snapshots/test/normalize-unicode.js.test.cjs b/tap-snapshots/test/normalize-unicode.js.test.cjs index 3163313d..6c7be82a 100644 --- a/tap-snapshots/test/normalize-unicode.js.test.cjs +++ b/tap-snapshots/test/normalize-unicode.js.test.cjs @@ -5,26 +5,26 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/normalize-unicode.js TAP normalize with strip slashes "1/4foo.txt" > normalized 1`] = ` -1/4foo.txt +exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ" > normalized 1`] = ` +īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ ` -exports[`test/normalize-unicode.js TAP normalize with strip slashes "\\\\a\\\\b\\\\c\\\\d\\\\" > normalized 1`] = ` +exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "\\\\a\\\\b\\\\c\\\\d\\\\" > normalized 1`] = ` /a/b/c/d ` -exports[`test/normalize-unicode.js TAP normalize with strip slashes "Âŧfoo.txt" > normalized 1`] = ` -Âŧfoo.txt -` - -exports[`test/normalize-unicode.js TAP normalize with strip slashes "īš¨aaaaīš¨ddddīš¨" > normalized 1`] = ` +exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "īš¨aaaaīš¨ddddīš¨" > normalized 1`] = ` īš¨aaaaīš¨ddddīš¨ ` -exports[`test/normalize-unicode.js TAP normalize with strip slashes "īŧŧbbbīŧŧeeeīŧŧ" > normalized 1`] = ` +exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "īŧŧbbbīŧŧeeeīŧŧ" > normalized 1`] = ` īŧŧbbbīŧŧeeeīŧŧ ` -exports[`test/normalize-unicode.js TAP normalize with strip slashes "īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ" > normalized 1`] = ` -īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ +exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "1/4foo.txt" > normalized 1`] = ` +1/4foo.txt +` + +exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "Âŧfoo.txt" > normalized 1`] = ` +Âŧfoo.txt ` diff --git a/test/create.js b/test/create.js index fdfd78b8..9292c66d 100644 --- a/test/create.js +++ b/test/create.js @@ -1,40 +1,40 @@ -'use strict' +import t from 'tap' +import { c, list, Pack, PackSync } from '../dist/esm/index.js' +import fs from 'fs' +import path from 'path' +import { rimraf } from 'rimraf' +import { mkdirp } from 'mkdirp' +import mutateFS from 'mutate-fs' +import { spawn } from 'child_process' +import { fileURLToPath } from 'url' const isWindows = process.platform === 'win32' -const t = require('tap') -const c = require('../lib/create.js') -const list = require('../lib/list.js') -const fs = require('fs') -const path = require('path') +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) const dir = path.resolve(__dirname, 'fixtures/create') const tars = path.resolve(__dirname, 'fixtures/tars') -const rimraf = require('rimraf') -const mkdirp = require('mkdirp') -const spawn = require('child_process').spawn -const Pack = require('../lib/pack.js') -const mutateFS = require('mutate-fs') -const { promisify } = require('util') const readtar = (file, cb) => { const child = spawn('tar', ['tf', file]) const out = [] child.stdout.on('data', c => out.push(c)) child.on('close', (code, signal) => - cb(code, signal, Buffer.concat(out).toString())) + cb(code, signal, Buffer.concat(out).toString()), + ) } -t.teardown(() => new Promise(resolve => rimraf(dir, resolve))) +t.teardown(() => rimraf(dir)) t.before(async () => { - await promisify(rimraf)(dir) + await rimraf(dir) await mkdirp(dir) }) t.test('no cb if sync or without file', t => { - t.throws(_ => c({ sync: true }, ['asdf'], _ => _)) - t.throws(_ => c(_ => _)) - t.throws(_ => c({}, _ => _)) - t.throws(_ => c({}, ['asdf'], _ => _)) + t.throws(() => c({ sync: true }, ['asdf'], () => {})) + t.throws(() => c(() => {})) + t.throws(() => c({}, () => {})) + t.throws(() => c({}, ['asdf'], () => {})) t.end() }) @@ -43,11 +43,14 @@ t.test('create file', t => { t.test('sync', t => { const file = path.resolve(dir, 'sync.tar') - c({ - file: file, - cwd: __dirname, - sync: true, - }, files) + c( + { + file: file, + cwd: __dirname, + sync: true, + }, + files, + ) readtar(file, (code, signal, list) => { t.equal(code, 0) t.equal(signal, null) @@ -58,28 +61,35 @@ t.test('create file', t => { t.test('async', t => { const file = path.resolve(dir, 'async.tar') - c({ - file: file, - cwd: __dirname, - }, files, er => { - if (er) { - throw er - } - readtar(file, (code, signal, list) => { - t.equal(code, 0) - t.equal(signal, null) - t.equal(list.trim(), 'create.js') - t.end() - }) - }) + c( + { + file: file, + cwd: __dirname, + }, + files, + er => { + if (er) { + throw er + } + readtar(file, (code, signal, list) => { + t.equal(code, 0) + t.equal(signal, null) + t.equal(list.trim(), 'create.js') + t.end() + }) + }, + ) }) t.test('async promise only', t => { const file = path.resolve(dir, 'promise.tar') - c({ - file: file, - cwd: __dirname, - }, files).then(_ => { + c( + { + file: file, + cwd: __dirname, + }, + files, + ).then(() => { readtar(file, (code, signal, list) => { t.equal(code, 0) t.equal(signal, null) @@ -93,12 +103,15 @@ t.test('create file', t => { const mode = isWindows ? 0o666 : 0o740 t.test('sync', t => { const file = path.resolve(dir, 'sync-mode.tar') - c({ - mode: mode, - file: file, - cwd: __dirname, - sync: true, - }, files) + c( + { + mode: mode, + file: file, + cwd: __dirname, + sync: true, + }, + files, + ) readtar(file, (code, signal, list) => { t.equal(code, 0) t.equal(signal, null) @@ -110,22 +123,26 @@ t.test('create file', t => { t.test('async', t => { const file = path.resolve(dir, 'async-mode.tar') - c({ - mode: mode, - file: file, - cwd: __dirname, - }, files, er => { - if (er) { - throw er - } - readtar(file, (code, signal, list) => { - t.equal(code, 0) - t.equal(signal, null) - t.equal(list.trim(), 'create.js') - t.equal(fs.lstatSync(file).mode & 0o7777, mode) - t.end() - }) - }) + c( + { + mode: mode, + file: file, + cwd: __dirname, + }, + files, + er => { + if (er) { + throw er + } + readtar(file, (code, signal, list) => { + t.equal(code, 0) + t.equal(signal, null) + t.equal(list.trim(), 'create.js') + t.equal(fs.lstatSync(file).mode & 0o7777, mode) + t.end() + }) + }, + ) }) t.end() @@ -134,7 +151,7 @@ t.test('create file', t => { }) t.test('create', t => { - t.type(c({ sync: true }, ['README.md']), Pack.Sync) + t.type(c({ sync: true }, ['README.md']), PackSync) t.type(c(['README.md']), Pack) t.end() }) @@ -143,12 +160,17 @@ t.test('open fails', t => { const poop = new Error('poop') const file = path.resolve(dir, 'throw-open.tar') t.teardown(mutateFS.statFail(poop)) - t.throws(_ => c({ - file: file, - sync: true, - cwd: __dirname, - }, [path.basename(__filename)])) - t.throws(_ => fs.lstatSync(file)) + t.throws(() => + c( + { + file: file, + sync: true, + cwd: __dirname, + }, + [path.basename(__filename)], + ), + ) + t.throws(() => fs.lstatSync(file)) t.end() }) @@ -158,25 +180,31 @@ t.test('gzipped tarball that makes some drain/resume stuff', t => { // don't include node_modules/.cache, since that gets written to // by nyc during tests, and can result in spurious errors. - const entries = fs.readdirSync(`${cwd}/node_modules`) - .filter(e => !/^\./.test(e)) + const entries = fs + .readdirSync(`${cwd}/node_modules`) + .filter(e => !/^[@.]/.test(e)) .map(e => `node_modules/${e}`) - c({ z: true, C: cwd }, entries) - .pipe(fs.createWriteStream(out)) - .on('finish', _ => { - const child = spawn('tar', ['tf', out], { - stdio: ['ignore', 'ignore', 'pipe'], - }) - child.stderr.on('data', c => { - t.fail(c + '') - }) - child.on('close', (code, signal) => { - t.equal(code, 0) - t.equal(signal, null) - t.end() - }) + const stream = c({ z: true, C: cwd }, entries) + + const outStream = fs.createWriteStream(out) + outStream.on('drain', () => { + stream.resume() + }) + + stream.pipe(outStream).on('finish', () => { + const child = spawn('tar', ['tf', out], { + stdio: ['ignore', 'ignore', 'pipe'], + }) + child.stderr.on('data', c => { + t.fail(c + '') + }) + child.on('close', (code, signal) => { + t.equal(code, 0) + t.equal(signal, null) + t.end() }) + }) }) t.test('create tarball out of another tarball', t => { @@ -192,7 +220,8 @@ t.test('create tarball out of another tarball', t => { 'hardlink-2', 'symlink', ] - list({ f: out, + list({ + f: out, sync: true, onentry: entry => { if (entry.path === 'hardlink-2') { @@ -205,25 +234,33 @@ t.test('create tarball out of another tarball', t => { t.equal(entry.type, 'File') } t.equal(entry.path, expect.shift()) - } }) + }, + }) t.same(expect, []) t.end() } t.test('sync', t => { - c({ - f: out, - cwd: tars, - sync: true, - }, ['@dir.tar', '@utf8.tar', '@links.tar']) + c( + { + f: out, + cwd: tars, + sync: true, + }, + ['@dir.tar', '@utf8.tar', '@links.tar'], + ) check(t) }) - t.test('async', t => { - c({ - f: out, - cwd: tars, - }, ['@dir.tar', '@utf8.tar', '@links.tar'], _ => check(t)) + t.test('async', async t => { + await c( + { + f: out, + cwd: tars, + }, + ['@dir.tar', '@utf8.tar', '@links.tar'], + ) + check(t) }) t.end() diff --git a/test/cwd-error.js b/test/cwd-error.js new file mode 100644 index 00000000..1961b404 --- /dev/null +++ b/test/cwd-error.js @@ -0,0 +1,10 @@ +import t from 'tap' +import { CwdError } from '../dist/esm/cwd-error.js' + +t.match(new CwdError('path', 'code'), { + name: 'CwdError', + path: 'path', + code: 'code', + syscall: 'chdir', + message: `code: Cannot cd into 'path'`, +}) diff --git a/test/extract.js b/test/extract.js index c11d0afc..8fe8eff1 100644 --- a/test/extract.js +++ b/test/extract.js @@ -1,18 +1,22 @@ -'use strict' - -const t = require('tap') -const nock = require('nock') -const x = require('../lib/extract.js') -const path = require('path') -const fs = require('fs') +import t from 'tap' +import nock from 'nock' +import { extract as x } from '../dist/esm/extract.js' +import path from 'path' +import fs from 'fs' +import { fileURLToPath } from 'url' +import { promisify } from 'util' +import { mkdirp } from 'mkdirp' +import { rimraf } from 'rimraf' +import { pipeline as PL } from 'stream' +import { Unpack, UnpackSync } from '../dist/esm/unpack.js' +const pipeline = promisify(PL) +import http from 'http' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) const extractdir = path.resolve(__dirname, 'fixtures/extract') const tars = path.resolve(__dirname, 'fixtures/tars') -const mkdirp = require('mkdirp') -const { promisify } = require('util') -const rimraf = promisify(require('rimraf')) -const mutateFS = require('mutate-fs') -const pipeline = promisify(require('stream').pipeline) -const http = require('http') +import mutateFS from 'mutate-fs' const tnock = (t, host, opts) => { nock.disableNetConnect() @@ -24,7 +28,7 @@ const tnock = (t, host, opts) => { return server } -t.teardown(_ => rimraf(extractdir)) +t.teardown(() => rimraf(extractdir)) t.test('basic extracting', t => { const file = path.resolve(tars, 'utf8.tar') @@ -38,11 +42,15 @@ t.test('basic extracting', t => { const check = async t => { fs.lstatSync(dir + '/Ί.txt') fs.lstatSync(dir + '/🌟.txt') - t.throws(_ => fs.lstatSync(dir + '/long-path/r/e/a/l/l/y/-/d/e/e/p/-' + - '/f/o/l/d/e/r/-/p/a/t/h/Ί.txt')) + t.throws(() => + fs.lstatSync( + dir + + '/long-path/r/e/a/l/l/y/-/d/e/e/p/-' + + '/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', + ), + ) await rimraf(dir) - t.end() } const files = ['🌟.txt', 'Ί.txt'] @@ -51,12 +59,13 @@ t.test('basic extracting', t => { return check(t) }) - t.test('async promisey', t => { - return x({ file: file, cwd: dir }, files).then(_ => check(t)) + t.test('async promisey', async t => { + await x({ file: file, cwd: dir }, files) + return check(t) }) - t.test('async cb', t => { - return x({ file: file, cwd: dir }, files, er => { + t.test('async cb', async t => { + await x({ file: file, cwd: dir }, files, er => { if (er) { throw er } @@ -67,11 +76,11 @@ t.test('basic extracting', t => { t.end() }) -t.test('ensure an open stream is not prematuraly closed', t => { +t.test('ensure an open stream is not prematurely closed', t => { t.plan(1) const file = path.resolve(tars, 'long-paths.tar') - const dir = path.resolve(extractdir, 'basic-with-stream') + const dir = t.testdir({}) t.beforeEach(async () => { await rimraf(dir) @@ -84,14 +93,12 @@ t.test('ensure an open stream is not prematuraly closed', t => { t.end() } - t.test('async promisey', t => { + t.test('async promisey', async t => { const stream = fs.createReadStream(file, { highWaterMark: 1, }) - pipeline( - stream, - x({ cwd: dir }) - ).then(_ => check(t)) + await pipeline(stream, x({ cwd: dir })) + return check(t) }) t.end() @@ -120,12 +127,13 @@ t.test('ensure an open stream is not prematuraly closed http', t => { .delay(250) .reply(200, () => fs.createReadStream(file)) - http.get('http://codeload.github.com/npm/node-tar/tar.gz/main', (stream) => { - return pipeline( - stream, - x({ cwd: dir }) - ).then(_ => check(t)) - }) + http.get( + 'http://codeload.github.com/npm/node-tar/tar.gz/main', + async stream => { + await pipeline(stream, x({ cwd: dir })) + return check(t) + }, + ) }) t.end() @@ -142,34 +150,47 @@ t.test('file list and filter', t => { const check = async t => { fs.lstatSync(dir + '/Ί.txt') - t.throws(_ => fs.lstatSync(dir + '/🌟.txt')) - t.throws(_ => fs.lstatSync(dir + '/long-path/r/e/a/l/l/y/-/d/e/e/p/-' + - '/f/o/l/d/e/r/-/p/a/t/h/Ί.txt')) + t.throws(() => fs.lstatSync(dir + '/🌟.txt')) + t.throws(() => + fs.lstatSync( + dir + + '/long-path/r/e/a/l/l/y/-/d/e/e/p/-' + + '/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', + ), + ) await rimraf(dir) - t.end() } const filter = path => path === 'Ί.txt' t.test('sync', t => { - x({ filter: filter, file: file, sync: true, C: dir }, ['🌟.txt', 'Ί.txt']) + x({ filter: filter, file: file, sync: true, C: dir }, [ + '🌟.txt', + 'Ί.txt', + ]) return check(t) }) - t.test('async promisey', t => { - return x({ filter: filter, file: file, cwd: dir }, ['🌟.txt', 'Ί.txt']).then(_ => { - return check(t) - }) + t.test('async promisey', async t => { + await x({ filter: filter, file: file, cwd: dir }, [ + '🌟.txt', + 'Ί.txt', + ]) + check(t) }) t.test('async cb', t => { - return x({ filter: filter, file: file, cwd: dir }, ['🌟.txt', 'Ί.txt'], er => { - if (er) { - throw er - } - return check(t) - }) + return x( + { filter: filter, file: file, cwd: dir }, + ['🌟.txt', 'Ί.txt'], + er => { + if (er) { + throw er + } + return check(t) + }, + ) }) t.end() @@ -185,12 +206,17 @@ t.test('no file list', t => { }) const check = async t => { - t.equal(fs.lstatSync(path.resolve(dir, '1024-bytes.txt')).size, 1024) - t.equal(fs.lstatSync(path.resolve(dir, '512-bytes.txt')).size, 512) + t.equal( + fs.lstatSync(path.resolve(dir, '1024-bytes.txt')).size, + 1024, + ) + t.equal( + fs.lstatSync(path.resolve(dir, '512-bytes.txt')).size, + 512, + ) t.equal(fs.lstatSync(path.resolve(dir, 'one-byte.txt')).size, 1) t.equal(fs.lstatSync(path.resolve(dir, 'zero-byte.txt')).size, 0) await rimraf(dir) - t.end() } t.test('sync', t => { @@ -198,10 +224,9 @@ t.test('no file list', t => { return check(t) }) - t.test('async promisey', t => { - return x({ file: file, cwd: dir }).then(_ => { - return check(t) - }) + t.test('async promisey', async t => { + await x({ file: file, cwd: dir }) + return check(t) }) t.test('async cb', t => { @@ -227,12 +252,17 @@ t.test('read in itty bits', t => { }) const check = async t => { - t.equal(fs.lstatSync(path.resolve(dir, '1024-bytes.txt')).size, 1024) - t.equal(fs.lstatSync(path.resolve(dir, '512-bytes.txt')).size, 512) + t.equal( + fs.lstatSync(path.resolve(dir, '1024-bytes.txt')).size, + 1024, + ) + t.equal( + fs.lstatSync(path.resolve(dir, '512-bytes.txt')).size, + 512, + ) t.equal(fs.lstatSync(path.resolve(dir, 'one-byte.txt')).size, 1) t.equal(fs.lstatSync(path.resolve(dir, 'zero-byte.txt')).size, 0) await rimraf(dir) - t.end() } t.test('sync', t => { @@ -240,49 +270,53 @@ t.test('read in itty bits', t => { return check(t) }) - t.test('async promisey', t => { - return x({ file: file, cwd: dir, maxReadSize: maxReadSize }).then(_ => { - return check(t) - }) + t.test('async promisey', async t => { + await x({ file: file, cwd: dir, maxReadSize: maxReadSize }) + return check(t) }) t.test('async cb', t => { - return x({ file: file, cwd: dir, maxReadSize: maxReadSize }, er => { - if (er) { - throw er - } - return check(t) - }) + return x( + { file: file, cwd: dir, maxReadSize: maxReadSize }, + er => { + if (er) { + throw er + } + return check(t) + }, + ) }) t.end() }) t.test('bad calls', t => { - t.throws(_ => x(_ => _)) - t.throws(_ => x({ sync: true }, _ => _)) - t.throws(_ => x({ sync: true }, [], _ => _)) + t.throws(() => x(() => {})) + t.throws(() => x({ sync: true }, () => {})) + t.throws(() => x({ sync: true }, [], () => {})) t.end() }) t.test('no file', t => { - const Unpack = require('../lib/unpack.js') t.type(x(), Unpack) t.type(x(['asdf']), Unpack) - t.type(x({ sync: true }), Unpack.Sync) + t.type(x({ sync: true }), UnpackSync) t.end() }) t.test('nonexistent', t => { - t.throws(_ => x({ sync: true, file: 'does not exist' })) - x({ file: 'does not exist' }).catch(_ => t.end()) + t.throws(() => x({ sync: true, file: 'does not exist' })) + x({ file: 'does not exist' }).catch(() => t.end()) }) t.test('read fail', t => { const poop = new Error('poop') t.teardown(mutateFS.fail('read', poop)) - t.throws(_ => x({ maxReadSize: 10, sync: true, file: __filename }), poop) + t.throws( + () => x({ maxReadSize: 10, sync: true, file: __filename }), + poop, + ) t.end() }) @@ -305,8 +339,18 @@ t.test('sync gzip error edge case test', async t => { }, }) - t.same(fs.readdirSync(dir + '/x').sort(), - ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']) + t.same(fs.readdirSync(dir + '/x').sort(), [ + '1', + '10', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + ]) t.end() }) @@ -328,24 +372,46 @@ t.test('brotli', async t => { const f = fs.openSync(filename, 'a') fs.closeSync(f) - const expect = new Error('TAR_BAD_ARCHIVE: Unrecognized archive format') + const expect = new Error( + 'TAR_BAD_ARCHIVE: Unrecognized archive format', + ) - t.throws(_ => x({ sync: true, file: filename }), expect) + t.throws(() => x({ sync: true, file: filename }), expect) }) t.test('succeeds based on file extension', t => { x({ sync: true, file: file, C: dir }) - t.same(fs.readdirSync(dir + '/x').sort(), - ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']) + t.same(fs.readdirSync(dir + '/x').sort(), [ + '1', + '10', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + ]) t.end() }) t.test('succeeds when passed explicit option', t => { x({ sync: true, file: file, C: dir, brotli: true }) - t.same(fs.readdirSync(dir + '/x').sort(), - ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']) + t.same(fs.readdirSync(dir + '/x').sort(), [ + '1', + '10', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + ]) t.end() }) }) diff --git a/test/fixtures/make-tar.js b/test/fixtures/make-tar.js new file mode 100644 index 00000000..77ee2b26 --- /dev/null +++ b/test/fixtures/make-tar.js @@ -0,0 +1,26 @@ +import { Header } from '../../dist/esm/header.js' +export const makeTar = chunks => { + let dataLen = 0 + return Buffer.concat( + chunks.map(chunk => { + if (Buffer.isBuffer(chunk)) { + dataLen += chunk.length + return chunk + } + const size = Math.max( + typeof chunk === 'string' + ? 512 * Math.ceil(chunk.length / 512) + : 512, + ) + dataLen += size + const buf = Buffer.alloc(size) + if (typeof chunk === 'string') { + buf.write(chunk) + } else { + new Header(chunk).encode(buf, 0) + } + return buf + }), + dataLen, + ) +} diff --git a/test/fixtures/parse/bad-cksum--filter-strict.json b/test/fixtures/parse/bad-cksum--filter-strict.json index edfce539..48e0680b 100644 --- a/test/fixtures/parse/bad-cksum--filter-strict.json +++ b/test/fixtures/parse/bad-cksum--filter-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/bad-cksum--filter.json b/test/fixtures/parse/bad-cksum--filter.json index 55274a4e..d2664877 100644 --- a/test/fixtures/parse/bad-cksum--filter.json +++ b/test/fixtures/parse/bad-cksum--filter.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/bad-cksum--meta-250-filter-strict.json b/test/fixtures/parse/bad-cksum--meta-250-filter-strict.json index edfce539..48e0680b 100644 --- a/test/fixtures/parse/bad-cksum--meta-250-filter-strict.json +++ b/test/fixtures/parse/bad-cksum--meta-250-filter-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/bad-cksum--meta-250-filter.json b/test/fixtures/parse/bad-cksum--meta-250-filter.json index 55274a4e..d2664877 100644 --- a/test/fixtures/parse/bad-cksum--meta-250-filter.json +++ b/test/fixtures/parse/bad-cksum--meta-250-filter.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/bad-cksum--meta-250-strict.json b/test/fixtures/parse/bad-cksum--meta-250-strict.json index edfce539..48e0680b 100644 --- a/test/fixtures/parse/bad-cksum--meta-250-strict.json +++ b/test/fixtures/parse/bad-cksum--meta-250-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/bad-cksum--meta-250.json b/test/fixtures/parse/bad-cksum--meta-250.json index 55274a4e..d2664877 100644 --- a/test/fixtures/parse/bad-cksum--meta-250.json +++ b/test/fixtures/parse/bad-cksum--meta-250.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/bad-cksum--strict.json b/test/fixtures/parse/bad-cksum--strict.json index edfce539..48e0680b 100644 --- a/test/fixtures/parse/bad-cksum--strict.json +++ b/test/fixtures/parse/bad-cksum--strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/bad-cksum.json b/test/fixtures/parse/bad-cksum.json index 55274a4e..d2664877 100644 --- a/test/fixtures/parse/bad-cksum.json +++ b/test/fixtures/parse/bad-cksum.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/body-byte-counts--filter-strict.json b/test/fixtures/parse/body-byte-counts--filter-strict.json index 7290291b..9462cd61 100644 --- a/test/fixtures/parse/body-byte-counts--filter-strict.json +++ b/test/fixtures/parse/body-byte-counts--filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1024, "mtime": "2017-04-10T16:57:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -54,9 +45,6 @@ "gname": "staff", "size": 512, "mtime": "2017-04-10T17:08:55.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -93,9 +77,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -110,17 +91,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -132,9 +109,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:08:01.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -149,9 +123,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/body-byte-counts--filter.json b/test/fixtures/parse/body-byte-counts--filter.json index 7290291b..9462cd61 100644 --- a/test/fixtures/parse/body-byte-counts--filter.json +++ b/test/fixtures/parse/body-byte-counts--filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1024, "mtime": "2017-04-10T16:57:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -54,9 +45,6 @@ "gname": "staff", "size": 512, "mtime": "2017-04-10T17:08:55.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -93,9 +77,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -110,17 +91,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -132,9 +109,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:08:01.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -149,9 +123,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/body-byte-counts--meta-250-filter-strict.json b/test/fixtures/parse/body-byte-counts--meta-250-filter-strict.json index 7290291b..9462cd61 100644 --- a/test/fixtures/parse/body-byte-counts--meta-250-filter-strict.json +++ b/test/fixtures/parse/body-byte-counts--meta-250-filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1024, "mtime": "2017-04-10T16:57:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -54,9 +45,6 @@ "gname": "staff", "size": 512, "mtime": "2017-04-10T17:08:55.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -93,9 +77,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -110,17 +91,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -132,9 +109,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:08:01.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -149,9 +123,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/body-byte-counts--meta-250-filter.json b/test/fixtures/parse/body-byte-counts--meta-250-filter.json index 7290291b..9462cd61 100644 --- a/test/fixtures/parse/body-byte-counts--meta-250-filter.json +++ b/test/fixtures/parse/body-byte-counts--meta-250-filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1024, "mtime": "2017-04-10T16:57:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -54,9 +45,6 @@ "gname": "staff", "size": 512, "mtime": "2017-04-10T17:08:55.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -93,9 +77,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -110,17 +91,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -132,9 +109,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:08:01.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -149,9 +123,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/body-byte-counts--meta-250-strict.json b/test/fixtures/parse/body-byte-counts--meta-250-strict.json index 8069e9cd..8ae48534 100644 --- a/test/fixtures/parse/body-byte-counts--meta-250-strict.json +++ b/test/fixtures/parse/body-byte-counts--meta-250-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1024, "mtime": "2017-04-10T16:57:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -54,9 +45,6 @@ "gname": "staff", "size": 512, "mtime": "2017-04-10T17:08:55.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -93,9 +77,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -110,17 +91,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -132,9 +109,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:08:01.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -149,9 +123,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/body-byte-counts--meta-250.json b/test/fixtures/parse/body-byte-counts--meta-250.json index 8069e9cd..8ae48534 100644 --- a/test/fixtures/parse/body-byte-counts--meta-250.json +++ b/test/fixtures/parse/body-byte-counts--meta-250.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1024, "mtime": "2017-04-10T16:57:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -54,9 +45,6 @@ "gname": "staff", "size": 512, "mtime": "2017-04-10T17:08:55.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -93,9 +77,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -110,17 +91,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -132,9 +109,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:08:01.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -149,9 +123,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/body-byte-counts--strict.json b/test/fixtures/parse/body-byte-counts--strict.json index 8069e9cd..8ae48534 100644 --- a/test/fixtures/parse/body-byte-counts--strict.json +++ b/test/fixtures/parse/body-byte-counts--strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1024, "mtime": "2017-04-10T16:57:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -54,9 +45,6 @@ "gname": "staff", "size": 512, "mtime": "2017-04-10T17:08:55.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -93,9 +77,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -110,17 +91,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -132,9 +109,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:08:01.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -149,9 +123,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/body-byte-counts.json b/test/fixtures/parse/body-byte-counts.json index 8069e9cd..8ae48534 100644 --- a/test/fixtures/parse/body-byte-counts.json +++ b/test/fixtures/parse/body-byte-counts.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1024, "mtime": "2017-04-10T16:57:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -54,9 +45,6 @@ "gname": "staff", "size": 512, "mtime": "2017-04-10T17:08:55.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -93,9 +77,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -110,17 +91,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -132,9 +109,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:08:01.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -149,9 +123,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/dir--filter-strict.json b/test/fixtures/parse/dir--filter-strict.json index 69926438..52757dae 100644 --- a/test/fixtures/parse/dir--filter-strict.json +++ b/test/fixtures/parse/dir--filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:00:17.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/dir--filter.json b/test/fixtures/parse/dir--filter.json index 69926438..52757dae 100644 --- a/test/fixtures/parse/dir--filter.json +++ b/test/fixtures/parse/dir--filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:00:17.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/dir--meta-250-filter-strict.json b/test/fixtures/parse/dir--meta-250-filter-strict.json index 69926438..52757dae 100644 --- a/test/fixtures/parse/dir--meta-250-filter-strict.json +++ b/test/fixtures/parse/dir--meta-250-filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:00:17.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/dir--meta-250-filter.json b/test/fixtures/parse/dir--meta-250-filter.json index 69926438..52757dae 100644 --- a/test/fixtures/parse/dir--meta-250-filter.json +++ b/test/fixtures/parse/dir--meta-250-filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:00:17.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/dir--meta-250-strict.json b/test/fixtures/parse/dir--meta-250-strict.json index 0a933bf5..0688cc0b 100644 --- a/test/fixtures/parse/dir--meta-250-strict.json +++ b/test/fixtures/parse/dir--meta-250-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:00:17.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/dir--meta-250.json b/test/fixtures/parse/dir--meta-250.json index 0a933bf5..0688cc0b 100644 --- a/test/fixtures/parse/dir--meta-250.json +++ b/test/fixtures/parse/dir--meta-250.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:00:17.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/dir--strict.json b/test/fixtures/parse/dir--strict.json index 0a933bf5..0688cc0b 100644 --- a/test/fixtures/parse/dir--strict.json +++ b/test/fixtures/parse/dir--strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:00:17.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/dir.json b/test/fixtures/parse/dir.json index 0a933bf5..0688cc0b 100644 --- a/test/fixtures/parse/dir.json +++ b/test/fixtures/parse/dir.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T17:00:17.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/emptypax--filter-strict.json b/test/fixtures/parse/emptypax--filter-strict.json index 2810367d..eb30c2be 100644 --- a/test/fixtures/parse/emptypax--filter-strict.json +++ b/test/fixtures/parse/emptypax--filter-strict.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:33:21.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -37,8 +26,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:33:21.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,17 +40,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -75,9 +58,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/emptypax--filter.json b/test/fixtures/parse/emptypax--filter.json index 2810367d..eb30c2be 100644 --- a/test/fixtures/parse/emptypax--filter.json +++ b/test/fixtures/parse/emptypax--filter.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:33:21.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -37,8 +26,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:33:21.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,17 +40,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -75,9 +58,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/emptypax--meta-250-filter-strict.json b/test/fixtures/parse/emptypax--meta-250-filter-strict.json index 2810367d..eb30c2be 100644 --- a/test/fixtures/parse/emptypax--meta-250-filter-strict.json +++ b/test/fixtures/parse/emptypax--meta-250-filter-strict.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:33:21.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -37,8 +26,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:33:21.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,17 +40,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -75,9 +58,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/emptypax--meta-250-filter.json b/test/fixtures/parse/emptypax--meta-250-filter.json index 2810367d..eb30c2be 100644 --- a/test/fixtures/parse/emptypax--meta-250-filter.json +++ b/test/fixtures/parse/emptypax--meta-250-filter.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:33:21.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -37,8 +26,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:33:21.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,17 +40,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -75,9 +58,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/emptypax--meta-250-strict.json b/test/fixtures/parse/emptypax--meta-250-strict.json index 686a428a..55125fe7 100644 --- a/test/fixtures/parse/emptypax--meta-250-strict.json +++ b/test/fixtures/parse/emptypax--meta-250-strict.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:33:21.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -37,8 +26,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:33:21.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,17 +40,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -75,9 +58,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/emptypax--meta-250.json b/test/fixtures/parse/emptypax--meta-250.json index 686a428a..55125fe7 100644 --- a/test/fixtures/parse/emptypax--meta-250.json +++ b/test/fixtures/parse/emptypax--meta-250.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:33:21.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -37,8 +26,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:33:21.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,17 +40,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -75,9 +58,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/emptypax--strict.json b/test/fixtures/parse/emptypax--strict.json index 686a428a..55125fe7 100644 --- a/test/fixtures/parse/emptypax--strict.json +++ b/test/fixtures/parse/emptypax--strict.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:33:21.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -37,8 +26,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:33:21.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,17 +40,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -75,9 +58,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/emptypax.json b/test/fixtures/parse/emptypax.json index 686a428a..55125fe7 100644 --- a/test/fixtures/parse/emptypax.json +++ b/test/fixtures/parse/emptypax.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:33:21.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -37,8 +26,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:33:21.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,17 +40,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -75,9 +58,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/file--filter-strict.json b/test/fixtures/parse/file--filter-strict.json index 07e38b45..800a4e51 100644 --- a/test/fixtures/parse/file--filter-strict.json +++ b/test/fixtures/parse/file--filter-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/file--filter.json b/test/fixtures/parse/file--filter.json index 07e38b45..800a4e51 100644 --- a/test/fixtures/parse/file--filter.json +++ b/test/fixtures/parse/file--filter.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/file--meta-250-filter-strict.json b/test/fixtures/parse/file--meta-250-filter-strict.json index 07e38b45..800a4e51 100644 --- a/test/fixtures/parse/file--meta-250-filter-strict.json +++ b/test/fixtures/parse/file--meta-250-filter-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/file--meta-250-filter.json b/test/fixtures/parse/file--meta-250-filter.json index 07e38b45..800a4e51 100644 --- a/test/fixtures/parse/file--meta-250-filter.json +++ b/test/fixtures/parse/file--meta-250-filter.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/file--meta-250-strict.json b/test/fixtures/parse/file--meta-250-strict.json index 07e38b45..800a4e51 100644 --- a/test/fixtures/parse/file--meta-250-strict.json +++ b/test/fixtures/parse/file--meta-250-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/file--meta-250.json b/test/fixtures/parse/file--meta-250.json index 07e38b45..800a4e51 100644 --- a/test/fixtures/parse/file--meta-250.json +++ b/test/fixtures/parse/file--meta-250.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/file--strict.json b/test/fixtures/parse/file--strict.json index 07e38b45..800a4e51 100644 --- a/test/fixtures/parse/file--strict.json +++ b/test/fixtures/parse/file--strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/file.json b/test/fixtures/parse/file.json index 07e38b45..800a4e51 100644 --- a/test/fixtures/parse/file.json +++ b/test/fixtures/parse/file.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/global-header--filter-strict.json b/test/fixtures/parse/global-header--filter-strict.json index 114679a2..3032d06b 100644 --- a/test/fixtures/parse/global-header--filter-strict.json +++ b/test/fixtures/parse/global-header--filter-strict.json @@ -6,23 +6,8 @@ [ "entry", { - "extended": null, "globalExtended": { - "atime": null, - "charset": null, - "comment": null, - "ctime": null, - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, "path": "ab", - "size": null, - "uid": null, - "uname": null, - "dev": null, - "ino": null, - "nlink": null, "global": true }, "type": "File", @@ -36,9 +21,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +35,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/global-header--filter.json b/test/fixtures/parse/global-header--filter.json index 114679a2..3032d06b 100644 --- a/test/fixtures/parse/global-header--filter.json +++ b/test/fixtures/parse/global-header--filter.json @@ -6,23 +6,8 @@ [ "entry", { - "extended": null, "globalExtended": { - "atime": null, - "charset": null, - "comment": null, - "ctime": null, - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, "path": "ab", - "size": null, - "uid": null, - "uname": null, - "dev": null, - "ino": null, - "nlink": null, "global": true }, "type": "File", @@ -36,9 +21,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +35,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/global-header--meta-250-filter-strict.json b/test/fixtures/parse/global-header--meta-250-filter-strict.json index 114679a2..3032d06b 100644 --- a/test/fixtures/parse/global-header--meta-250-filter-strict.json +++ b/test/fixtures/parse/global-header--meta-250-filter-strict.json @@ -6,23 +6,8 @@ [ "entry", { - "extended": null, "globalExtended": { - "atime": null, - "charset": null, - "comment": null, - "ctime": null, - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, "path": "ab", - "size": null, - "uid": null, - "uname": null, - "dev": null, - "ino": null, - "nlink": null, "global": true }, "type": "File", @@ -36,9 +21,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +35,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/global-header--meta-250-filter.json b/test/fixtures/parse/global-header--meta-250-filter.json index 114679a2..3032d06b 100644 --- a/test/fixtures/parse/global-header--meta-250-filter.json +++ b/test/fixtures/parse/global-header--meta-250-filter.json @@ -6,23 +6,8 @@ [ "entry", { - "extended": null, "globalExtended": { - "atime": null, - "charset": null, - "comment": null, - "ctime": null, - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, "path": "ab", - "size": null, - "uid": null, - "uname": null, - "dev": null, - "ino": null, - "nlink": null, "global": true }, "type": "File", @@ -36,9 +21,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +35,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/global-header--meta-250-strict.json b/test/fixtures/parse/global-header--meta-250-strict.json index 114679a2..3032d06b 100644 --- a/test/fixtures/parse/global-header--meta-250-strict.json +++ b/test/fixtures/parse/global-header--meta-250-strict.json @@ -6,23 +6,8 @@ [ "entry", { - "extended": null, "globalExtended": { - "atime": null, - "charset": null, - "comment": null, - "ctime": null, - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, "path": "ab", - "size": null, - "uid": null, - "uname": null, - "dev": null, - "ino": null, - "nlink": null, "global": true }, "type": "File", @@ -36,9 +21,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +35,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/global-header--meta-250.json b/test/fixtures/parse/global-header--meta-250.json index 114679a2..3032d06b 100644 --- a/test/fixtures/parse/global-header--meta-250.json +++ b/test/fixtures/parse/global-header--meta-250.json @@ -6,23 +6,8 @@ [ "entry", { - "extended": null, "globalExtended": { - "atime": null, - "charset": null, - "comment": null, - "ctime": null, - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, "path": "ab", - "size": null, - "uid": null, - "uname": null, - "dev": null, - "ino": null, - "nlink": null, "global": true }, "type": "File", @@ -36,9 +21,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +35,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/global-header--strict.json b/test/fixtures/parse/global-header--strict.json index 114679a2..3032d06b 100644 --- a/test/fixtures/parse/global-header--strict.json +++ b/test/fixtures/parse/global-header--strict.json @@ -6,23 +6,8 @@ [ "entry", { - "extended": null, "globalExtended": { - "atime": null, - "charset": null, - "comment": null, - "ctime": null, - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, "path": "ab", - "size": null, - "uid": null, - "uname": null, - "dev": null, - "ino": null, - "nlink": null, "global": true }, "type": "File", @@ -36,9 +21,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +35,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/global-header.json b/test/fixtures/parse/global-header.json index 114679a2..3032d06b 100644 --- a/test/fixtures/parse/global-header.json +++ b/test/fixtures/parse/global-header.json @@ -6,23 +6,8 @@ [ "entry", { - "extended": null, "globalExtended": { - "atime": null, - "charset": null, - "comment": null, - "ctime": null, - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, "path": "ab", - "size": null, - "uid": null, - "uname": null, - "dev": null, - "ino": null, - "nlink": null, "global": true }, "type": "File", @@ -36,9 +21,6 @@ "gname": "staff", "size": 1, "mtime": "2017-04-10T16:58:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +35,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links--filter-strict.json b/test/fixtures/parse/links--filter-strict.json index ed902aa1..acf569af 100644 --- a/test/fixtures/parse/links--filter-strict.json +++ b/test/fixtures/parse/links--filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 26, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -54,8 +45,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-1", "header": { "cksumValid": true, @@ -71,17 +60,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -93,8 +78,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -110,9 +93,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links--filter.json b/test/fixtures/parse/links--filter.json index ed902aa1..acf569af 100644 --- a/test/fixtures/parse/links--filter.json +++ b/test/fixtures/parse/links--filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 26, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -54,8 +45,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-1", "header": { "cksumValid": true, @@ -71,17 +60,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -93,8 +78,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -110,9 +93,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links--meta-250-filter-strict.json b/test/fixtures/parse/links--meta-250-filter-strict.json index ed902aa1..acf569af 100644 --- a/test/fixtures/parse/links--meta-250-filter-strict.json +++ b/test/fixtures/parse/links--meta-250-filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 26, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -54,8 +45,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-1", "header": { "cksumValid": true, @@ -71,17 +60,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -93,8 +78,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -110,9 +93,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links--meta-250-filter.json b/test/fixtures/parse/links--meta-250-filter.json index ed902aa1..acf569af 100644 --- a/test/fixtures/parse/links--meta-250-filter.json +++ b/test/fixtures/parse/links--meta-250-filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 26, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -54,8 +45,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-1", "header": { "cksumValid": true, @@ -71,17 +60,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -93,8 +78,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -110,9 +93,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links--meta-250-strict.json b/test/fixtures/parse/links--meta-250-strict.json index fdf07254..216a3ba7 100644 --- a/test/fixtures/parse/links--meta-250-strict.json +++ b/test/fixtures/parse/links--meta-250-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 26, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -54,8 +45,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-1", "header": { "cksumValid": true, @@ -71,17 +60,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -93,8 +78,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -110,9 +93,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links--meta-250.json b/test/fixtures/parse/links--meta-250.json index fdf07254..216a3ba7 100644 --- a/test/fixtures/parse/links--meta-250.json +++ b/test/fixtures/parse/links--meta-250.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 26, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -54,8 +45,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-1", "header": { "cksumValid": true, @@ -71,17 +60,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -93,8 +78,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -110,9 +93,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links--strict.json b/test/fixtures/parse/links--strict.json index fdf07254..216a3ba7 100644 --- a/test/fixtures/parse/links--strict.json +++ b/test/fixtures/parse/links--strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 26, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -54,8 +45,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-1", "header": { "cksumValid": true, @@ -71,17 +60,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -93,8 +78,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -110,9 +93,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-invalid--filter-strict.json b/test/fixtures/parse/links-invalid--filter-strict.json index fd2d5dc8..6fdfb2d5 100644 --- a/test/fixtures/parse/links-invalid--filter-strict.json +++ b/test/fixtures/parse/links-invalid--filter-strict.json @@ -23,8 +23,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -36,8 +34,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -53,9 +49,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-invalid--filter.json b/test/fixtures/parse/links-invalid--filter.json index 42a58d14..1e14b8a0 100644 --- a/test/fixtures/parse/links-invalid--filter.json +++ b/test/fixtures/parse/links-invalid--filter.json @@ -17,8 +17,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -30,8 +28,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -47,9 +43,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-invalid--meta-250-filter-strict.json b/test/fixtures/parse/links-invalid--meta-250-filter-strict.json index fd2d5dc8..6fdfb2d5 100644 --- a/test/fixtures/parse/links-invalid--meta-250-filter-strict.json +++ b/test/fixtures/parse/links-invalid--meta-250-filter-strict.json @@ -23,8 +23,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -36,8 +34,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -53,9 +49,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-invalid--meta-250-filter.json b/test/fixtures/parse/links-invalid--meta-250-filter.json index 42a58d14..1e14b8a0 100644 --- a/test/fixtures/parse/links-invalid--meta-250-filter.json +++ b/test/fixtures/parse/links-invalid--meta-250-filter.json @@ -17,8 +17,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -30,8 +28,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -47,9 +43,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-invalid--meta-250-strict.json b/test/fixtures/parse/links-invalid--meta-250-strict.json index 0c6c72d0..6e9c1531 100644 --- a/test/fixtures/parse/links-invalid--meta-250-strict.json +++ b/test/fixtures/parse/links-invalid--meta-250-strict.json @@ -23,8 +23,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -36,8 +34,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -53,9 +49,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-invalid--meta-250.json b/test/fixtures/parse/links-invalid--meta-250.json index c62395e3..569dcb62 100644 --- a/test/fixtures/parse/links-invalid--meta-250.json +++ b/test/fixtures/parse/links-invalid--meta-250.json @@ -17,8 +17,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -30,8 +28,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -47,9 +43,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-invalid--strict.json b/test/fixtures/parse/links-invalid--strict.json index 0c6c72d0..6e9c1531 100644 --- a/test/fixtures/parse/links-invalid--strict.json +++ b/test/fixtures/parse/links-invalid--strict.json @@ -23,8 +23,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -36,8 +34,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -53,9 +49,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-invalid.json b/test/fixtures/parse/links-invalid.json index c62395e3..569dcb62 100644 --- a/test/fixtures/parse/links-invalid.json +++ b/test/fixtures/parse/links-invalid.json @@ -17,8 +17,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -30,8 +28,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -47,9 +43,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-strip--filter-strict.json b/test/fixtures/parse/links-strip--filter-strict.json index 9a640e0b..47069c6b 100644 --- a/test/fixtures/parse/links-strip--filter-strict.json +++ b/test/fixtures/parse/links-strip--filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -54,9 +45,6 @@ "gname": "", "size": 26, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -93,8 +77,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -110,17 +92,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -132,8 +110,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -149,17 +125,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -171,8 +143,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -188,9 +158,7 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-strip--filter.json b/test/fixtures/parse/links-strip--filter.json index 9a640e0b..47069c6b 100644 --- a/test/fixtures/parse/links-strip--filter.json +++ b/test/fixtures/parse/links-strip--filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -54,9 +45,6 @@ "gname": "", "size": 26, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -93,8 +77,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -110,17 +92,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -132,8 +110,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -149,17 +125,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -171,8 +143,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -188,9 +158,7 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-strip--meta-250-filter-strict.json b/test/fixtures/parse/links-strip--meta-250-filter-strict.json index 9a640e0b..47069c6b 100644 --- a/test/fixtures/parse/links-strip--meta-250-filter-strict.json +++ b/test/fixtures/parse/links-strip--meta-250-filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -54,9 +45,6 @@ "gname": "", "size": 26, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -93,8 +77,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -110,17 +92,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -132,8 +110,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -149,17 +125,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -171,8 +143,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -188,9 +158,7 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-strip--meta-250-filter.json b/test/fixtures/parse/links-strip--meta-250-filter.json index 9a640e0b..47069c6b 100644 --- a/test/fixtures/parse/links-strip--meta-250-filter.json +++ b/test/fixtures/parse/links-strip--meta-250-filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -54,9 +45,6 @@ "gname": "", "size": 26, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -93,8 +77,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -110,17 +92,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": true, @@ -132,8 +110,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -149,17 +125,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -171,8 +143,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -188,9 +158,7 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-strip--meta-250-strict.json b/test/fixtures/parse/links-strip--meta-250-strict.json index 17e5397d..f908c9e3 100644 --- a/test/fixtures/parse/links-strip--meta-250-strict.json +++ b/test/fixtures/parse/links-strip--meta-250-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -54,9 +45,6 @@ "gname": "", "size": 26, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -93,8 +77,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -110,17 +92,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -132,8 +110,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -149,17 +125,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -171,8 +143,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -188,9 +158,7 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-strip--meta-250.json b/test/fixtures/parse/links-strip--meta-250.json index 17e5397d..f908c9e3 100644 --- a/test/fixtures/parse/links-strip--meta-250.json +++ b/test/fixtures/parse/links-strip--meta-250.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -54,9 +45,6 @@ "gname": "", "size": 26, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -93,8 +77,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -110,17 +92,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -132,8 +110,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -149,17 +125,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -171,8 +143,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -188,9 +158,7 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-strip--strict.json b/test/fixtures/parse/links-strip--strict.json index 17e5397d..f908c9e3 100644 --- a/test/fixtures/parse/links-strip--strict.json +++ b/test/fixtures/parse/links-strip--strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -54,9 +45,6 @@ "gname": "", "size": 26, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -93,8 +77,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -110,17 +92,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -132,8 +110,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -149,17 +125,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -171,8 +143,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -188,9 +158,7 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links-strip.json b/test/fixtures/parse/links-strip.json index 17e5397d..f908c9e3 100644 --- a/test/fixtures/parse/links-strip.json +++ b/test/fixtures/parse/links-strip.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -54,9 +45,6 @@ "gname": "", "size": 26, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,17 +59,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -93,8 +77,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -110,17 +92,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -132,8 +110,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "strip-dir/hardlink-1", "header": { "cksumValid": true, @@ -149,17 +125,13 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -171,8 +143,6 @@ "gname": "", "size": 0, "mtime": "2018-11-06T01:45:25.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -188,9 +158,7 @@ "uname": "", "gname": "", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/links.json b/test/fixtures/parse/links.json index fdf07254..216a3ba7 100644 --- a/test/fixtures/parse/links.json +++ b/test/fixtures/parse/links.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 26, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Link", "meta": false, "ignore": false, @@ -54,8 +45,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:05.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-1", "header": { "cksumValid": true, @@ -71,17 +60,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -93,8 +78,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T19:27:33.000Z", - "atime": null, - "ctime": null, "linkpath": "hardlink-2", "header": { "cksumValid": true, @@ -110,9 +93,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-paths--filter-strict.json b/test/fixtures/parse/long-paths--filter-strict.json index 8dfe9de3..53e376da 100644 --- a/test/fixtures/parse/long-paths--filter-strict.json +++ b/test/fixtures/parse/long-paths--filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:53:02.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -47,23 +40,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:54:12.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836297, "nlink": 1, + "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -76,8 +58,6 @@ "size": 100, "mtime": "2017-04-10T16:54:12.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:54:12.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -107,23 +85,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:56:18.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836326, "nlink": 1, + "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -136,8 +103,6 @@ "size": 100, "mtime": "2017-04-10T16:56:18.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:56:18.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -152,17 +117,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -174,9 +135,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -191,17 +149,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -213,9 +167,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -230,17 +181,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -252,9 +199,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -269,17 +213,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -291,9 +231,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -308,17 +245,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -330,9 +263,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -347,17 +277,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -369,9 +295,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -386,17 +309,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -408,9 +327,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -425,17 +341,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -447,9 +359,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -464,17 +373,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -486,9 +391,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -503,17 +405,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -525,9 +423,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -542,17 +437,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -564,9 +455,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -581,17 +469,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -603,9 +487,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -620,17 +501,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -642,9 +519,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -659,17 +533,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -681,9 +551,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -698,17 +565,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -720,9 +583,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -737,17 +597,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -759,9 +615,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -776,17 +629,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -798,9 +647,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -815,17 +661,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -837,9 +679,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -854,17 +693,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -876,9 +711,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -893,17 +725,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -915,9 +743,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -932,17 +757,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -954,9 +775,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -971,17 +789,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -993,9 +807,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1010,17 +821,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -1032,9 +839,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1049,17 +853,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -1071,9 +871,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:58:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1088,17 +885,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1110,9 +903,6 @@ "gname": "staff", "size": 6, "mtime": "2017-04-10T16:56:46.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1127,17 +917,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1149,9 +935,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1166,9 +949,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1181,23 +962,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:52:20.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836253, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1210,8 +980,6 @@ "size": 100, "mtime": "2017-04-10T16:52:20.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:52:20.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1226,9 +994,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1241,23 +1007,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:52:20.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836254, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1270,8 +1025,6 @@ "size": 100, "mtime": "2017-04-10T16:52:20.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:52:20.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1286,9 +1039,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1301,23 +1052,12 @@ { "extended": { "atime": "2017-04-10T17:07:25.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1330,8 +1070,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:07:25.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1346,9 +1084,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-paths--filter.json b/test/fixtures/parse/long-paths--filter.json index 8dfe9de3..53e376da 100644 --- a/test/fixtures/parse/long-paths--filter.json +++ b/test/fixtures/parse/long-paths--filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:53:02.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -47,23 +40,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:54:12.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836297, "nlink": 1, + "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -76,8 +58,6 @@ "size": 100, "mtime": "2017-04-10T16:54:12.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:54:12.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -107,23 +85,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:56:18.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836326, "nlink": 1, + "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -136,8 +103,6 @@ "size": 100, "mtime": "2017-04-10T16:56:18.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:56:18.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -152,17 +117,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -174,9 +135,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -191,17 +149,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -213,9 +167,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -230,17 +181,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -252,9 +199,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -269,17 +213,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -291,9 +231,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -308,17 +245,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -330,9 +263,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -347,17 +277,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -369,9 +295,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -386,17 +309,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -408,9 +327,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -425,17 +341,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -447,9 +359,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -464,17 +373,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -486,9 +391,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -503,17 +405,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -525,9 +423,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -542,17 +437,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -564,9 +455,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -581,17 +469,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -603,9 +487,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -620,17 +501,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -642,9 +519,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -659,17 +533,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -681,9 +551,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -698,17 +565,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -720,9 +583,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -737,17 +597,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -759,9 +615,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -776,17 +629,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -798,9 +647,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -815,17 +661,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -837,9 +679,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -854,17 +693,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -876,9 +711,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -893,17 +725,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -915,9 +743,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -932,17 +757,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -954,9 +775,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -971,17 +789,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -993,9 +807,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1010,17 +821,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -1032,9 +839,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1049,17 +853,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -1071,9 +871,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:58:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1088,17 +885,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1110,9 +903,6 @@ "gname": "staff", "size": 6, "mtime": "2017-04-10T16:56:46.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1127,17 +917,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1149,9 +935,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1166,9 +949,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1181,23 +962,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:52:20.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836253, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1210,8 +980,6 @@ "size": 100, "mtime": "2017-04-10T16:52:20.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:52:20.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1226,9 +994,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1241,23 +1007,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:52:20.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836254, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1270,8 +1025,6 @@ "size": 100, "mtime": "2017-04-10T16:52:20.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:52:20.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1286,9 +1039,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1301,23 +1052,12 @@ { "extended": { "atime": "2017-04-10T17:07:25.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1330,8 +1070,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:07:25.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1346,9 +1084,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-paths--meta-250-filter-strict.json b/test/fixtures/parse/long-paths--meta-250-filter-strict.json index 2a2e4960..0ceedf38 100644 --- a/test/fixtures/parse/long-paths--meta-250-filter-strict.json +++ b/test/fixtures/parse/long-paths--meta-250-filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:53:02.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -47,23 +40,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:54:12.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836297, "nlink": 1, + "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -76,8 +58,6 @@ "size": 100, "mtime": "2017-04-10T16:54:12.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:54:12.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,17 +72,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -114,9 +90,6 @@ "gname": "staff", "size": 283, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -131,17 +104,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -153,9 +122,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -170,17 +136,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -192,9 +154,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -209,17 +168,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -231,9 +186,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -248,17 +200,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -270,9 +218,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -287,17 +232,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -309,9 +250,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -326,17 +264,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -348,9 +282,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -365,17 +296,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -387,9 +314,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -404,17 +328,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -426,9 +346,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -443,17 +360,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -465,9 +378,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -482,17 +392,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -504,9 +410,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -521,17 +424,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -543,9 +442,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -560,17 +456,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -582,9 +474,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -599,17 +488,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -621,9 +506,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -638,17 +520,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -660,9 +538,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -677,17 +552,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -699,9 +570,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -716,17 +584,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -738,9 +602,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -755,17 +616,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -777,9 +634,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -794,17 +648,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -816,9 +666,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -833,17 +680,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -855,9 +698,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -872,17 +712,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -894,9 +730,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -911,17 +744,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -933,9 +762,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -950,17 +776,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -972,9 +794,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -989,17 +808,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -1011,9 +826,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1028,17 +840,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -1050,9 +858,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1067,17 +872,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -1089,9 +890,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:58:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1106,17 +904,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1128,9 +922,6 @@ "gname": "staff", "size": 6, "mtime": "2017-04-10T16:56:46.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1145,17 +936,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1167,9 +954,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1184,17 +968,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -1206,9 +986,6 @@ "gname": "staff", "size": 289, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1223,17 +1000,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1245,9 +1018,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1262,17 +1032,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -1284,9 +1050,6 @@ "gname": "staff", "size": 339, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1301,17 +1064,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1323,9 +1082,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1340,9 +1096,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1355,23 +1109,12 @@ { "extended": { "atime": "2017-04-10T17:07:25.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1384,8 +1127,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:07:25.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1400,9 +1141,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-paths--meta-250-filter.json b/test/fixtures/parse/long-paths--meta-250-filter.json index 2a2e4960..0ceedf38 100644 --- a/test/fixtures/parse/long-paths--meta-250-filter.json +++ b/test/fixtures/parse/long-paths--meta-250-filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:53:02.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -47,23 +40,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:54:12.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836297, "nlink": 1, + "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -76,8 +58,6 @@ "size": 100, "mtime": "2017-04-10T16:54:12.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:54:12.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,17 +72,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -114,9 +90,6 @@ "gname": "staff", "size": 283, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -131,17 +104,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -153,9 +122,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -170,17 +136,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -192,9 +154,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -209,17 +168,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -231,9 +186,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -248,17 +200,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -270,9 +218,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -287,17 +232,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -309,9 +250,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -326,17 +264,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -348,9 +282,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -365,17 +296,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -387,9 +314,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -404,17 +328,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -426,9 +346,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -443,17 +360,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -465,9 +378,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -482,17 +392,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -504,9 +410,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -521,17 +424,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -543,9 +442,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -560,17 +456,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -582,9 +474,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -599,17 +488,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -621,9 +506,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -638,17 +520,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -660,9 +538,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -677,17 +552,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -699,9 +570,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -716,17 +584,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -738,9 +602,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -755,17 +616,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -777,9 +634,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -794,17 +648,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -816,9 +666,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -833,17 +680,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -855,9 +698,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -872,17 +712,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -894,9 +730,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -911,17 +744,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -933,9 +762,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -950,17 +776,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -972,9 +794,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -989,17 +808,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -1011,9 +826,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1028,17 +840,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -1050,9 +858,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1067,17 +872,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -1089,9 +890,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:58:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1106,17 +904,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1128,9 +922,6 @@ "gname": "staff", "size": 6, "mtime": "2017-04-10T16:56:46.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1145,17 +936,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1167,9 +954,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1184,17 +968,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -1206,9 +986,6 @@ "gname": "staff", "size": 289, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1223,17 +1000,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1245,9 +1018,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1262,17 +1032,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -1284,9 +1050,6 @@ "gname": "staff", "size": 339, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1301,17 +1064,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1323,9 +1082,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1340,9 +1096,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1355,23 +1109,12 @@ { "extended": { "atime": "2017-04-10T17:07:25.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -1384,8 +1127,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:07:25.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1400,9 +1141,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-paths--meta-250-strict.json b/test/fixtures/parse/long-paths--meta-250-strict.json index 532f2365..7fdf8ac4 100644 --- a/test/fixtures/parse/long-paths--meta-250-strict.json +++ b/test/fixtures/parse/long-paths--meta-250-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:53:02.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -47,23 +40,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:54:12.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836297, "nlink": 1, + "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -76,8 +58,6 @@ "size": 100, "mtime": "2017-04-10T16:54:12.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:54:12.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,17 +72,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -114,9 +90,6 @@ "gname": "staff", "size": 283, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -131,17 +104,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -153,9 +122,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -170,17 +136,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -192,9 +154,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -209,17 +168,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -231,9 +186,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -248,17 +200,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -270,9 +218,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -287,17 +232,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -309,9 +250,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -326,17 +264,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -348,9 +282,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -365,17 +296,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -387,9 +314,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -404,17 +328,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -426,9 +346,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -443,17 +360,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -465,9 +378,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -482,17 +392,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -504,9 +410,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -521,17 +424,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -543,9 +442,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -560,17 +456,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -582,9 +474,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -599,17 +488,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -621,9 +506,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -638,17 +520,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -660,9 +538,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -677,17 +552,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -699,9 +570,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -716,17 +584,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -738,9 +602,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -755,17 +616,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -777,9 +634,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -794,17 +648,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -816,9 +666,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -833,17 +680,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -855,9 +698,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -872,17 +712,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -894,9 +730,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -911,17 +744,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -933,9 +762,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -950,17 +776,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -972,9 +794,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -989,17 +808,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -1011,9 +826,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1028,17 +840,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -1050,9 +858,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1067,17 +872,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -1089,9 +890,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:58:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1106,17 +904,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1128,9 +922,6 @@ "gname": "staff", "size": 6, "mtime": "2017-04-10T16:56:46.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1145,17 +936,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1167,9 +954,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1184,17 +968,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -1206,9 +986,6 @@ "gname": "staff", "size": 289, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1223,17 +1000,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1245,9 +1018,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1262,17 +1032,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -1284,9 +1050,6 @@ "gname": "staff", "size": 339, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1301,17 +1064,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1323,9 +1082,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1340,9 +1096,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1355,23 +1109,12 @@ { "extended": { "atime": "2017-04-10T17:07:25.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1384,8 +1127,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:07:25.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1400,9 +1141,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-paths--meta-250.json b/test/fixtures/parse/long-paths--meta-250.json index 532f2365..7fdf8ac4 100644 --- a/test/fixtures/parse/long-paths--meta-250.json +++ b/test/fixtures/parse/long-paths--meta-250.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:53:02.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -47,23 +40,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:54:12.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836297, "nlink": 1, + "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -76,8 +58,6 @@ "size": 100, "mtime": "2017-04-10T16:54:12.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:54:12.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,17 +72,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -114,9 +90,6 @@ "gname": "staff", "size": 283, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -131,17 +104,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -153,9 +122,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -170,17 +136,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -192,9 +154,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -209,17 +168,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -231,9 +186,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -248,17 +200,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -270,9 +218,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -287,17 +232,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -309,9 +250,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -326,17 +264,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -348,9 +282,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -365,17 +296,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -387,9 +314,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -404,17 +328,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -426,9 +346,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -443,17 +360,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -465,9 +378,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -482,17 +392,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -504,9 +410,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -521,17 +424,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -543,9 +442,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -560,17 +456,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -582,9 +474,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -599,17 +488,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -621,9 +506,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -638,17 +520,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -660,9 +538,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -677,17 +552,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -699,9 +570,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -716,17 +584,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -738,9 +602,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -755,17 +616,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -777,9 +634,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -794,17 +648,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -816,9 +666,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -833,17 +680,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -855,9 +698,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -872,17 +712,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -894,9 +730,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -911,17 +744,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -933,9 +762,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -950,17 +776,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -972,9 +794,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -989,17 +808,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -1011,9 +826,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1028,17 +840,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -1050,9 +858,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1067,17 +872,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -1089,9 +890,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:58:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1106,17 +904,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1128,9 +922,6 @@ "gname": "staff", "size": 6, "mtime": "2017-04-10T16:56:46.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1145,17 +936,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1167,9 +954,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1184,17 +968,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -1206,9 +986,6 @@ "gname": "staff", "size": 289, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1223,17 +1000,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1245,9 +1018,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1262,17 +1032,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -1284,9 +1050,6 @@ "gname": "staff", "size": 339, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1301,17 +1064,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1323,9 +1082,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1340,9 +1096,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1355,23 +1109,12 @@ { "extended": { "atime": "2017-04-10T17:07:25.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1384,8 +1127,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:07:25.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1400,9 +1141,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-paths--strict.json b/test/fixtures/parse/long-paths--strict.json index 835fd96c..fb49f544 100644 --- a/test/fixtures/parse/long-paths--strict.json +++ b/test/fixtures/parse/long-paths--strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:53:02.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -47,23 +40,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:54:12.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836297, "nlink": 1, + "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -76,8 +58,6 @@ "size": 100, "mtime": "2017-04-10T16:54:12.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:54:12.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -107,23 +85,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:56:18.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836326, "nlink": 1, + "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -136,8 +103,6 @@ "size": 100, "mtime": "2017-04-10T16:56:18.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:56:18.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -152,17 +117,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -174,9 +135,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -191,17 +149,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -213,9 +167,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -230,17 +181,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -252,9 +199,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -269,17 +213,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -291,9 +231,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -308,17 +245,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -330,9 +263,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -347,17 +277,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -369,9 +295,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -386,17 +309,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -408,9 +327,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -425,17 +341,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -447,9 +359,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -464,17 +373,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -486,9 +391,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -503,17 +405,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -525,9 +423,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -542,17 +437,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -564,9 +455,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -581,17 +469,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -603,9 +487,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -620,17 +501,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -642,9 +519,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -659,17 +533,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -681,9 +551,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -698,17 +565,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -720,9 +583,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -737,17 +597,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -759,9 +615,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -776,17 +629,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -798,9 +647,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -815,17 +661,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -837,9 +679,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -854,17 +693,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -876,9 +711,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -893,17 +725,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -915,9 +743,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -932,17 +757,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -954,9 +775,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -971,17 +789,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -993,9 +807,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1010,17 +821,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -1032,9 +839,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1049,17 +853,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -1071,9 +871,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:58:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1088,17 +885,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1110,9 +903,6 @@ "gname": "staff", "size": 6, "mtime": "2017-04-10T16:56:46.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1127,17 +917,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1149,9 +935,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1166,9 +949,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1181,23 +962,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:52:20.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836253, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1210,8 +980,6 @@ "size": 100, "mtime": "2017-04-10T16:52:20.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:52:20.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1226,9 +994,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1241,23 +1007,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:52:20.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836254, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1270,8 +1025,6 @@ "size": 100, "mtime": "2017-04-10T16:52:20.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:52:20.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1286,9 +1039,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1301,23 +1052,12 @@ { "extended": { "atime": "2017-04-10T17:07:25.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1330,8 +1070,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:07:25.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1346,9 +1084,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-paths.json b/test/fixtures/parse/long-paths.json index 835fd96c..fb49f544 100644 --- a/test/fixtures/parse/long-paths.json +++ b/test/fixtures/parse/long-paths.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -15,9 +13,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:53:02.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,9 +27,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -47,23 +40,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:54:12.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836297, "nlink": 1, + "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -76,8 +58,6 @@ "size": 100, "mtime": "2017-04-10T16:54:12.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:54:12.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -92,9 +72,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -107,23 +85,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:56:18.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836326, "nlink": 1, + "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -136,8 +103,6 @@ "size": 100, "mtime": "2017-04-10T16:56:18.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:56:18.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -152,17 +117,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -174,9 +135,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -191,17 +149,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -213,9 +167,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -230,17 +181,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -252,9 +199,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -269,17 +213,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -291,9 +231,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -308,17 +245,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -330,9 +263,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -347,17 +277,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -369,9 +295,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -386,17 +309,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -408,9 +327,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -425,17 +341,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -447,9 +359,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -464,17 +373,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -486,9 +391,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -503,17 +405,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -525,9 +423,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -542,17 +437,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -564,9 +455,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -581,17 +469,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -603,9 +487,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -620,17 +501,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -642,9 +519,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -659,17 +533,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -681,9 +551,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -698,17 +565,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -720,9 +583,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -737,17 +597,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -759,9 +615,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -776,17 +629,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -798,9 +647,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -815,17 +661,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -837,9 +679,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -854,17 +693,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -876,9 +711,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -893,17 +725,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -915,9 +743,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -932,17 +757,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -954,9 +775,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -971,17 +789,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -993,9 +807,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1010,17 +821,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -1032,9 +839,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1049,17 +853,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -1071,9 +871,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T16:58:47.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1088,17 +885,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1110,9 +903,6 @@ "gname": "staff", "size": 6, "mtime": "2017-04-10T16:56:46.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1127,17 +917,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1149,9 +935,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:52:20.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1166,9 +949,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1181,23 +962,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:52:20.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836253, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1210,8 +980,6 @@ "size": 100, "mtime": "2017-04-10T16:52:20.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:52:20.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1226,9 +994,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1241,23 +1007,12 @@ { "extended": { "atime": "2017-04-10T17:01:57.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:52:20.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836254, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1270,8 +1025,6 @@ "size": 100, "mtime": "2017-04-10T16:52:20.000Z", "atime": "2017-04-10T17:01:57.000Z", - "ctime": "2017-04-10T16:52:20.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1286,9 +1039,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -1301,23 +1052,12 @@ { "extended": { "atime": "2017-04-10T17:07:25.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -1330,8 +1070,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:07:25.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -1346,9 +1084,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-pax--filter-strict.json b/test/fixtures/parse/long-pax--filter-strict.json index 7e9df8bb..57f80513 100644 --- a/test/fixtures/parse/long-pax--filter-strict.json +++ b/test/fixtures/parse/long-pax--filter-strict.json @@ -7,24 +7,16 @@ "ignoredEntry", { "extended": { - "atime": null, - "charset": null, + "mtime": "2017-04-10T16:54:12.000Z", "comment": "all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy", - "ctime": null, "gid": 20, + "uid": 501, "gname": "staff", - "linkpath": null, - "mtime": "2017-04-10T16:54:12.000Z", + "uname": "isaacs", "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "size": 100, - "uid": 501, - "uname": "isaacs", - "dev": null, - "ino": null, - "nlink": null, "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -36,9 +28,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +42,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-pax--filter.json b/test/fixtures/parse/long-pax--filter.json index 7e9df8bb..57f80513 100644 --- a/test/fixtures/parse/long-pax--filter.json +++ b/test/fixtures/parse/long-pax--filter.json @@ -7,24 +7,16 @@ "ignoredEntry", { "extended": { - "atime": null, - "charset": null, + "mtime": "2017-04-10T16:54:12.000Z", "comment": "all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy", - "ctime": null, "gid": 20, + "uid": 501, "gname": "staff", - "linkpath": null, - "mtime": "2017-04-10T16:54:12.000Z", + "uname": "isaacs", "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "size": 100, - "uid": 501, - "uname": "isaacs", - "dev": null, - "ino": null, - "nlink": null, "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -36,9 +28,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +42,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-pax--meta-250-filter-strict.json b/test/fixtures/parse/long-pax--meta-250-filter-strict.json index 584863e0..4129b6fc 100644 --- a/test/fixtures/parse/long-pax--meta-250-filter-strict.json +++ b/test/fixtures/parse/long-pax--meta-250-filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1282, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -54,9 +45,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,9 +59,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-pax--meta-250-filter.json b/test/fixtures/parse/long-pax--meta-250-filter.json index 584863e0..4129b6fc 100644 --- a/test/fixtures/parse/long-pax--meta-250-filter.json +++ b/test/fixtures/parse/long-pax--meta-250-filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1282, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -54,9 +45,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,9 +59,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-pax--meta-250-strict.json b/test/fixtures/parse/long-pax--meta-250-strict.json index 5a19f0ec..f989196b 100644 --- a/test/fixtures/parse/long-pax--meta-250-strict.json +++ b/test/fixtures/parse/long-pax--meta-250-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1282, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -54,9 +45,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,9 +59,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-pax--meta-250.json b/test/fixtures/parse/long-pax--meta-250.json index 5a19f0ec..f989196b 100644 --- a/test/fixtures/parse/long-pax--meta-250.json +++ b/test/fixtures/parse/long-pax--meta-250.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "ExtendedHeader", "meta": true, "ignore": true, @@ -15,9 +13,6 @@ "gname": "staff", "size": 1282, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -32,17 +27,13 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], [ "entry", { - "extended": null, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -54,9 +45,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -71,9 +59,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-pax--strict.json b/test/fixtures/parse/long-pax--strict.json index c72def09..2385c664 100644 --- a/test/fixtures/parse/long-pax--strict.json +++ b/test/fixtures/parse/long-pax--strict.json @@ -7,24 +7,16 @@ "entry", { "extended": { - "atime": null, - "charset": null, + "mtime": "2017-04-10T16:54:12.000Z", "comment": "all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy", - "ctime": null, "gid": 20, + "uid": 501, "gname": "staff", - "linkpath": null, - "mtime": "2017-04-10T16:54:12.000Z", + "uname": "isaacs", "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "size": 100, - "uid": 501, - "uname": "isaacs", - "dev": null, - "ino": null, - "nlink": null, "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -36,9 +28,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +42,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/long-pax.json b/test/fixtures/parse/long-pax.json index c72def09..2385c664 100644 --- a/test/fixtures/parse/long-pax.json +++ b/test/fixtures/parse/long-pax.json @@ -7,24 +7,16 @@ "entry", { "extended": { - "atime": null, - "charset": null, + "mtime": "2017-04-10T16:54:12.000Z", "comment": "all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy all work and no play makes johnny a tar boy", - "ctime": null, "gid": 20, + "uid": 501, "gname": "staff", - "linkpath": null, - "mtime": "2017-04-10T16:54:12.000Z", + "uname": "isaacs", "path": "120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "size": 100, - "uid": 501, - "uname": "isaacs", - "dev": null, - "ino": null, - "nlink": null, "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -36,9 +28,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:54:12.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +42,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/next-file-has-long--filter-strict.json b/test/fixtures/parse/next-file-has-long--filter-strict.json index a010d9e3..efe114cd 100644 --- a/test/fixtures/parse/next-file-has-long--filter-strict.json +++ b/test/fixtures/parse/next-file-has-long--filter-strict.json @@ -9,7 +9,6 @@ "extended": { "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -21,9 +20,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -38,9 +34,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -54,7 +48,6 @@ "extended": { "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -66,8 +59,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T23:22:33.000Z", - "atime": null, - "ctime": null, "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "header": { "cksumValid": true, @@ -83,9 +74,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/next-file-has-long--filter.json b/test/fixtures/parse/next-file-has-long--filter.json index a010d9e3..efe114cd 100644 --- a/test/fixtures/parse/next-file-has-long--filter.json +++ b/test/fixtures/parse/next-file-has-long--filter.json @@ -9,7 +9,6 @@ "extended": { "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -21,9 +20,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -38,9 +34,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -54,7 +48,6 @@ "extended": { "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -66,8 +59,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T23:22:33.000Z", - "atime": null, - "ctime": null, "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "header": { "cksumValid": true, @@ -83,9 +74,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/next-file-has-long--meta-250-filter-strict.json b/test/fixtures/parse/next-file-has-long--meta-250-filter-strict.json index a010d9e3..efe114cd 100644 --- a/test/fixtures/parse/next-file-has-long--meta-250-filter-strict.json +++ b/test/fixtures/parse/next-file-has-long--meta-250-filter-strict.json @@ -9,7 +9,6 @@ "extended": { "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -21,9 +20,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -38,9 +34,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -54,7 +48,6 @@ "extended": { "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -66,8 +59,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T23:22:33.000Z", - "atime": null, - "ctime": null, "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "header": { "cksumValid": true, @@ -83,9 +74,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/next-file-has-long--meta-250-filter.json b/test/fixtures/parse/next-file-has-long--meta-250-filter.json index a010d9e3..efe114cd 100644 --- a/test/fixtures/parse/next-file-has-long--meta-250-filter.json +++ b/test/fixtures/parse/next-file-has-long--meta-250-filter.json @@ -9,7 +9,6 @@ "extended": { "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -21,9 +20,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -38,9 +34,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -54,7 +48,6 @@ "extended": { "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": true, @@ -66,8 +59,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T23:22:33.000Z", - "atime": null, - "ctime": null, "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "header": { "cksumValid": true, @@ -83,9 +74,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/next-file-has-long--meta-250-strict.json b/test/fixtures/parse/next-file-has-long--meta-250-strict.json index 9d6eef02..852c825b 100644 --- a/test/fixtures/parse/next-file-has-long--meta-250-strict.json +++ b/test/fixtures/parse/next-file-has-long--meta-250-strict.json @@ -9,7 +9,6 @@ "extended": { "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -21,9 +20,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -38,9 +34,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -54,7 +48,6 @@ "extended": { "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -66,8 +59,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T23:22:33.000Z", - "atime": null, - "ctime": null, "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "header": { "cksumValid": true, @@ -83,9 +74,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/next-file-has-long--meta-250.json b/test/fixtures/parse/next-file-has-long--meta-250.json index 9d6eef02..852c825b 100644 --- a/test/fixtures/parse/next-file-has-long--meta-250.json +++ b/test/fixtures/parse/next-file-has-long--meta-250.json @@ -9,7 +9,6 @@ "extended": { "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -21,9 +20,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -38,9 +34,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -54,7 +48,6 @@ "extended": { "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -66,8 +59,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T23:22:33.000Z", - "atime": null, - "ctime": null, "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "header": { "cksumValid": true, @@ -83,9 +74,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/next-file-has-long--strict.json b/test/fixtures/parse/next-file-has-long--strict.json index 9d6eef02..852c825b 100644 --- a/test/fixtures/parse/next-file-has-long--strict.json +++ b/test/fixtures/parse/next-file-has-long--strict.json @@ -9,7 +9,6 @@ "extended": { "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -21,9 +20,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -38,9 +34,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -54,7 +48,6 @@ "extended": { "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -66,8 +59,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T23:22:33.000Z", - "atime": null, - "ctime": null, "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "header": { "cksumValid": true, @@ -83,9 +74,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/next-file-has-long.json b/test/fixtures/parse/next-file-has-long.json index 9d6eef02..852c825b 100644 --- a/test/fixtures/parse/next-file-has-long.json +++ b/test/fixtures/parse/next-file-has-long.json @@ -9,7 +9,6 @@ "extended": { "path": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -21,9 +20,6 @@ "gname": "staff", "size": 100, "mtime": "2017-04-10T16:56:18.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -38,9 +34,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -54,7 +48,6 @@ "extended": { "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" }, - "globalExtended": null, "type": "SymbolicLink", "meta": false, "ignore": false, @@ -66,8 +59,6 @@ "gname": "staff", "size": 0, "mtime": "2017-04-10T23:22:33.000Z", - "atime": null, - "ctime": null, "linkpath": "170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "header": { "cksumValid": true, @@ -83,9 +74,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/null-byte--filter-strict.json b/test/fixtures/parse/null-byte--filter-strict.json index 3c27f2bb..e96a4f8a 100644 --- a/test/fixtures/parse/null-byte--filter-strict.json +++ b/test/fixtures/parse/null-byte--filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -11,13 +9,8 @@ "mode": 509, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 0, "mtime": "2017-07-31T22:21:58.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2017-07-31T22:21:58.000Z", "cksum": 11228, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "this_is_a_really_long_directory_name_with_a_lot_of_characters/this_is_a_really_long_tgz_file_with_a_lot_of_characters.tgz" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -56,13 +44,8 @@ "mode": 436, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 200, "mtime": "2017-07-31T22:21:53.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2017-07-31T22:21:53.000Z", "cksum": 15210, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/null-byte--filter.json b/test/fixtures/parse/null-byte--filter.json index 3c27f2bb..e96a4f8a 100644 --- a/test/fixtures/parse/null-byte--filter.json +++ b/test/fixtures/parse/null-byte--filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -11,13 +9,8 @@ "mode": 509, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 0, "mtime": "2017-07-31T22:21:58.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2017-07-31T22:21:58.000Z", "cksum": 11228, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "this_is_a_really_long_directory_name_with_a_lot_of_characters/this_is_a_really_long_tgz_file_with_a_lot_of_characters.tgz" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -56,13 +44,8 @@ "mode": 436, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 200, "mtime": "2017-07-31T22:21:53.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2017-07-31T22:21:53.000Z", "cksum": 15210, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/null-byte--meta-250-filter-strict.json b/test/fixtures/parse/null-byte--meta-250-filter-strict.json index 3c27f2bb..e96a4f8a 100644 --- a/test/fixtures/parse/null-byte--meta-250-filter-strict.json +++ b/test/fixtures/parse/null-byte--meta-250-filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -11,13 +9,8 @@ "mode": 509, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 0, "mtime": "2017-07-31T22:21:58.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2017-07-31T22:21:58.000Z", "cksum": 11228, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "this_is_a_really_long_directory_name_with_a_lot_of_characters/this_is_a_really_long_tgz_file_with_a_lot_of_characters.tgz" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -56,13 +44,8 @@ "mode": 436, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 200, "mtime": "2017-07-31T22:21:53.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2017-07-31T22:21:53.000Z", "cksum": 15210, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/null-byte--meta-250-filter.json b/test/fixtures/parse/null-byte--meta-250-filter.json index 3c27f2bb..e96a4f8a 100644 --- a/test/fixtures/parse/null-byte--meta-250-filter.json +++ b/test/fixtures/parse/null-byte--meta-250-filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -11,13 +9,8 @@ "mode": 509, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 0, "mtime": "2017-07-31T22:21:58.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2017-07-31T22:21:58.000Z", "cksum": 11228, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "this_is_a_really_long_directory_name_with_a_lot_of_characters/this_is_a_really_long_tgz_file_with_a_lot_of_characters.tgz" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -56,13 +44,8 @@ "mode": 436, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 200, "mtime": "2017-07-31T22:21:53.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2017-07-31T22:21:53.000Z", "cksum": 15210, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/null-byte--meta-250-strict.json b/test/fixtures/parse/null-byte--meta-250-strict.json index a9bad194..bb1f092c 100644 --- a/test/fixtures/parse/null-byte--meta-250-strict.json +++ b/test/fixtures/parse/null-byte--meta-250-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -11,13 +9,8 @@ "mode": 509, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 0, "mtime": "2017-07-31T22:21:58.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2017-07-31T22:21:58.000Z", "cksum": 11228, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "this_is_a_really_long_directory_name_with_a_lot_of_characters/this_is_a_really_long_tgz_file_with_a_lot_of_characters.tgz" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -56,13 +44,8 @@ "mode": 436, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 200, "mtime": "2017-07-31T22:21:53.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2017-07-31T22:21:53.000Z", "cksum": 15210, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/null-byte--meta-250.json b/test/fixtures/parse/null-byte--meta-250.json index a9bad194..bb1f092c 100644 --- a/test/fixtures/parse/null-byte--meta-250.json +++ b/test/fixtures/parse/null-byte--meta-250.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -11,13 +9,8 @@ "mode": 509, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 0, "mtime": "2017-07-31T22:21:58.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2017-07-31T22:21:58.000Z", "cksum": 11228, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "this_is_a_really_long_directory_name_with_a_lot_of_characters/this_is_a_really_long_tgz_file_with_a_lot_of_characters.tgz" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -56,13 +44,8 @@ "mode": 436, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 200, "mtime": "2017-07-31T22:21:53.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2017-07-31T22:21:53.000Z", "cksum": 15210, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/null-byte--strict.json b/test/fixtures/parse/null-byte--strict.json index a9bad194..bb1f092c 100644 --- a/test/fixtures/parse/null-byte--strict.json +++ b/test/fixtures/parse/null-byte--strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -11,13 +9,8 @@ "mode": 509, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 0, "mtime": "2017-07-31T22:21:58.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2017-07-31T22:21:58.000Z", "cksum": 11228, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "this_is_a_really_long_directory_name_with_a_lot_of_characters/this_is_a_really_long_tgz_file_with_a_lot_of_characters.tgz" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -56,13 +44,8 @@ "mode": 436, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 200, "mtime": "2017-07-31T22:21:53.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2017-07-31T22:21:53.000Z", "cksum": 15210, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/null-byte.json b/test/fixtures/parse/null-byte.json index a9bad194..bb1f092c 100644 --- a/test/fixtures/parse/null-byte.json +++ b/test/fixtures/parse/null-byte.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -11,13 +9,8 @@ "mode": 509, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 0, "mtime": "2017-07-31T22:21:58.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2017-07-31T22:21:58.000Z", "cksum": 11228, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "this_is_a_really_long_directory_name_with_a_lot_of_characters/this_is_a_really_long_tgz_file_with_a_lot_of_characters.tgz" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -56,13 +44,8 @@ "mode": 436, "uid": 1000, "gid": 1000, - "uname": null, - "gname": null, "size": 200, "mtime": "2017-07-31T22:21:53.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2017-07-31T22:21:53.000Z", "cksum": 15210, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/trailing-slash-corner-case--filter-strict.json b/test/fixtures/parse/trailing-slash-corner-case--filter-strict.json index 3739da97..151be717 100644 --- a/test/fixtures/parse/trailing-slash-corner-case--filter-strict.json +++ b/test/fixtures/parse/trailing-slash-corner-case--filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -11,13 +9,8 @@ "mode": 493, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 0, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13612, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/a-truly-unlucky-file-beyond-130-byte-path-length.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -56,13 +44,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13611, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -93,7 +72,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/some-unlucky-file.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -101,13 +79,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-18T23:49:44.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -119,12 +92,8 @@ "mtime": "2018-06-18T23:49:44.000Z", "cksum": 13602, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/trailing-slash-corner-case--filter.json b/test/fixtures/parse/trailing-slash-corner-case--filter.json index 3739da97..151be717 100644 --- a/test/fixtures/parse/trailing-slash-corner-case--filter.json +++ b/test/fixtures/parse/trailing-slash-corner-case--filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -11,13 +9,8 @@ "mode": 493, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 0, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13612, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/a-truly-unlucky-file-beyond-130-byte-path-length.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -56,13 +44,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13611, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -93,7 +72,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/some-unlucky-file.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -101,13 +79,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-18T23:49:44.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -119,12 +92,8 @@ "mtime": "2018-06-18T23:49:44.000Z", "cksum": 13602, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/trailing-slash-corner-case--meta-250-filter-strict.json b/test/fixtures/parse/trailing-slash-corner-case--meta-250-filter-strict.json index 3739da97..151be717 100644 --- a/test/fixtures/parse/trailing-slash-corner-case--meta-250-filter-strict.json +++ b/test/fixtures/parse/trailing-slash-corner-case--meta-250-filter-strict.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -11,13 +9,8 @@ "mode": 493, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 0, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13612, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/a-truly-unlucky-file-beyond-130-byte-path-length.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -56,13 +44,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13611, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -93,7 +72,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/some-unlucky-file.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -101,13 +79,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-18T23:49:44.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -119,12 +92,8 @@ "mtime": "2018-06-18T23:49:44.000Z", "cksum": 13602, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/trailing-slash-corner-case--meta-250-filter.json b/test/fixtures/parse/trailing-slash-corner-case--meta-250-filter.json index 3739da97..151be717 100644 --- a/test/fixtures/parse/trailing-slash-corner-case--meta-250-filter.json +++ b/test/fixtures/parse/trailing-slash-corner-case--meta-250-filter.json @@ -2,8 +2,6 @@ [ "ignoredEntry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": true, @@ -11,13 +9,8 @@ "mode": 493, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 0, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13612, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/a-truly-unlucky-file-beyond-130-byte-path-length.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -56,13 +44,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13611, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -93,7 +72,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/some-unlucky-file.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -101,13 +79,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-18T23:49:44.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -119,12 +92,8 @@ "mtime": "2018-06-18T23:49:44.000Z", "cksum": 13602, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/trailing-slash-corner-case--meta-250-strict.json b/test/fixtures/parse/trailing-slash-corner-case--meta-250-strict.json index 14200298..c5110f0c 100644 --- a/test/fixtures/parse/trailing-slash-corner-case--meta-250-strict.json +++ b/test/fixtures/parse/trailing-slash-corner-case--meta-250-strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -11,13 +9,8 @@ "mode": 493, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 0, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13612, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/a-truly-unlucky-file-beyond-130-byte-path-length.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -56,13 +44,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13611, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -93,7 +72,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/some-unlucky-file.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -101,13 +79,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-18T23:49:44.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -119,12 +92,8 @@ "mtime": "2018-06-18T23:49:44.000Z", "cksum": 13602, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/trailing-slash-corner-case--meta-250.json b/test/fixtures/parse/trailing-slash-corner-case--meta-250.json index 14200298..c5110f0c 100644 --- a/test/fixtures/parse/trailing-slash-corner-case--meta-250.json +++ b/test/fixtures/parse/trailing-slash-corner-case--meta-250.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -11,13 +9,8 @@ "mode": 493, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 0, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13612, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/a-truly-unlucky-file-beyond-130-byte-path-length.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -56,13 +44,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13611, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -93,7 +72,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/some-unlucky-file.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -101,13 +79,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-18T23:49:44.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -119,12 +92,8 @@ "mtime": "2018-06-18T23:49:44.000Z", "cksum": 13602, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/trailing-slash-corner-case--strict.json b/test/fixtures/parse/trailing-slash-corner-case--strict.json index 14200298..c5110f0c 100644 --- a/test/fixtures/parse/trailing-slash-corner-case--strict.json +++ b/test/fixtures/parse/trailing-slash-corner-case--strict.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -11,13 +9,8 @@ "mode": 493, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 0, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13612, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/a-truly-unlucky-file-beyond-130-byte-path-length.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -56,13 +44,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13611, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -93,7 +72,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/some-unlucky-file.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -101,13 +79,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-18T23:49:44.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -119,12 +92,8 @@ "mtime": "2018-06-18T23:49:44.000Z", "cksum": 13602, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/trailing-slash-corner-case.json b/test/fixtures/parse/trailing-slash-corner-case.json index 14200298..c5110f0c 100644 --- a/test/fixtures/parse/trailing-slash-corner-case.json +++ b/test/fixtures/parse/trailing-slash-corner-case.json @@ -2,8 +2,6 @@ [ "entry", { - "extended": null, - "globalExtended": null, "type": "Directory", "meta": false, "ignore": false, @@ -11,13 +9,8 @@ "mode": 493, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 0, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -29,12 +22,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13612, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -48,7 +37,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/a-truly-unlucky-file-beyond-130-byte-path-length.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -56,13 +44,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-19T00:03:11.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -74,12 +57,8 @@ "mtime": "2018-06-19T00:03:11.000Z", "cksum": 13611, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -93,7 +72,6 @@ "extended": { "path": "99-byte-dirname-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc/some-unlucky-file.txt" }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -101,13 +79,8 @@ "mode": 420, "uid": 501, "gid": 20, - "uname": null, - "gname": null, "size": 560, "mtime": "2018-06-18T23:49:44.000Z", - "atime": null, - "ctime": null, - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -119,12 +92,8 @@ "mtime": "2018-06-18T23:49:44.000Z", "cksum": 13602, "linkpath": "", - "uname": null, - "gname": null, "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/utf8--filter-strict.json b/test/fixtures/parse/utf8--filter-strict.json index b8c5bac5..7dc9969f 100644 --- a/test/fixtures/parse/utf8--filter-strict.json +++ b/test/fixtures/parse/utf8--filter-strict.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:51:42.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836217, "nlink": 1, + "path": "Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -37,8 +26,6 @@ "size": 2, "mtime": "2017-04-10T16:51:42.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:51:42.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +40,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -68,23 +53,12 @@ { "extended": { "atime": "2017-04-10T17:06:33.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -97,8 +71,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:06:33.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -113,9 +85,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -128,23 +98,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -157,8 +116,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -173,9 +130,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/utf8--filter.json b/test/fixtures/parse/utf8--filter.json index b8c5bac5..7dc9969f 100644 --- a/test/fixtures/parse/utf8--filter.json +++ b/test/fixtures/parse/utf8--filter.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:51:42.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836217, "nlink": 1, + "path": "Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -37,8 +26,6 @@ "size": 2, "mtime": "2017-04-10T16:51:42.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:51:42.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +40,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -68,23 +53,12 @@ { "extended": { "atime": "2017-04-10T17:06:33.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -97,8 +71,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:06:33.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -113,9 +85,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -128,23 +98,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -157,8 +116,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -173,9 +130,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/utf8--meta-250-filter-strict.json b/test/fixtures/parse/utf8--meta-250-filter-strict.json index b8c5bac5..7dc9969f 100644 --- a/test/fixtures/parse/utf8--meta-250-filter-strict.json +++ b/test/fixtures/parse/utf8--meta-250-filter-strict.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:51:42.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836217, "nlink": 1, + "path": "Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -37,8 +26,6 @@ "size": 2, "mtime": "2017-04-10T16:51:42.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:51:42.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +40,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -68,23 +53,12 @@ { "extended": { "atime": "2017-04-10T17:06:33.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -97,8 +71,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:06:33.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -113,9 +85,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -128,23 +98,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -157,8 +116,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -173,9 +130,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/utf8--meta-250-filter.json b/test/fixtures/parse/utf8--meta-250-filter.json index b8c5bac5..7dc9969f 100644 --- a/test/fixtures/parse/utf8--meta-250-filter.json +++ b/test/fixtures/parse/utf8--meta-250-filter.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:51:42.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836217, "nlink": 1, + "path": "Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -37,8 +26,6 @@ "size": 2, "mtime": "2017-04-10T16:51:42.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:51:42.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +40,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -68,23 +53,12 @@ { "extended": { "atime": "2017-04-10T17:06:33.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -97,8 +71,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:06:33.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -113,9 +85,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -128,23 +98,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": true, @@ -157,8 +116,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -173,9 +130,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/utf8--meta-250-strict.json b/test/fixtures/parse/utf8--meta-250-strict.json index 611f052a..4ee5a61a 100644 --- a/test/fixtures/parse/utf8--meta-250-strict.json +++ b/test/fixtures/parse/utf8--meta-250-strict.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:51:42.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836217, "nlink": 1, + "path": "Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -37,8 +26,6 @@ "size": 2, "mtime": "2017-04-10T16:51:42.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:51:42.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +40,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -68,23 +53,12 @@ { "extended": { "atime": "2017-04-10T17:06:33.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -97,8 +71,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:06:33.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -113,9 +85,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -128,23 +98,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -157,8 +116,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -173,9 +130,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/utf8--meta-250.json b/test/fixtures/parse/utf8--meta-250.json index 611f052a..4ee5a61a 100644 --- a/test/fixtures/parse/utf8--meta-250.json +++ b/test/fixtures/parse/utf8--meta-250.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:51:42.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836217, "nlink": 1, + "path": "Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -37,8 +26,6 @@ "size": 2, "mtime": "2017-04-10T16:51:42.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:51:42.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +40,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -68,23 +53,12 @@ { "extended": { "atime": "2017-04-10T17:06:33.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -97,8 +71,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:06:33.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -113,9 +85,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -128,23 +98,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -157,8 +116,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -173,9 +130,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/utf8--strict.json b/test/fixtures/parse/utf8--strict.json index 611f052a..4ee5a61a 100644 --- a/test/fixtures/parse/utf8--strict.json +++ b/test/fixtures/parse/utf8--strict.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:51:42.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836217, "nlink": 1, + "path": "Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -37,8 +26,6 @@ "size": 2, "mtime": "2017-04-10T16:51:42.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:51:42.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +40,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -68,23 +53,12 @@ { "extended": { "atime": "2017-04-10T17:06:33.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -97,8 +71,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:06:33.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -113,9 +85,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -128,23 +98,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -157,8 +116,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -173,9 +130,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/fixtures/parse/utf8.json b/test/fixtures/parse/utf8.json index 611f052a..4ee5a61a 100644 --- a/test/fixtures/parse/utf8.json +++ b/test/fixtures/parse/utf8.json @@ -8,23 +8,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:51:42.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836217, "nlink": 1, + "path": "Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -37,8 +26,6 @@ "size": 2, "mtime": "2017-04-10T16:51:42.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:51:42.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -53,9 +40,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -68,23 +53,12 @@ { "extended": { "atime": "2017-04-10T17:06:33.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T17:05:56.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "🌟.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836716, "nlink": 1, + "path": "🌟.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -97,8 +71,6 @@ "size": 106, "mtime": "2017-04-10T17:05:55.000Z", "atime": "2017-04-10T17:06:33.000Z", - "ctime": "2017-04-10T17:05:56.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -113,9 +85,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], @@ -128,23 +98,12 @@ { "extended": { "atime": "2017-04-10T17:02:38.000Z", - "charset": null, - "comment": null, - "ctime": "2017-04-10T16:58:47.000Z", - "gid": null, - "gname": null, - "linkpath": null, - "mtime": null, - "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", - "size": null, - "uid": null, - "uname": null, "dev": 16777220, "ino": 9836396, "nlink": 1, + "path": "long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt", "global": false }, - "globalExtended": null, "type": "File", "meta": false, "ignore": false, @@ -157,8 +116,6 @@ "size": 2, "mtime": "2017-04-10T16:58:47.000Z", "atime": "2017-04-10T17:02:38.000Z", - "ctime": "2017-04-10T16:58:47.000Z", - "linkpath": "", "header": { "cksumValid": true, "needPax": false, @@ -173,9 +130,7 @@ "uname": "isaacs", "gname": "staff", "devmaj": 0, - "devmin": 0, - "atime": null, - "ctime": null + "devmin": 0 } } ], diff --git a/test/get-write-flag.js b/test/get-write-flag.js index 81c2f547..63c4a2bf 100644 --- a/test/get-write-flag.js +++ b/test/get-write-flag.js @@ -1,67 +1,73 @@ -const t = require('tap') +import fs from 'fs' +import t from 'tap' +import { fileURLToPath } from 'url' +import { getWriteFlag } from '../dist/esm/get-write-flag.js' + +const __filename = fileURLToPath(import.meta.url) // run three scenarios // unix (no fmap) // win32 (without fmap support) // win32 (with fmap support) -const fs = require('fs') const hasFmap = !!fs.constants.UV_FS_O_FILEMAP -const platform = process.platform +const { platform } = process const UV_FS_O_FILEMAP = 0x20000000 switch (process.argv[2]) { case 'win32-fmap': { - if (!hasFmap) { - global.__FAKE_TESTING_FS__ = { - constants: { - ...fs.constants, - ...{ UV_FS_O_FILEMAP }, - }, - } - } const { O_CREAT, O_TRUNC, O_WRONLY } = fs.constants - if (platform !== 'win32') { - process.env.__FAKE_PLATFORM__ = 'win32' - } - const getFlag = require('../lib/get-write-flag.js') - t.equal(getFlag(1), UV_FS_O_FILEMAP | O_TRUNC | O_CREAT | O_WRONLY) - t.equal(getFlag(512 * 1024 + 1), 'w') + t.equal( + getWriteFlag(1), + UV_FS_O_FILEMAP | O_TRUNC | O_CREAT | O_WRONLY, + ) + t.equal(getWriteFlag(512 * 1024 + 1), 'w') break } case 'win32-nofmap': { - if (hasFmap) { - global.__FAKE_TESTING_FS__ = { - constants: { - ...fs.constants, - ...{ UV_FS_O_FILEMAP: 0 }, - }, - } - } - if (platform !== 'win32') { - process.env.__FAKE_PLATFORM__ = 'win32' - } - const getFlag = require('../lib/get-write-flag.js') - t.equal(getFlag(1), 'w') - t.equal(getFlag(512 * 1024 + 1), 'w') + t.equal(getWriteFlag(1), 'w') + t.equal(getWriteFlag(512 * 1024 + 1), 'w') break } case 'unix': { - if (platform === 'win32') { - process.env.__FAKE_PLATFORM__ = 'darwin' - } - const getFlag = require('../lib/get-write-flag.js') - t.equal(getFlag(1), 'w') - t.equal(getFlag(512 * 1024 + 1), 'w') + t.equal(getWriteFlag(1), 'w') + t.equal(getWriteFlag(512 * 1024 + 1), 'w') break } default: { const node = process.execPath - t.spawn(node, [__filename, 'win32-fmap']) - t.spawn(node, [__filename, 'win32-nofmap']) - t.spawn(node, [__filename, 'unix']) + t.spawn(node, [__filename, 'win32-fmap'], { + env: { + ...process.env, + ...(platform === 'win32' + ? {} + : { + __FAKE_FS_O_FILENAME__: String(UV_FS_O_FILEMAP), + __FAKE_PLATFORM__: 'win32', + }), + }, + }) + t.spawn(node, [__filename, 'win32-nofmap'], { + env: { + ...process.env, + ...(platform === 'win32' + ? {} + : { + __FAKE_FS_O_FILENAME__: '0', + __FAKE_PLATFORM__: 'win32', + }), + }, + }) + t.spawn(node, [__filename, 'unix'], { + env: { + ...process.env, + ...(platform === 'win32' + ? { __FAKE_PLATFORM__: 'linux' } + : {}), + }, + }) } } diff --git a/test/header.js b/test/header.js index 1a17eb83..8d3eb06e 100644 --- a/test/header.js +++ b/test/header.js @@ -1,32 +1,32 @@ -'use strict' -const t = require('tap') -const Header = require('../lib/header.js') +import t from 'tap' +import { Header } from '../dist/esm/header.js' t.test('ustar format', t => { const buf = Buffer.from( '666f6f2e74787400000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000030303037353520003035373736312000303030303234200037373737' + - '3737373737373700313236373735363735343000303133303531200030000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461720030306973616163730000000000000000000000000000000000' + - '0000000000000000007374616666000000000000000000000000000000000000' + - '0000000000000000003030303030302000303030303030200000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000', - 'hex') + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000030303037353520003035373736312000303030303234200037373737' + + '3737373737373700313236373735363735343000303133303531200030000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461720030306973616163730000000000000000000000000000000000' + + '0000000000000000007374616666000000000000000000000000000000000000' + + '0000000000000000003030303030302000303030303030200000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', + ) const h = new Header({ path: 'foo.txt', }) const slab = Buffer.alloc(1024) - h.set({ + Object.assign(h, { mode: 0o755, uid: 24561, gid: 20, @@ -38,9 +38,11 @@ t.test('ustar format', t => { }) h.encode(slab) - t.equal(slab.slice(0, 512).toString('hex'), buf.toString('hex')) - t.equal(slab.toString('hex'), buf.toString('hex') + - (new Array(1025).join('0'))) + t.equal(slab.subarray(0, 512).toString('hex'), buf.toString('hex')) + t.equal( + slab.toString('hex'), + buf.toString('hex') + new Array(1025).join('0'), + ) const h2 = new Header(buf) @@ -64,30 +66,31 @@ t.test('ustar format', t => { t.test('xstar format', t => { const buf = Buffer.from( '666f6f2e74787400000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000030303037353520003035373736312000303030303234200030303030' + - '3030303134342000313236373735363735343000303135313331200030000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461720030306973616163730000000000000000000000000000000000' + - '0000000000000000007374616666000000000000000000000000000000000000' + - '0000000000000000003030303030302000303030303030200000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000031323637' + - '3735363735343000313236373735363735343000000000000000000000000000' + - // just some junk - '420420420420420420420420420420420420420420420420420420420420', - 'hex') + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000030303037353520003035373736312000303030303234200030303030' + + '3030303134342000313236373735363735343000303135313331200030000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461720030306973616163730000000000000000000000000000000000' + + '0000000000000000007374616666000000000000000000000000000000000000' + + '0000000000000000003030303030302000303030303030200000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000031323637' + + '3735363735343000313236373735363735343000000000000000000000000000' + + // just some junk + '420420420420420420420420420420420420420420420420420420420420', + 'hex', + ) const h = new Header({ path: 'foo.txt', }) - h.set({ + Object.assign(h, { mode: 0o755, uid: 24561, gid: 20, @@ -102,7 +105,7 @@ t.test('xstar format', t => { h.encode() const slab = h.block - t.equal(slab.toString('hex'), buf.slice(0, 512).toString('hex')) + t.equal(slab.toString('hex'), buf.subarray(0, 512).toString('hex')) const h2 = new Header(buf) @@ -131,25 +134,27 @@ t.test('prefix handling', t => { t.test('no times', t => { const buf = Buffer.from( '666f6f2e74787400000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000030303037353520003035373736312000303030303234200030303030' + - '3030303134342000313236373735363735343000303337323734200030000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461720030306973616163730000000000000000000000000000000000' + - '0000000000000000007374616666000000000000000000000000000000000000' + - '00000000000000000030303030303020003030303030302000722f652f612f6c' + - '2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f79' + - '2f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f72' + - '2f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f61' + - '2f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f642f652f652f702f2d' + - '2f702f612f742f68000000000000000000000000000000000000000000000000', - 'hex') + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000030303037353520003035373736312000303030303234200030303030' + + '3030303134342000313236373735363735343000303337323734200030000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461720030306973616163730000000000000000000000000000000000' + + '0000000000000000007374616666000000000000000000000000000000000000' + + '00000000000000000030303030303020003030303030302000722f652f612f6c' + + '2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f79' + + '2f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f72' + + '2f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f61' + + '2f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f642f652f652f702f2d' + + '2f702f612f742f68000000000000000000000000000000000000000000000000', + 'hex', + ) const h = new Header({ - path: 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + + path: + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/d/e/e/p/-/p/a/t/h/foo.txt', mode: 0o755, @@ -166,14 +171,17 @@ t.test('prefix handling', t => { const b2 = Buffer.alloc(512) h.encode(b2, 0) - t.equal(b2.toString().replace(/\0+/g, ' '), - buf.toString().replace(/\0+/g, ' ')) + t.equal( + b2.toString().replace(/\0+/g, ' '), + buf.toString().replace(/\0+/g, ' '), + ) t.equal(b2.toString('hex'), buf.toString('hex')) const h2 = new Header(buf) t.match(h2, { - path: 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + + path: + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/d/e/e/p/-/p/a/t/h/foo.txt', mode: 0o755, @@ -192,10 +200,13 @@ t.test('prefix handling', t => { }) t.equal(b2.toString().replace(/\0.*$/, ''), 'foo.txt') - t.equal(b2.slice(345).toString().replace(/\0.*$/, ''), 'r/e/a/l/l/y/-' + - '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + - '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + - '/d/e/e/p/-/p/a/t/h') + t.equal( + b2.subarray(345).toString().replace(/\0.*$/, ''), + 'r/e/a/l/l/y/-' + + '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + + '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + + '/d/e/e/p/-/p/a/t/h', + ) t.end() }) @@ -203,27 +214,29 @@ t.test('prefix handling', t => { t.test('a/c times, use shorter prefix field', t => { const buf = Buffer.from( '652f702f2d2f702f612f742f682f666f6f2e7478740000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000030303037353520003035373736312000303030303234200030303030' + - '3030303134342000313236373735363735343000303431353030200030000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461720030306973616163730000000000000000000000000000000000' + - '0000000000000000007374616666000000000000000000000000000000000000' + - '00000000000000000030303030303020003030303030302000722f652f612f6c' + - '2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f79' + - '2f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f72' + - '2f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f61' + - '2f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f642f65000031323637' + - '3735363735343000313236373735363735343000000000000000000000000000', - 'hex') + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000030303037353520003035373736312000303030303234200030303030' + + '3030303134342000313236373735363735343000303431353030200030000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461720030306973616163730000000000000000000000000000000000' + + '0000000000000000007374616666000000000000000000000000000000000000' + + '00000000000000000030303030303020003030303030302000722f652f612f6c' + + '2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f79' + + '2f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f72' + + '2f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f61' + + '2f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f642f65000031323637' + + '3735363735343000313236373735363735343000000000000000000000000000', + 'hex', + ) const h = new Header() - h.path = 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + - 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + - '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/d/e/e/p/-/p/a/t/h/foo.txt' + h.path = + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + + '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/d/e/e/p/-/p/a/t/h/foo.txt' h.mode = 0o755 h.uid = 24561 h.gid = 20 @@ -241,33 +254,44 @@ t.test('prefix handling', t => { const b3 = Buffer.alloc(1024) h.encode(b3, 100) - t.equal(b2.toString('hex'), b3.slice(100, 612).toString('hex')) + t.equal(b2.toString('hex'), b3.subarray(100, 612).toString('hex')) const h2 = new Header(b3, 100) - t.match(h2, { - path: 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + - 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + - '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/d/e/e/p/-/p/a/t/h/foo.txt', - mode: 0o755, - uid: 24561, - gid: 20, - size: 100, - mtime: new Date('2016-04-01T22:00Z'), - ctime: new Date('2016-04-01T22:00Z'), - atime: new Date('2016-04-01T22:00Z'), - type: 'File', - uname: 'isaacs', - gname: 'staff', - cksumValid: true, - cksum: 17216, - needPax: false, - }, 'header from buffer') - - t.equal(b2.toString().replace(/\0.*$/, ''), 'e/p/-/p/a/t/h/foo.txt') - t.equal(b2.slice(345).toString().replace(/\0.*$/, ''), 'r/e/a/l/l/y/-' + - '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + - '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/d/e') + t.match( + h2, + { + path: + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + + '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/d/e/e/p/-/p/a/t/h/foo.txt', + mode: 0o755, + uid: 24561, + gid: 20, + size: 100, + mtime: new Date('2016-04-01T22:00Z'), + ctime: new Date('2016-04-01T22:00Z'), + atime: new Date('2016-04-01T22:00Z'), + type: 'File', + uname: 'isaacs', + gname: 'staff', + cksumValid: true, + cksum: 17216, + needPax: false, + }, + 'header from buffer', + ) + + t.equal( + b2.toString().replace(/\0.*$/, ''), + 'e/p/-/p/a/t/h/foo.txt', + ) + t.equal( + b2.subarray(345).toString().replace(/\0.*$/, ''), + 'r/e/a/l/l/y/-' + + '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-' + + '/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/d/e', + ) t.end() }) @@ -275,27 +299,30 @@ t.test('prefix handling', t => { t.test('hella long basename', t => { const buf = Buffer.from( '6c6f6e672d66696c652d6c6f6e672d66696c652d6c6f6e672d66696c652d6c6f' + - '6e672d66696c652d6c6f6e672d66696c652d6c6f6e672d66696c652d6c6f6e67' + - '2d66696c652d6c6f6e672d66696c652d6c6f6e672d66696c652d6c6f6e672d66' + - '696c650030303037353520003035373736312000303030303234200030303030' + - '3030303134342000313236373735363735343000303630313431200030000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461720030306973616163730000000000000000000000000000000000' + - '0000000000000000007374616666000000000000000000000000000000000000' + - '00000000000000000030303030303020003030303030302000722f652f612f6c' + - '2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f79' + - '2f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f72' + - '2f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f61' + - '2f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f642f652f652f702f2d' + - '2f702f612f742f68000000000000000000000000000000000000000000000000', - 'hex') + '6e672d66696c652d6c6f6e672d66696c652d6c6f6e672d66696c652d6c6f6e67' + + '2d66696c652d6c6f6e672d66696c652d6c6f6e672d66696c652d6c6f6e672d66' + + '696c650030303037353520003035373736312000303030303234200030303030' + + '3030303134342000313236373735363735343000303630313431200030000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461720030306973616163730000000000000000000000000000000000' + + '0000000000000000007374616666000000000000000000000000000000000000' + + '00000000000000000030303030303020003030303030302000722f652f612f6c' + + '2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f79' + + '2f2d2f722f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f72' + + '2f652f612f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f722f652f61' + + '2f6c2f6c2f792f2d2f722f652f612f6c2f6c2f792f2d2f642f652f652f702f2d' + + '2f702f612f742f68000000000000000000000000000000000000000000000000', + 'hex', + ) const h = new Header({ - path: 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + + path: + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/d/e/e/p/-/p/a/t/h/' + - (new Array(20).join('long-file-')) + 'long-file.txt', + new Array(20).join('long-file-') + + 'long-file.txt', mode: 0o755, uid: 24561, gid: 20, @@ -318,7 +345,8 @@ t.test('prefix handling', t => { t.match(h2, { cksumValid: true, cksum: 24673, - path: 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + + path: + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + 'r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/r/e/a/l/l/y/-/' + 'r/e/a/l/l/y/-/d/e/e/p/-/p/a/t/h/long-file-long-file-long-' + 'file-long-file-long-file-long-file-long-file-long-file-long-' + @@ -332,26 +360,30 @@ t.test('prefix handling', t => { t.test('long basename, long dirname', t => { const buf = Buffer.from( '6c6f6e672d6469726e616d652d6c6f6e672d6469726e616d652d6c6f6e672d64' + - '69726e616d652d6c6f6e672d6469726e616d652d6c6f6e672d6469726e616d65' + - '2d6c6f6e672d6469726e616d652d6c6f6e672d6469726e616d652d6c6f6e672d' + - '6469720030303037353520003035373736312000303030303234200030303030' + - '3030303134342000313236373735363735343000303334323035200030000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461720030306973616163730000000000000000000000000000000000' + - '0000000000000000007374616666000000000000000000000000000000000000' + - '0000000000000000003030303030302000303030303030200000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000', - 'hex') + '69726e616d652d6c6f6e672d6469726e616d652d6c6f6e672d6469726e616d65' + + '2d6c6f6e672d6469726e616d652d6c6f6e672d6469726e616d652d6c6f6e672d' + + '6469720030303037353520003035373736312000303030303234200030303030' + + '3030303134342000313236373735363735343000303334323035200030000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461720030306973616163730000000000000000000000000000000000' + + '0000000000000000007374616666000000000000000000000000000000000000' + + '0000000000000000003030303030302000303030303030200000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', + ) const h = new Header({ - path: (new Array(30).join('long-dirname-')) + 'long-dirname/' + - (new Array(20).join('long-file-')) + 'long-file.txt', + path: + new Array(30).join('long-dirname-') + + 'long-dirname/' + + new Array(20).join('long-file-') + + 'long-file.txt', mode: 0o755, uid: 24561, gid: 20, @@ -376,7 +408,8 @@ t.test('prefix handling', t => { const h2 = new Header(b2) t.match(h2, { - path: 'long-dirname-long-dirname-long-dirname-long-dirname-' + + path: + 'long-dirname-long-dirname-long-dirname-long-dirname-' + 'long-dirname-long-dirname-long-dirname-long-dir', cksum: 14469, cksumValid: true, @@ -388,11 +421,15 @@ t.test('prefix handling', t => { }) t.test('throwers', t => { - t.throws(_ => new Header(Buffer.alloc(100)), - new Error('need 512 bytes for header')) + t.throws( + _ => new Header(Buffer.alloc(100)), + new Error('need 512 bytes for header'), + ) - t.throws(_ => new Header({}).encode(Buffer.alloc(100)), - new Error('need 512 bytes for header')) + t.throws( + _ => new Header({}).encode(Buffer.alloc(100)), + new Error('need 512 bytes for header'), + ) t.end() }) @@ -404,68 +441,72 @@ t.test('null block', t => { needPax: false, path: '', type: 'File', - mode: null, - uid: null, - gid: null, - size: null, - mtime: null, - cksum: null, + mode: undefined, + uid: undefined, + gid: undefined, + size: undefined, + mtime: undefined, + cksum: undefined, linkpath: '', - uname: null, - gname: null, + uname: undefined, + gname: undefined, devmaj: 0, devmin: 0, - atime: null, - ctime: null, + atime: undefined, + ctime: undefined, nullBlock: true, }) t.end() }) t.test('unknown type', t => { - const h = new Header(Buffer.from( - '666f6f2e74787400000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000030303037353520003035373736312000303030303234200030303030' + - '303030313434200031323637373536373534300030303630373620005a000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000', - 'hex')) - - t.equal(h.type, 'Z') - t.equal(h.typeKey, 'Z') + const h = new Header( + Buffer.from( + '666f6f2e74787400000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000030303037353520003035373736312000303030303234200030303030' + + '303030313434200031323637373536373534300030303630373620005a000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', + ), + ) + + t.equal(h.type, 'Unsupported') + t.equal(h.typeKey, 'Unsupported') t.end() }) t.test('dir as file with trailing /', t => { const b = Buffer.from( '782f792f00000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000030303030' + - '3030303030302000000000000000000000000000303034363136200030000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461720030300000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000003030303030302000303030303030200000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000', - 'hex') + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000030303030' + + '3030303030302000000000000000000000000000303034363136200030000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461720030300000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000003030303030302000303030303030200000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', + ) const h = new Header(b) t.equal(h.type, 'Directory') b[156] = '0'.charCodeAt(0) @@ -478,24 +519,28 @@ t.test('null numeric values do not get written', t => { const b = Buffer.alloc(512) const h = new Header() h.encode(b, 0) - t.equal( - b.toString('hex'), - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000303033303737200030000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461720030300000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000003030303030302000303030303030200000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000') + t.same( + b, + Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000303033303737200030000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461720030300000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000003030303030302000303030303030200000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', + ), + ) const h2 = new Header(b) t.match(h2, { type: 'File', @@ -503,19 +548,19 @@ t.test('null numeric values do not get written', t => { needPax: false, nullBlock: false, path: '', - mode: null, - uid: null, - gid: null, - size: null, - mtime: null, + mode: undefined, + uid: undefined, + gid: undefined, + size: undefined, + mtime: undefined, cksum: 1599, linkpath: '', uname: '', gname: '', devmaj: 0, devmin: 0, - atime: null, - ctime: null, + atime: undefined, + ctime: undefined, }) t.end() }) @@ -535,22 +580,23 @@ t.test('big numbers', t => { t.test('dir with long body', t => { const b = Buffer.from( '7061636b6167652f76656e646f72000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000030303037353520003030303030302000303030303030200030303030' + - '3030313030303020313330363133303232343120303132303236200035000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461720030300000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000003030303030302000303030303030200000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000', - 'hex') + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000030303037353520003030303030302000303030303030200030303030' + + '3030313030303020313330363133303232343120303132303236200035000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461720030300000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000003030303030302000303030303030200000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', + ) const h = new Header(b) t.equal(h.type, 'Directory') t.equal(h.size, 0) @@ -558,13 +604,18 @@ t.test('dir with long body', t => { }) t.test('null block, global extended header', t => { - const h = new Header(Buffer.alloc(512), 0, { - undef: undefined, - blerg: 'bloo', - }, { - path: '/global.path', - foo: 'global foo', - }) + const h = new Header( + Buffer.alloc(512), + 0, + { + undef: undefined, + blerg: 'bloo', + }, + { + path: '/global.path', + foo: 'global foo', + }, + ) t.match(h, { cksumValid: false, needPax: false, @@ -593,22 +644,26 @@ t.test('null block, global extended header', t => { t.test('gnutar-generated 10gb file size', t => { const b = Buffer.from( '313067622e696d67000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000030303030363634003030303137353000303030313735300080000000' + - '0000000280000000313334373434303132303500303131313437002030000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461722020006973616163730000000000000000000000000000000000' + - '0000000000000000006973616163730000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000', 'hex') + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000030303030363634003030303137353000303030313735300080000000' + + '0000000280000000313334373434303132303500303131313437002030000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461722020006973616163730000000000000000000000000000000000' + + '0000000000000000006973616163730000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', + ) const h = new Header(b) t.equal(h.size, 1024 * 1024 * 1024 * 10, 'should be 10gb file') + // cannot set type to something invalid + t.throws(() => h.type = 'Z') t.end() }) diff --git a/test/high-level-opt.js b/test/high-level-opt.js deleted file mode 100644 index 7a82ef3f..00000000 --- a/test/high-level-opt.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict' - -const t = require('tap') -const hlo = require('../lib/high-level-opt.js') - -t.same(hlo(), {}) - -t.same(hlo({ - C: 'dir', - f: 'file', - z: 'zip', - P: 'preserve', - U: 'unlink', - 'strip-components': 99, - foo: 'bar', -}), { - cwd: 'dir', - file: 'file', - gzip: 'zip', - preservePaths: 'preserve', - unlink: 'unlink', - strip: 99, - foo: 'bar', -}) - -t.same(hlo({ - C: 'dir', - f: 'file', - z: 'zip', - P: 'preserve', - U: 'unlink', - stripComponents: 99, - foo: 'bar', -}), { - cwd: 'dir', - file: 'file', - gzip: 'zip', - preservePaths: 'preserve', - unlink: 'unlink', - strip: 99, - foo: 'bar', -}) diff --git a/test/index.js b/test/index.js index 548a1dee..147f821f 100644 --- a/test/index.js +++ b/test/index.js @@ -1,5 +1,6 @@ -const t = require('tap') -const tar = require('../') +import t from 'tap' +import * as tar from '../dist/esm/index.js' + t.match(tar, { create: Function, c: Function, @@ -13,7 +14,7 @@ t.match(tar, { x: Function, Pack: Function, Unpack: Function, - Parse: Function, + Parser: Function, ReadEntry: Function, WriteEntry: Function, Header: Function, @@ -67,7 +68,7 @@ t.match(tar, { ]), }, }) -t.match(tar.Pack.Sync, Function) -t.match(tar.WriteEntry.Sync, Function) -t.match(tar.WriteEntry.Tar, Function) +t.match(tar.PackSync, Function) +t.match(tar.WriteEntrySync, Function) +t.match(tar.WriteEntryTar, Function) t.match(tar.Pax.parse, Function) diff --git a/test/large-numbers.js b/test/large-numbers.js index 055493e9..f2b80467 100644 --- a/test/large-numbers.js +++ b/test/large-numbers.js @@ -1,8 +1,5 @@ -'use strict' -const large = require('../lib/large-numbers.js') -const encode = large.encode -const parse = large.parse -const t = require('tap') +import t from 'tap' +import { encode, parse } from '../dist/esm/large-numbers.js' t.test('parse', t => { const cases = new Map([ diff --git a/test/list.js b/test/list.js index 26f59d9f..1533dc6d 100644 --- a/test/list.js +++ b/test/list.js @@ -1,15 +1,22 @@ -'use strict' -const t = require('tap') -const list = require('../lib/list.js') -const path = require('path') -const fs = require('fs') -const mutateFS = require('mutate-fs') +import fs, { readFileSync } from 'fs' +import mutateFS from 'mutate-fs' +import { dirname, resolve } from 'path' +import t from 'tap' +import { fileURLToPath } from 'url' +import { list } from '../dist/esm/list.js' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +const lp = JSON.parse( + readFileSync(__dirname + '/fixtures/parse/long-paths.json', 'utf8'), +) t.test('basic', t => { - const file = path.resolve(__dirname, 'fixtures/tars/long-paths.tar') - const expect = require('./fixtures/parse/long-paths.json').filter( - e => Array.isArray(e) && e[0] === 'entry' - ).map(e => e[1].path) + const file = resolve(__dirname, 'fixtures/tars/long-paths.tar') + const expect = lp + .filter(e => Array.isArray(e) && e[0] === 'entry') + .map(e => e[1].path) const check = (actual, t) => { t.same(actual, expect) @@ -30,30 +37,33 @@ t.test('basic', t => { return check(actual, t) }) - t.test('async promise', t => { + t.test('async promise', async t => { const actual = [] const onentry = entry => actual.push(entry.path) - return list({ - file: file, - onentry: onentry, - maxReadSize: maxReadSize, - }).then(_ => check(actual, t)) + return await list({ + file, + onentry, + maxReadSize, + }).then(() => check(actual, t)) }) t.test('async cb', t => { const actual = [] const onentry = entry => actual.push(entry.path) - list({ - file: file, - onentry: onentry, - maxReadSize: maxReadSize, - }, er => { - if (er) { - throw er - } - check(actual, t) - t.end() - }) + list( + { + file: file, + onentry: onentry, + maxReadSize: maxReadSize, + }, + er => { + if (er) { + throw er + } + check(actual, t) + t.end() + }, + ) }) t.end() }) @@ -79,7 +89,7 @@ t.test('basic', t => { t.end() }) - t.test('no onentry function', t => list({ file: file })) + t.test('no onentry function', () => list({ file: file })) t.test('limit to specific files', t => { const fileList = [ @@ -98,35 +108,43 @@ t.test('basic', t => { 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', ] - t.test('no filter function', t => { + t.test('no filter function', async t => { const check = _ => t.same(actual, expect) const actual = [] - return list({ - file: file, - onentry: entry => actual.push(entry.path), - }, fileList).then(check) + return list( + { + file: file, + onentry: entry => actual.push(entry.path), + }, + fileList, + ).then(check) }) t.test('no filter function, stream', t => { const check = _ => t.same(actual, expect) const actual = [] const onentry = entry => actual.push(entry.path) - fs.createReadStream(file).pipe(list(fileList) - .on('entry', onentry) - .on('end', _ => { - check() - t.end() - })) + fs.createReadStream(file).pipe( + list(fileList) + .on('entry', onentry) + .on('end', _ => { + check() + t.end() + }), + ) }) - t.test('filter function', t => { + t.test('filter function', async t => { const check = _ => t.same(actual, expect.slice(0, 1)) const actual = [] - return list({ - file: file, - filter: path => path === expect[0], - onentry: entry => actual.push(entry.path), - }, fileList).then(check) + return list( + { + file: file, + filter: path => path === expect[0], + onentry: entry => actual.push(entry.path), + }, + fileList, + ).then(check) }) return t.test('list is unmunged', t => { @@ -142,10 +160,14 @@ t.test('basic', t => { }) t.test('bad args', t => { - t.throws(_ => list({ file: __filename, sync: true }, _ => _), - new TypeError('callback not supported for sync tar functions')) - t.throws(_ => list(_ => _), - new TypeError('callback only supported with file option')) + t.throws( + _ => list({ file: __filename, sync: true }, _ => _), + new TypeError('callback not supported for sync tar functions'), + ) + t.throws( + _ => list(_ => _), + new TypeError('callback only supported with file option'), + ) t.end() }) @@ -172,11 +194,15 @@ t.test('read fail', t => { const poop = new Error('poop') t.teardown(mutateFS.fail('read', poop)) t.plan(1) - t.throws(_ => list({ - file: __filename, - sync: true, - maxReadSize: 10, - }), poop) + t.throws( + _ => + list({ + file: __filename, + sync: true, + maxReadSize: 10, + }), + poop, + ) }) t.test('cb', t => { const poop = new Error('poop') @@ -194,7 +220,7 @@ t.test('read fail', t => { }) t.test('noResume option', t => { - const file = path.resolve(__dirname, 'fixtures/tars/file.tar') + const file = resolve(__dirname, 'fixtures/tars/file.tar') t.test('sync', t => { let e list({ @@ -214,16 +240,18 @@ t.test('noResume option', t => { e.on('end', _ => t.end()) }) - t.test('async', t => list({ - file: file, - onentry: entry => { - process.nextTick(_ => { - t.notOk(entry.flowing) - entry.resume() - }) - }, - noResume: true, - })) + t.test('async', t => + list({ + file: file, + onentry: entry => { + process.nextTick(_ => { + t.notOk(entry.flowing) + entry.resume() + }) + }, + noResume: true, + }), + ) t.end() }) diff --git a/test/load-all.js b/test/load-all.js index 524a3f4e..111a5fb6 100644 --- a/test/load-all.js +++ b/test/load-all.js @@ -1,10 +1,16 @@ -'use strict' // just load all the files so we can't cheat coverage by avoiding something -require('../') -const fs = require('fs') -const path = require('path') -const lib = path.resolve(__dirname, '../lib') -fs.readdirSync(lib) - .filter(f => /\.js$/.test(f)) - .forEach(f => require('../lib/' + f)) -require('tap').pass('all lib files loaded') +import fs from 'fs' +import t from 'tap' +import path, { dirname } from 'path' +import { fileURLToPath } from 'url' +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) +const lib = path.resolve(__dirname, '../dist/esm') +await Promise.all( + fs + .readdirSync(lib) + .filter(f => /\.js$/.test(f)) + .map(f => import('../dist/esm/' + f)), +) + +t.pass('all lib files loaded') diff --git a/test/make-tar.js b/test/make-tar.js deleted file mode 100644 index 668d2164..00000000 --- a/test/make-tar.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict' -// a little utility to create virtual tar data -if (module === require.main) { - return require('tap').pass('this is fine') -} - -const Header = require('../lib/header.js') -module.exports = chunks => { - let dataLen = 0 - return Buffer.concat(chunks.map(chunk => { - if (Buffer.isBuffer(chunk)) { - dataLen += chunk.length - return chunk - } - const size = Math.max(typeof chunk === 'string' - ? 512 * Math.ceil(chunk.length / 512) - : 512) - dataLen += size - const buf = Buffer.alloc(size) - if (typeof chunk === 'string') { - buf.write(chunk) - } else { - new Header(chunk).encode(buf, 0) - } - return buf - }), dataLen) -} diff --git a/test/map.js b/test/map.js index fcd4e47f..33d3251b 100644 --- a/test/map.js +++ b/test/map.js @@ -1,7 +1,9 @@ -const t = require('tap') -const map = require('../map.js') -t.equal(map('test/index.js'), 'index.js') -t.same(map('test/unpack.js'), ['lib/unpack.js', 'lib/mkdir.js']) +import t from 'tap' +import map from '../map.js' +import { fileURLToPath } from 'url' +const __filename = fileURLToPath(import.meta.url) +t.equal(map('test/index.js'), 'src/index.ts') +t.same(map('test/unpack.js'), ['src/unpack.ts', 'src/mkdir.ts']) t.same(map('test/load-all.js'), []) t.equal(map(__filename), 'map.js') -t.equal(map('test/asdf'), 'lib/asdf') +t.equal(map('test/asdf'), 'src/asdf') diff --git a/test/mode-fix.js b/test/mode-fix.js index 779124b1..6c5b54a6 100644 --- a/test/mode-fix.js +++ b/test/mode-fix.js @@ -1,16 +1,15 @@ -'use strict' -const t = require('tap') -const mf = require('../lib/mode-fix.js') +import t from 'tap' +import { modeFix } from '../dist/esm/mode-fix.js' -t.equal(mf(0o10644, false), 0o644) -t.equal(mf(0o10644, true), 0o755) -t.equal(mf(0o10604, true), 0o705) -t.equal(mf(0o10600, true), 0o700) -t.equal(mf(0o10066, true), 0o077) +t.equal(modeFix(0o10644, false), 0o644) +t.equal(modeFix(0o10644, true), 0o755) +t.equal(modeFix(0o10604, true), 0o705) +t.equal(modeFix(0o10600, true), 0o700) +t.equal(modeFix(0o10066, true), 0o077) -t.equal(mf(0o10664, false, true), 0o644) -t.equal(mf(0o10066, false, true), 0o644) -t.equal(mf(0o10666, true, true), 0o755) -t.equal(mf(0o10604, true, true), 0o705) -t.equal(mf(0o10600, true, true), 0o700) -t.equal(mf(0o10066, true, true), 0o755) +t.equal(modeFix(0o10664, false, true), 0o644) +t.equal(modeFix(0o10066, false, true), 0o644) +t.equal(modeFix(0o10666, true, true), 0o755) +t.equal(modeFix(0o10604, true, true), 0o705) +t.equal(modeFix(0o10600, true, true), 0o700) +t.equal(modeFix(0o10066, true, true), 0o755) diff --git a/test/normalize-unicode.js b/test/normalize-unicode.js index 0d34f38c..969ee6ca 100644 --- a/test/normalize-unicode.js +++ b/test/normalize-unicode.js @@ -1,18 +1,32 @@ +import t from 'tap' + process.env.TESTING_TAR_FAKE_PLATFORM = 'win32' -const t = require('tap') -const normalize = require('../lib/normalize-unicode.js') -const stripSlash = require('../lib/strip-trailing-slashes.js') -const normPath = require('../lib/normalize-windows-path.js') + +const [ + { normalizeUnicode }, + { stripTrailingSlashes }, + { normalizeWindowsPath }, +] = await Promise.all([ + import('../dist/esm/normalize-unicode.js'), + import('../dist/esm/strip-trailing-slashes.js'), + import('../dist/esm/normalize-windows-path.js'), +]) // cafeˁ const cafe1 = Buffer.from([0x63, 0x61, 0x66, 0xc3, 0xa9]).toString() // cafe with a ` -const cafe2 = Buffer.from([0x63, 0x61, 0x66, 0x65, 0xcc, 0x81]).toString() +const cafe2 = Buffer.from([ + 0x63, 0x61, 0x66, 0x65, 0xcc, 0x81, +]).toString() -t.equal(normalize(cafe1), normalize(cafe2), 'matching unicodes') -t.equal(normalize(cafe1), normalize(cafe2), 'cached') -t.equal(normalize('foo'), 'foo', 'non-unicode string') +t.equal( + normalizeUnicode(cafe1), + normalizeUnicode(cafe2), + 'matching unicodes', +) +t.equal(normalizeUnicode(cafe1), normalizeUnicode(cafe2), 'cached') +t.equal(normalizeUnicode('foo'), 'foo', 'non-unicode string') t.test('normalize with strip slashes', t => { const paths = [ @@ -28,8 +42,12 @@ t.test('normalize with strip slashes', t => { for (const path of paths) { t.test(JSON.stringify(path), t => { - const a = normalize(stripSlash(normPath(path))) - const b = stripSlash(normPath(normalize(path))) + const a = normalizeUnicode( + stripTrailingSlashes(normalizeWindowsPath(path)), + ) + const b = stripTrailingSlashes( + normalizeWindowsPath(normalizeUnicode(path)), + ) t.matchSnapshot(a, 'normalized') t.equal(a, b, 'order should not matter') t.end() diff --git a/test/normalize-windows-path.js b/test/normalize-windows-path.js index e9c705ab..8fbaa647 100644 --- a/test/normalize-windows-path.js +++ b/test/normalize-windows-path.js @@ -1,28 +1,38 @@ -const t = require('tap') +import t from 'tap' const realPlatform = process.platform const fakePlatform = realPlatform === 'win32' ? 'posix' : 'win32' -t.test('posix', t => { +t.test('posix', async t => { if (realPlatform === 'win32') { process.env.TESTING_TAR_FAKE_PLATFORM = fakePlatform } else { delete process.env.TESTING_TAR_FAKE_PLATFORM } - const normPath = t.mock('../lib/normalize-windows-path.js') - t.equal(normPath('/some/path/back\\slashes'), '/some/path/back\\slashes') - t.equal(normPath('c:\\foo\\bar'), 'c:\\foo\\bar') + const { normalizeWindowsPath } = await t.mockImport( + '../dist/esm/normalize-windows-path.js', + ) + t.equal( + normalizeWindowsPath('/some/path/back\\slashes'), + '/some/path/back\\slashes', + ) + t.equal(normalizeWindowsPath('c:\\foo\\bar'), 'c:\\foo\\bar') t.end() }) -t.test('win32', t => { +t.test('win32', async t => { if (realPlatform !== 'win32') { process.env.TESTING_TAR_FAKE_PLATFORM = fakePlatform } else { delete process.env.TESTING_TAR_FAKE_PLATFORM } - const normPath = t.mock('../lib/normalize-windows-path.js') - t.equal(normPath('/some/path/back\\slashes'), '/some/path/back/slashes') - t.equal(normPath('c:\\foo\\bar'), 'c:/foo/bar') + const { normalizeWindowsPath } = await t.mockImport( + '../dist/esm/normalize-windows-path.js', + ) + t.equal( + normalizeWindowsPath('/some/path/back\\slashes'), + '/some/path/back/slashes', + ) + t.equal(normalizeWindowsPath('c:\\foo\\bar'), 'c:/foo/bar') t.end() }) diff --git a/test/options.js b/test/options.js new file mode 100644 index 00000000..5e10df5b --- /dev/null +++ b/test/options.js @@ -0,0 +1,65 @@ +import t from 'tap' +import { + dealias, + isSync, + isSyncFile, + isFile, +} from '../dist/esm/options.js' + +t.same(dealias(), {}) +t.same(dealias(false), {}) + +t.same( + dealias({ + C: 'dir', + f: 'file', + z: 'zip', + P: 'preserve', + U: 'unlink', + 'strip-components': 99, + foo: 'bar', + }), + { + cwd: 'dir', + file: 'file', + gzip: 'zip', + preservePaths: 'preserve', + unlink: 'unlink', + strip: 99, + foo: 'bar', + }, +) + +t.same( + dealias({ + C: 'dir', + f: 'file', + z: 'zip', + P: 'preserve', + U: 'unlink', + stripComponents: 99, + foo: 'bar', + }), + { + cwd: 'dir', + file: 'file', + gzip: 'zip', + preservePaths: 'preserve', + unlink: 'unlink', + strip: 99, + foo: 'bar', + }, +) + +t.equal(isSyncFile(dealias({ sync: true, f: 'x' })), true) +t.equal(isSyncFile(dealias({ file: 'x' })), false) +t.equal(isSyncFile(dealias({ sync: true })), false) +t.equal(isSyncFile(dealias({})), false) +t.equal(isSync(dealias({ sync: true, f: 'x' })), true) +t.equal(isSync(dealias({ file: 'x' })), false) +t.equal(isSync(dealias({ sync: true })), true) +t.equal(isSync(dealias({})), false) +t.equal(isFile(dealias({ sync: true, f: 'x' })), true) +t.equal(isFile(dealias({ file: 'x' })), true) +t.equal(isFile(dealias({ sync: true })), false) +t.equal(isFile(dealias({})), false) diff --git a/test/pack.js b/test/pack.js index a4f8bfbe..dae2fba9 100644 --- a/test/pack.js +++ b/test/pack.js @@ -1,37 +1,45 @@ -'use strict' -const t = require('tap') -const Pack = require('../lib/pack.js') -const PackSync = Pack.Sync -const fs = require('fs') -const path = require('path') +import t from 'tap' +import { Pack, PackSync } from '../dist/esm/pack.js' +import fs from 'fs' +import path from 'path' +import { fileURLToPath } from 'url' + +import { Header } from '../dist/esm/header.js' +import zlib from 'zlib' +import * as miniz from 'minizlib' +import mutateFS from 'mutate-fs' +import { Minipass } from 'minipass' +import EE from 'events' +import { rimraf } from 'rimraf' +import { mkdirp } from 'mkdirp' +import { ReadEntry } from '../dist/esm/read-entry.js' +import { normalizeWindowsPath as normPath } from '../dist/esm/normalize-windows-path.js' + +const { default: chmodr } = await import('chmodr') + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) + const fixtures = path.resolve(__dirname, 'fixtures') const files = path.resolve(fixtures, 'files') const tars = path.resolve(fixtures, 'tars') -const chmodr = require('chmodr') -const Header = require('../lib/header.js') -const zlib = require('zlib') -const miniz = require('minizlib') -const mutateFS = require('mutate-fs') -const { Minipass } = require('minipass') + process.env.USER = 'isaacs' -const EE = require('events').EventEmitter -const rimraf = require('rimraf') -const mkdirp = require('mkdirp') -const ReadEntry = require('../lib/read-entry.js') const isWindows = process.platform === 'win32' -const normPath = require('../lib/normalize-windows-path.js') const ctime = new Date('2017-05-10T01:03:12.000Z') const atime = new Date('2017-04-17T00:00:00.000Z') const mtime = new Date('2016-04-01T19:00:00.000Z') -t.teardown(mutateFS.statMutate((er, st) => { - if (st) { - st.ctime = ctime - st.atime = atime - st.mtime = mtime - } -})) +t.teardown( + mutateFS.statMutate((_er, st) => { + if (st) { + st.ctime = ctime + st.atime = atime + st.mtime = mtime + } + }), +) t.test('set up', t => { const one = fs.statSync(files + '/hardlink-1') @@ -54,7 +62,7 @@ t.test('pack a file', t => { .on('end', _ => { const data = Buffer.concat(out) t.equal(data.length, 2048) - t.match(data.slice(512).toString(), /^a\0{511}\0{1024}$/) + t.match(data.subarray(512).toString(), /^a\0{511}\0{1024}$/) const h = new Header(data) const expect = { cksumValid: true, @@ -84,7 +92,7 @@ t.test('pack a file', t => { throw new Error('no data!') } - t.equal(sync.slice(512).toString(), data.slice(512).toString()) + t.equal(sync.subarray(512).toString(), data.subarray(512).toString()) const hs = new Header(sync) t.match(hs, expect) t.end() @@ -93,13 +101,13 @@ t.test('pack a file', t => { t.test('pack a file with a prefix', t => { const out = [] - new Pack({ cwd: files, prefix: 'package/' }) + new Pack({ mtime, cwd: files, prefix: 'package/' }) .end('.dotfile') .on('data', c => out.push(c)) .on('end', _ => { const data = Buffer.concat(out) t.equal(data.length, 2048) - t.match(data.slice(512).toString(), /^.\n\0{510}\0{1024}$/) + t.match(data.subarray(512).toString(), /^.\n\0{510}\0{1024}$/) const h = new Header(data) const expect = { cksumValid: true, @@ -121,8 +129,10 @@ t.test('pack a file with a prefix', t => { } t.match(h, expect) const sync = new PackSync({ cwd: files, prefix: 'package' }) - .add('.dotfile').end().read() - t.equal(sync.slice(512).toString(), data.slice(512).toString()) + .add('.dotfile') + .end() + .read() + t.equal(sync.subarray(512).toString(), data.subarray(512).toString()) const hs = new Header(sync) t.match(hs, expect) t.end() @@ -163,15 +173,21 @@ t.test('portable pack a dir', t => { } t.match(h, expect) t.equal(data.length, 2048) - t.match(data.slice(1024).toString(), /^\0{1024}$/) + t.match(data.subarray(1024).toString(), /^\0{1024}$/) - const syncgz = new PackSync({ cwd: files, portable: true, gzip: true }) - .add('dir').end().read() + const syncgz = new PackSync({ + cwd: files, + portable: true, + gzip: true, + }) + .add('dir') + .end() + .read() t.equal(syncgz[9], 255, 'gzip OS flag set to "unknown"') const sync = new miniz.Gunzip().end(zipped).read() - t.equal(sync.slice(512).toString(), data.slice(512).toString()) + t.equal(sync.subarray(512).toString(), data.subarray(512).toString()) const hs = new Header(sync) t.match(hs, expect) @@ -193,8 +209,8 @@ t.test('portable pack a dir', t => { ctime: null, nullBlock: false, } - t.match(new Header(data.slice(512)), expect2) - t.match(new Header(sync.slice(512)), expect2) + t.match(new Header(data.subarray(512)), expect2) + t.match(new Header(sync.subarray(512)), expect2) t.end() }) }) @@ -235,11 +251,13 @@ t.test('use process cwd if cwd not specified', t => { } t.match(h, expect) t.equal(data.length, 2048) - t.match(data.slice(1024).toString(), /^\0{1024}$/) + t.match(data.subarray(1024).toString(), /^\0{1024}$/) const sync = new PackSync({ cwd: files }) - .add('dir').end().read() - t.equal(sync.slice(512).toString(), data.slice(512).toString()) + .add('dir') + .end() + .read() + t.equal(sync.subarray(512).toString(), data.subarray(512).toString()) const hs = new Header(sync) t.match(hs, expect) @@ -261,15 +279,15 @@ t.test('use process cwd if cwd not specified', t => { ctime: ctime, nullBlock: false, } - t.match(new Header(data.slice(512)), expect2) - t.match(new Header(sync.slice(512)), expect2) + t.match(new Header(data.subarray(512)), expect2) + t.match(new Header(sync.subarray(512)), expect2) t.end() }) }) t.test('filter', t => { const out = [] - const filter = (path, stat) => stat.isDirectory() + const filter = (_path, stat) => stat.isDirectory() // only include directories, so dir/x should not appear new Pack({ cwd: files, filter: filter }) @@ -301,11 +319,13 @@ t.test('filter', t => { } t.match(h, expect) t.equal(data.length, 1536) - t.match(data.slice(512).toString(), /^\0{1024}$/) + t.match(data.subarray(512).toString(), /^\0{1024}$/) const sync = new PackSync({ cwd: files, filter: filter }) - .add('dir').end().read() - t.equal(sync.slice(512).toString(), data.slice(512).toString()) + .add('dir') + .end() + .read() + t.equal(sync.subarray(512).toString(), data.subarray(512).toString()) const hs = new Header(sync) t.match(hs, expect) t.end() @@ -314,7 +334,7 @@ t.test('filter', t => { t.test('add the same dir twice (exercise cache code)', t => { const out = [] - const filter = (path, stat) => stat.isDirectory() + const filter = (_path, stat) => stat.isDirectory() // only include directories, so dir/x should not appear const pack = new Pack({ cwd: files, filter: filter }) @@ -346,10 +366,10 @@ t.test('add the same dir twice (exercise cache code)', t => { nullBlock: false, } t.match(h, expect) - const h2 = new Header(data.slice(512)) + const h2 = new Header(data.subarray(512)) t.match(h2, expect) t.equal(data.length, 2048) - t.match(data.slice(1024).toString(), /^\0{1024}$/) + t.match(data.subarray(1024).toString(), /^\0{1024}$/) const sync = new PackSync({ cwd: files, @@ -358,11 +378,17 @@ t.test('add the same dir twice (exercise cache code)', t => { readdirCache: pack.readdirCache, statCache: pack.statCache, }) - .add('dir').add('dir').end().read() - t.equal(sync.slice(1024).toString(), data.slice(1024).toString()) + .add('dir') + .add('dir') + .end() + .read() + t.equal( + sync.subarray(1024).toString(), + data.subarray(1024).toString(), + ) const hs = new Header(sync) t.match(hs, expect) - const hs2 = new Header(sync.slice(512)) + const hs2 = new Header(sync.subarray(512)) t.match(hs2, expect) t.end() }) @@ -384,7 +410,10 @@ t.test('if brotli is truthy, make it an object', t => { t.test('throws if both gzip and brotli are truthy', t => { const opt = { gzip: true, brotli: true } - t.throws(_ => new Pack(opt), new TypeError('gzip and brotli are mutually exclusive')) + t.throws( + _ => new Pack(opt), + new TypeError('gzip and brotli are mutually exclusive'), + ) t.end() }) @@ -404,14 +433,16 @@ t.test('gzip, also a very deep path', t => { const data = zlib.unzipSync(zipped) const entries = [] for (var i = 0; i < data.length; i += 512) { - const slice = data.slice(i, i + 512) + const slice = data.subarray(i, i + 512) const h = new Header(slice) if (h.nullBlock) { entries.push('null block') } else if (h.cksumValid) { entries.push([h.type, h.path]) } else if (entries[entries.length - 1][0] === 'File') { - entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) + entries[entries.length - 1].push( + slice.toString().replace(/\0.*$/, ''), + ) } } @@ -436,27 +467,72 @@ t.test('gzip, also a very deep path', t => { ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/'], ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/'], ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', 'short\n'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], - ['ExtendedHeader', 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222'], - ['ExtendedHeader', 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', + 'short\n', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', + ], + [ + 'ExtendedHeader', + 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222', + ], + [ + 'ExtendedHeader', + 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + ], ['ExtendedHeader', 'PaxHeader/Ί.txt'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', 'Ί'], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', + 'Ί', + ], 'null block', 'null block', ] let ok = true entries.forEach((entry, i) => { - ok = ok && + ok = + ok && t.equal(entry[0], expect[i][0]) && t.equal(entry[1], expect[i][1]) && (!entry[2] || t.equal(entry[2], expect[i][2])) @@ -483,14 +559,16 @@ t.test('brotli, also a very deep path', t => { const data = zlib.brotliDecompressSync(zipped) const entries = [] for (var i = 0; i < data.length; i += 512) { - const slice = data.slice(i, i + 512) + const slice = data.subarray(i, i + 512) const h = new Header(slice) if (h.nullBlock) { entries.push('null block') } else if (h.cksumValid) { entries.push([h.type, h.path]) } else if (entries[entries.length - 1][0] === 'File') { - entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) + entries[entries.length - 1].push( + slice.toString().replace(/\0.*$/, ''), + ) } } @@ -515,30 +593,75 @@ t.test('brotli, also a very deep path', t => { ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/'], ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/'], ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', 'short\n'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], - ['ExtendedHeader', 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222'], - ['ExtendedHeader', 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', + 'short\n', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', + ], + [ + 'ExtendedHeader', + 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222', + ], + [ + 'ExtendedHeader', + 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + ], ['ExtendedHeader', 'PaxHeader/Ί.txt'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', 'Ί'], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', + 'Ί', + ], 'null block', 'null block', ] let ok = true entries.forEach((entry, i) => { - ok = ok && - t.equal(entry[0], expect[i][0]) && - t.equal(entry[1], expect[i][1]) && - (!entry[2] || t.equal(entry[2], expect[i][2])) + ok = + ok && + t.equal(entry[0], expect[i][0]) && + t.equal(entry[1], expect[i][1]) && + (!entry[2] || t.equal(entry[2], expect[i][2])) }) t.end() @@ -549,7 +672,8 @@ t.test('very deep gzip path, sync', t => { const pack = new PackSync({ cwd: files, gzip: true, - }).add('dir') + }) + .add('dir') .add('long-path') .end() @@ -562,14 +686,16 @@ t.test('very deep gzip path, sync', t => { const data = zlib.unzipSync(zipped) const entries = [] for (var i = 0; i < data.length; i += 512) { - const slice = data.slice(i, i + 512) + const slice = data.subarray(i, i + 512) const h = new Header(slice) if (h.nullBlock) { entries.push('null block') } else if (h.cksumValid) { entries.push([h.type, h.path]) } else if (entries[entries.length - 1][0] === 'File') { - entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) + entries[entries.length - 1].push( + slice.toString().replace(/\0.*$/, ''), + ) } } @@ -596,25 +722,64 @@ t.test('very deep gzip path, sync', t => { ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/'], ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/'], ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', 'short\n'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], - ['ExtendedHeader', 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222'], - ['ExtendedHeader', 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', + 'short\n', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', + ], + [ + 'ExtendedHeader', + 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222', + ], + [ + 'ExtendedHeader', + 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + ], ['ExtendedHeader', 'PaxHeader/Ί.txt'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', 'Ί'], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', + 'Ί', + ], 'null block', 'null block', ] let ok = true entries.forEach((entry, i) => { - ok = ok && + ok = + ok && t.equal(entry[0], expect[i][0]) && t.equal(entry[1], expect[i][1]) && (!entry[2] || t.equal(entry[2], expect[i][2])) @@ -628,7 +793,8 @@ t.test('very deep brotli path, sync', t => { const pack = new PackSync({ cwd: files, brotli: true, - }).add('dir') + }) + .add('dir') .add('long-path') .end() @@ -641,14 +807,16 @@ t.test('very deep brotli path, sync', t => { const data = zlib.brotliDecompressSync(zipped) const entries = [] for (var i = 0; i < data.length; i += 512) { - const slice = data.slice(i, i + 512) + const slice = data.subarray(i, i + 512) const h = new Header(slice) if (h.nullBlock) { entries.push('null block') } else if (h.cksumValid) { entries.push([h.type, h.path]) } else if (entries[entries.length - 1][0] === 'File') { - entries[entries.length - 1].push(slice.toString().replace(/\0.*$/, '')) + entries[entries.length - 1].push( + slice.toString().replace(/\0.*$/, ''), + ) } } @@ -675,28 +843,67 @@ t.test('very deep brotli path, sync', t => { ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/'], ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/'], ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/'], - ['Directory', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', 'short\n'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'], - ['ExtendedHeader', 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222'], - ['ExtendedHeader', 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/', + ], + [ + 'Directory', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt', + 'short\n', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', + ], + [ + 'ExtendedHeader', + 'PaxHeader/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222', + ], + [ + 'ExtendedHeader', + 'PaxHeader/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccc', + ], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxccccccccccccccccccccccccccccccccccccccccccccccccc', + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + ], ['ExtendedHeader', 'PaxHeader/Ί.txt'], - ['File', 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', 'Ί'], + [ + 'File', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt', + 'Ί', + ], 'null block', 'null block', ] let ok = true entries.forEach((entry, i) => { - ok = ok && + ok = + ok && t.equal(entry[0], expect[i][0]) && - t.equal(entry[1], expect[i][1]) && - (!entry[2] || t.equal(entry[2], expect[i][2])) + t.equal(entry[1], expect[i][1]) && + (!entry[2] || t.equal(entry[2], expect[i][2])) }) t.end() @@ -711,8 +918,10 @@ t.test('write after end', t => { t.test('emit error when stat fail', t => { t.teardown(mutateFS.statFail(new Error('xyz'))) - t.throws(_ => new PackSync({ cwd: files }).add('one-byte.txt'), - new Error('xyz')) + t.throws( + _ => new PackSync({ cwd: files }).add('one-byte.txt'), + new Error('xyz'), + ) new Pack({ cwd: files }).add('one-byte.txt').on('error', e => { t.match(e, { message: 'xyz' }) @@ -722,7 +931,10 @@ t.test('emit error when stat fail', t => { t.test('readdir fail', t => { t.teardown(mutateFS.fail('readdir', new Error('xyz'))) - t.throws(_ => new PackSync({ cwd: files }).add('dir'), new Error('xyz')) + t.throws( + _ => new PackSync({ cwd: files }).add('dir'), + new Error('xyz'), + ) new Pack({ cwd: files }).add('dir').on('error', e => { t.match(e, { message: 'xyz' }) @@ -764,7 +976,7 @@ t.test('pipe into a slow reader', t => { } t.match(h, expect) t.equal(data.length, 21504) - t.match(data.slice(data.length - 1024).toString(), /^\0{1024}$/) + t.match(data.subarray(data.length - 1024).toString(), /^\0{1024}$/) t.end() }) }) @@ -772,11 +984,13 @@ t.test('pipe into a slow reader', t => { t.test('pipe into a slow gzip reader', t => { const out = [] const mp2 = new miniz.Unzip() - const p = new Pack({ cwd: files, gzip: true }).add('long-path').end() + const p = new Pack({ cwd: files, gzip: true }) + .add('long-path') + .end() p.pause() class SlowStream extends EE { - write (chunk) { + write(chunk) { mp2.write(chunk) setTimeout(_ => { this.emit('drain') @@ -785,7 +999,7 @@ t.test('pipe into a slow gzip reader', t => { return false } - end (chunk) { + end(chunk) { return mp2.end(chunk) } } @@ -823,7 +1037,7 @@ t.test('pipe into a slow gzip reader', t => { } t.match(h, expect) t.equal(data.length, 21504) - t.match(data.slice(data.length - 1024).toString(), /^\0{1024}$/) + t.match(data.subarray(data.length - 1024).toString(), /^\0{1024}$/) t.end() }) }) @@ -835,12 +1049,12 @@ t.test('ignores mid-queue', t => { let didFirst = false const p = new Pack({ cwd: tars, - filter: (p, st) => { + filter: (p, _st) => { if (p === './') { return true } if (!didFirst) { - return didFirst = true + return (didFirst = true) } return false }, @@ -852,8 +1066,8 @@ t.test('ignores mid-queue', t => { p.on('data', c => out.push(c)) p.on('end', _ => { const data = Buffer.concat(out) - t.equal(data.slice(0, 100).toString().replace(/\0.*$/, ''), './') - const file = data.slice(512, 612).toString().replace(/\0.*$/, '') + t.equal(data.subarray(0, 100).toString().replace(/\0.*$/, ''), './') + const file = data.subarray(512, 612).toString().replace(/\0.*$/, '') t.not(files.indexOf(file), -1) t.end() }) @@ -869,17 +1083,21 @@ t.test('warnings', t => { const p = new Pack({ cwd: files, onwarn: (c, m, p) => warnings.push([c, m, p]), - }).end(f).on('data', c => out.push(c)) + }) + .end(f) + .on('data', c => out.push(c)) const out = [] p.on('end', _ => { const data = Buffer.concat(out) t.equal(data.length, 2048) - t.match(warnings, [[ - 'TAR_ENTRY_INFO', - /stripping .* from absolute path/, - { path: normPath(f) }, - ]]) + t.match(warnings, [ + [ + 'TAR_ENTRY_INFO', + /stripping .* from absolute path/, + { path: normPath(f) }, + ], + ]) t.match(new Header(data), { path: normPath(f).replace(/^(\/|[a-z]:\/)/i, ''), @@ -900,7 +1118,9 @@ t.test('warnings', t => { strict: strict, preservePaths: true, onwarn: (c, m, p) => warnings.push([c, m, p]), - }).end(f).on('data', c => out.push(c)) + }) + .end(f) + .on('data', c => out.push(c)) p.on('end', _ => { const data = Buffer.concat(out) t.equal(warnings.length, 0) @@ -918,13 +1138,15 @@ t.test('warnings', t => { new Pack({ strict: true, cwd: files, - }).end(f).on('error', e => { - t.match(e, { - message: /stripping .* from absolute path/, - path: normPath(f), - }) - t.end() }) + .end(f) + .on('error', e => { + t.match(e, { + message: /stripping .* from absolute path/, + path: normPath(f), + }) + t.end() + }) }) t.end() @@ -963,7 +1185,7 @@ t.test('no dir recurse', t => { }) t.test('sync', t => { - const p = new Pack.Sync({ + const p = new PackSync({ cwd: dir, noDirRecurse: true, }) @@ -975,48 +1197,57 @@ t.test('no dir recurse', t => { t.end() }) -t.test('follow', { skip: isWindows && 'file symlinks not available' }, t => { - const check = (out, t) => { - const data = Buffer.concat(out) - t.equal(data.length, 2048) - t.match(new Header(data, 0), { - type: 'File', - cksumValid: true, - needPax: false, - path: 'symlink', - mode: isWindows ? 0o666 : 0o644, - size: 26, - }) - t.match(data.slice(512).toString(), /this link is like diamond\n\0+$/) - t.end() - } +t.test( + 'follow', + { skip: isWindows && 'file symlinks not available' }, + t => { + const check = (out, t) => { + const data = Buffer.concat(out) + t.equal(data.length, 2048) + t.match(new Header(data, 0), { + type: 'File', + cksumValid: true, + needPax: false, + path: 'symlink', + mode: isWindows ? 0o666 : 0o644, + size: 26, + }) + t.match( + data.subarray(512).toString(), + /this link is like diamond\n\0+$/, + ) + t.end() + } - t.test('async', t => { - const out = [] - const p = new Pack({ cwd: files, follow: true }) - p.on('data', c => out.push(c)) - p.on('end', _ => check(out, t)) - p.end('symlink') - }) + t.test('async', t => { + const out = [] + const p = new Pack({ cwd: files, follow: true }) + p.on('data', c => out.push(c)) + p.on('end', _ => check(out, t)) + p.end('symlink') + }) - t.test('sync', t => { - const out = [] - const p = new Pack.Sync({ cwd: files, follow: true }) - p.on('data', c => out.push(c)) - p.end('symlink') - check(out, t) - }) + t.test('sync', t => { + const out = [] + const p = new PackSync({ cwd: files, follow: true }) + p.on('data', c => out.push(c)) + p.end('symlink') + check(out, t) + }) - t.end() -}) + t.end() + }, +) t.test('pack ReadEntries', t => { t.test('basic', t => { - const readEntry = new ReadEntry(new Header({ - path: 'x', - type: 'File', - size: 1, - })) + const readEntry = new ReadEntry( + new Header({ + path: 'x', + type: 'File', + size: 1, + }), + ) const p = new Pack() p.end(readEntry) const out = [] @@ -1024,9 +1255,9 @@ t.test('pack ReadEntries', t => { p.on('end', _ => { const data = Buffer.concat(out) t.equal(data.length, 2048) - t.match(data.slice(1024).toString(), /^\0+$/) - t.equal(data.slice(0, 100).toString().replace(/\0.*$/, ''), 'x') - t.equal(data.slice(512, 514).toString(), 'x\0') + t.match(data.subarray(1024).toString(), /^\0+$/) + t.equal(data.subarray(0, 100).toString().replace(/\0.*$/, ''), 'x') + t.equal(data.subarray(512, 514).toString(), 'x\0') t.end() }) const buf = Buffer.alloc(512) @@ -1035,11 +1266,13 @@ t.test('pack ReadEntries', t => { }) t.test('prefix', t => { - const readEntry = new ReadEntry(new Header({ - path: 'x', - type: 'File', - size: 1, - })) + const readEntry = new ReadEntry( + new Header({ + path: 'x', + type: 'File', + size: 1, + }), + ) const p = new Pack({ prefix: 'y' }) p.end(readEntry) const out = [] @@ -1047,9 +1280,12 @@ t.test('pack ReadEntries', t => { p.on('end', _ => { const data = Buffer.concat(out) t.equal(data.length, 2048) - t.match(data.slice(1024).toString(), /^\0+$/) - t.equal(data.slice(0, 100).toString().replace(/\0.*$/, ''), 'y/x') - t.equal(data.slice(512, 514).toString(), 'x\0') + t.match(data.subarray(1024).toString(), /^\0+$/) + t.equal( + data.subarray(0, 100).toString().replace(/\0.*$/, ''), + 'y/x', + ) + t.equal(data.subarray(512, 514).toString(), 'x\0') t.end() }) const buf = Buffer.alloc(512) @@ -1058,21 +1294,27 @@ t.test('pack ReadEntries', t => { }) t.test('filter out', t => { - const re1 = new ReadEntry(new Header({ - path: 'a', - type: 'File', - size: 1, - })) - const re2 = new ReadEntry(new Header({ - path: 'x', - type: 'File', - size: 1, - })) - const re3 = new ReadEntry(new Header({ - path: 'y', - type: 'File', - size: 1, - })) + const re1 = new ReadEntry( + new Header({ + path: 'a', + type: 'File', + size: 1, + }), + ) + const re2 = new ReadEntry( + new Header({ + path: 'x', + type: 'File', + size: 1, + }), + ) + const re3 = new ReadEntry( + new Header({ + path: 'y', + type: 'File', + size: 1, + }), + ) const p = new Pack({ filter: p => p === 'x' }) p.add(re1) p.add(re2) @@ -1082,9 +1324,9 @@ t.test('pack ReadEntries', t => { p.on('end', _ => { const data = Buffer.concat(out) t.equal(data.length, 2048) - t.match(data.slice(1024).toString(), /^\0+$/) - t.equal(data.slice(0, 100).toString().replace(/\0.*$/, ''), 'x') - t.equal(data.slice(512, 514).toString(), 'x\0') + t.match(data.subarray(1024).toString(), /^\0+$/) + t.equal(data.subarray(0, 100).toString().replace(/\0.*$/, ''), 'x') + t.equal(data.subarray(512, 514).toString(), 'x\0') t.end() }) { @@ -1119,7 +1361,7 @@ t.test('filter out everything', t => { t.test('sync', t => { const out = [] - const p = new Pack.Sync({ cwd: files, filter: filter }) + const p = new PackSync({ cwd: files, filter: filter }) p.on('data', c => out.push(c)) p.end('./') check(out, t) @@ -1127,7 +1369,7 @@ t.test('filter out everything', t => { t.test('async', t => { const out = [] - const p = new Pack.Sync({ cwd: files, filter: filter }) + const p = new PackSync({ cwd: files, filter: filter }) p.on('data', c => out.push(c)) p.on('end', _ => check(out, t)) p.end('./') @@ -1149,41 +1391,53 @@ t.test('fs.open fails', t => { t.test('sync', t => { t.plan(1) - t.throws(_ => - new Pack.Sync({ cwd: files }).end('one-byte.txt'), poop) + t.throws( + _ => new PackSync({ cwd: files }).end('one-byte.txt'), + poop, + ) }) t.end() }) -const write = opts => new Promise((resolve, reject) => { - const p = new Pack() - let totalSize = 0 - p.on('data', d => totalSize += d.length) - p.once('error', reject) - p.once('end', () => resolve(totalSize)) - - const file1 = new ReadEntry(new Header({ - path: 'file1.txt', - size: 5, - })) - if (opts.before) { - file1.end('file1') - p.add(file1) - } else { - p.add(file1) - file1.end('file1') - } +const write = opts => + new Promise((resolve, reject) => { + const p = new Pack() + let totalSize = 0 + p.on('data', d => (totalSize += d.length)) + p.once('error', reject) + p.once('end', () => resolve(totalSize)) + + const file1 = new ReadEntry( + new Header({ + path: 'file1.txt', + size: 5, + type: 'File', + }), + ) + if (opts.before) { + file1.end('file1') + p.add(file1) + } else { + p.add(file1) + file1.end('file1') + } - p.end() -}) + p.end() + }) t.test('padding works regardless of arite/add order', t => Promise.all([ write({ before: true }), write({ before: false }), ]).then(res => - t.equal(res[0], res[1], 'length is the same regardless of write/add order'))) + t.equal( + res[0], + res[1], + 'length is the same regardless of write/add order', + ), + ), +) t.test('prefix and subdirs', t => { const dir = path.resolve(fixtures, 'pack-prefix-subdirs') @@ -1214,7 +1468,8 @@ t.test('prefix and subdirs', t => { const check = (out, t) => { const data = Buffer.concat(out) expect.forEach((e, i) => - t.equal(e, data.slice(i * 512, i * 512 + e.length).toString())) + t.equal(e, data.subarray(i * 512, i * 512 + e.length).toString()), + ) t.end() } @@ -1235,8 +1490,8 @@ t.test('prefix and subdirs', t => { }) return t.test('sync', t => { - t.test('.', t => runTest(t, '.', Pack.Sync)) - return t.test('./', t => runTest(t, './', Pack.Sync)) + t.test('.', t => runTest(t, '.', PackSync)) + return t.test('./', t => runTest(t, './', PackSync)) }) }) @@ -1291,9 +1546,9 @@ t.test('prefix and hard links', t => { const data = Buffer.concat(out) expect.forEach((e, i) => { if (typeof e === 'string') { - t.equal(data.slice(i * 512, i * 512 + e.length).toString(), e) + t.equal(data.subarray(i * 512, i * 512 + e.length).toString(), e) } else { - t.match(new Header(data.slice(i * 512, (i + 1) * 512)), e) + t.match(new Header(data.subarray(i * 512, (i + 1) * 512)), e) } }) t.end() @@ -1330,8 +1585,8 @@ t.test('prefix and hard links', t => { }) t.test('sync', t => { - t.test('.', t => runTest(t, '.', Pack.Sync)) - return t.test('./', t => runTest(t, './', Pack.Sync)) + t.test('.', t => runTest(t, '.', PackSync)) + return t.test('./', t => runTest(t, './', PackSync)) }) t.end() diff --git a/test/parse.js b/test/parse.js index 2cc68782..ebee05e6 100644 --- a/test/parse.js +++ b/test/parse.js @@ -1,24 +1,30 @@ -'use strict' -const t = require('tap') -const Parse = require('../lib/parse.js') - -const makeTar = require('./make-tar.js') -const fs = require('fs') -const path = require('path') +import t from 'tap' +import { Parser } from '../dist/esm/parse.js' +import { makeTar } from './fixtures/make-tar.js' +import fs, { readFileSync } from 'fs' +import path, { dirname } from 'path' +import zlib from 'zlib' +import { Minipass } from 'minipass' +import { Header } from '../dist/esm/header.js' +import EE from 'events' +import { fileURLToPath } from 'url' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) const tardir = path.resolve(__dirname, 'fixtures/tars') -const zlib = require('zlib') -const { Minipass } = require('minipass') -const Header = require('../lib/header.js') -const EE = require('events').EventEmitter t.test('fixture tests', t => { class ByteStream extends Minipass { - write (chunk) { + write(chunk) { for (let i = 0; i < chunk.length - 1; i++) { - super.write(chunk.slice(i, i + 1)) + super.write(chunk.subarray(i, i + 1)) } - return super.write(chunk.slice(chunk.length - 1, chunk.length)) + const ret = super.write(chunk.subarray(chunk.length - 1, chunk.length)) + if (ret === false) { + throw new Error('BS write return false') + } + return ret } } @@ -26,21 +32,28 @@ t.test('fixture tests', t => { let ok = true let cursor = 0 p.on('entry', entry => { - ok = ok && t.match(['entry', entry], expect[cursor++], entry.path) + ok = + ok && t.match(['entry', entry], expect[cursor++], entry.path) if (slow) { - setTimeout(_ => entry.resume()) + setTimeout(() => entry.resume()) } else { entry.resume() } }) p.on('ignoredEntry', entry => { - ok = ok && t.match(['ignoredEntry', entry], expect[cursor++], - 'ignored: ' + entry.path) + ok = + ok && + t.match( + ['ignoredEntry', entry], + expect[cursor++], + 'ignored: ' + entry.path, + ) }) - p.on('warn', (c, message, data) => { - ok = ok && t.match(['warn', c, message], expect[cursor++], 'warn') + p.on('warn', (c, message, _data) => { + ok = + ok && t.match(['warn', c, message], expect[cursor++], 'warn') }) - p.on('nullBlock', _ => { + p.on('nullBlock', () => { ok = ok && t.match(['nullBlock'], expect[cursor++], 'null') }) p.on('error', er => { @@ -49,204 +62,261 @@ t.test('fixture tests', t => { p.on('meta', meta => { ok = ok && t.match(['meta', meta], expect[cursor++], 'meta') }) - p.on('eof', _ => { + p.on('eof', () => { ok = ok && t.match(['eof'], expect[cursor++], 'eof') }) - p.on('end', _ => { + p.on('end', () => { ok = ok && t.match(['end'], expect[cursor++], 'end') t.end() }) } t.jobs = 4 - const path = require('path') const parsedir = path.resolve(__dirname, 'fixtures/parse') const files = fs.readdirSync(tardir) - const maxMetaOpt = [250, null] + const maxMetaOpt = [250, undefined] const filterOpt = [true, false] const strictOpt = [true, false] const runTest = (file, maxMeta, filter, strict) => { const tardata = fs.readFileSync(file) const base = path.basename(file, '.tar') - t.test('file=' + base + '.tar' + - ' maxmeta=' + maxMeta + - ' filter=' + filter + - ' strict=' + strict, t => { - const o = - (maxMeta ? '-meta-' + maxMeta : '') + - (filter ? '-filter' : '') + - (strict ? '-strict' : '') - const tail = (o ? '-' + o : '') + '.json' - const eventsFile = parsedir + '/' + base + tail - const expect = require(eventsFile) - - t.test('uncompressed one byte at a time', t => { - const bs = new ByteStream() - const opt = (maxMeta || filter || strict) ? { - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, - } : null - const bp = new Parse(opt) - trackEvents(t, expect, bp) - bs.pipe(bp) - bs.end(tardata) - }) - - t.test('uncompressed all at once', t => { - const p = new Parse({ - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, + t.test( + 'file=' + + base + + '.tar' + + ' maxmeta=' + + maxMeta + + ' filter=' + + filter + + ' strict=' + + strict, + t => { + const o = + (maxMeta ? '-meta-' + maxMeta : '') + + (filter ? '-filter' : '') + + (strict ? '-strict' : '') + const tail = (o ? '-' + o : '') + '.json' + const eventsFile = parsedir + '/' + base + tail + const expect = JSON.parse(readFileSync(eventsFile, 'utf8')) + + t.test('uncompressed one byte at a time', t => { + const bs = new ByteStream() + bs.on('data', c => { + if (!Buffer.isBuffer(c)) throw new Error('wat1') + if (c.length !== 1) throw new Error('wat2') + }) + const opt = + maxMeta || filter || strict + ? { + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + } + : undefined + const p = new Parser(opt) + trackEvents(t, expect, p) + bs.pipe(p) + bs.write(tardata) + bs.end() }) - trackEvents(t, expect, p) - p.end(tardata) - }) - - t.test('uncompressed one byte at a time, filename .tbr', t => { - const bs = new ByteStream() - const opt = (maxMeta || filter || strict) ? { - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, - file: 'example.tbr', - } : null - const bp = new Parse(opt) - trackEvents(t, expect, bp) - bs.pipe(bp) - bs.end(tardata) - }) - - t.test('uncompressed all at once, filename .tar.br', t => { - const p = new Parse({ - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, - file: 'example.tar.br', + + t.test('uncompressed all at once', t => { + const p = new Parser({ + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + }) + trackEvents(t, expect, p) + p.end(tardata) }) - trackEvents(t, expect, p) - p.end(tardata) - }) - - t.test('gzipped all at once', t => { - const p = new Parse({ - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, + + t.test( + 'uncompressed one byte at a time, filename .tbr', + t => { + const bs = new ByteStream() + const opt = + maxMeta || filter || strict + ? { + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + file: 'example.tbr', + } + : undefined + const bp = new Parser(opt) + trackEvents(t, expect, bp) + bs.pipe(bp) + bs.end(tardata) + }, + ) + + t.test('uncompressed all at once, filename .tar.br', t => { + const p = new Parser({ + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + file: 'example.tar.br', + }) + trackEvents(t, expect, p) + p.end(tardata) }) - trackEvents(t, expect, p) - p.end(zlib.gzipSync(tardata)) - }) - - t.test('gzipped all at once, filename .tbr', t => { - const p = new Parse({ - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, - file: 'example.tbr', + + t.test('gzipped all at once', t => { + const p = new Parser({ + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + }) + trackEvents(t, expect, p) + p.end(zlib.gzipSync(tardata)) }) - trackEvents(t, expect, p) - p.end(zlib.gzipSync(tardata)) - }) - - t.test('gzipped byte at a time', t => { - const bs = new ByteStream() - const bp = new Parse({ - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, + + t.test('gzipped all at once, filename .tbr', t => { + const p = new Parser({ + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + file: 'example.tbr', + }) + trackEvents(t, expect, p) + p.end(zlib.gzipSync(tardata)) }) - trackEvents(t, expect, bp) - bs.pipe(bp) - bs.end(zlib.gzipSync(tardata)) - }) - - t.test('compress with brotli based on filename .tar.br', t => { - const p = new Parse({ - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, - file: 'example.tar.br', + + t.test('gzipped byte at a time', t => { + const bs = new ByteStream() + const bp = new Parser({ + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + }) + trackEvents(t, expect, bp) + bs.pipe(bp) + bs.end(zlib.gzipSync(tardata)) }) - trackEvents(t, expect, p) - p.end(zlib.brotliCompressSync(tardata)) - }) - - t.test('compress with brotli based on filename .tbr', t => { - const p = new Parse({ - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, - file: 'example.tbr', + + t.test( + 'compress with brotli based on filename .tar.br', + t => { + const p = new Parser({ + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + file: 'example.tar.br', + }) + trackEvents(t, expect, p) + p.end(zlib.brotliCompressSync(tardata)) + }, + ) + + t.test('compress with brotli based on filename .tbr', t => { + const p = new Parser({ + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + file: 'example.tbr', + }) + trackEvents(t, expect, p) + p.end(zlib.brotliCompressSync(tardata)) }) - trackEvents(t, expect, p) - p.end(zlib.brotliCompressSync(tardata)) - }) - - t.test('compress with brotli all at once', t => { - const p = new Parse({ - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, - brotli: {}, + + t.test('compress with brotli all at once', t => { + const p = new Parser({ + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + brotli: {}, + }) + trackEvents(t, expect, p) + p.end(zlib.brotliCompressSync(tardata)) }) - trackEvents(t, expect, p) - p.end(zlib.brotliCompressSync(tardata)) - }) - - t.test('compress with brotli byte at a time', t => { - const bs = new ByteStream() - const bp = new Parse({ - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, - brotli: {}, + + t.test('compress with brotli byte at a time', t => { + const bs = new ByteStream() + const bp = new Parser({ + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + brotli: {}, + }) + trackEvents(t, expect, bp) + bs.pipe(bp) + bs.end(zlib.brotliCompressSync(tardata)) }) - trackEvents(t, expect, bp) - bs.pipe(bp) - bs.end(zlib.brotliCompressSync(tardata)) - }) - - t.test('compress with brotli .tbr byte at a time', t => { - const bs = new ByteStream() - const bp = new Parse({ - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, - file: 'example.tbr', + + t.test('compress with brotli .tbr byte at a time', t => { + const bs = new ByteStream() + const bp = new Parser({ + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + file: 'example.tbr', + }) + trackEvents(t, expect, bp) + bs.pipe(bp) + bs.end(zlib.brotliCompressSync(tardata)) }) - trackEvents(t, expect, bp) - bs.pipe(bp) - bs.end(zlib.brotliCompressSync(tardata)) - }) - - t.test('async chunks', t => { - const p = new Parse({ - maxMetaEntrySize: maxMeta, - filter: filter ? (path, entry) => entry.size % 2 !== 0 : null, - strict: strict, + + t.test('async chunks', t => { + const p = new Parser({ + maxMetaEntrySize: maxMeta, + filter: filter + ? (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + }) + trackEvents(t, expect, p, true) + p.write(tardata.subarray(0, Math.floor(tardata.length / 2))) + process.nextTick(() => + p.end(tardata.subarray(Math.floor(tardata.length / 2))), + ) }) - trackEvents(t, expect, p, true) - p.write(tardata.slice(0, Math.floor(tardata.length / 2))) - process.nextTick(_ => p.end(tardata.slice(Math.floor(tardata.length / 2)))) - }) - t.end() - }) + t.end() + }, + ) } files - .map(f => path.resolve(tardir, f)).forEach(file => + .map(f => path.resolve(tardir, f)) + .forEach(file => maxMetaOpt.forEach(maxMeta => strictOpt.forEach(strict => filterOpt.forEach(filter => - runTest(file, maxMeta, filter, strict))))) + runTest(file, maxMeta, filter, strict), + ), + ), + ), + ) t.end() }) t.test('strict warn with an error emits that error', t => { t.plan(1) - const p = new Parse({ + const p = new Parser({ strict: true, }) p.on('error', emitted => t.equal(emitted, er)) @@ -256,8 +326,8 @@ t.test('strict warn with an error emits that error', t => { t.test('onwarn gets added to the warn event', t => { t.plan(1) - const p = new Parse({ - onwarn (code, message) { + const p = new Parser({ + onwarn(_code, message) { t.equal(message, 'this is fine') }, }) @@ -266,7 +336,7 @@ t.test('onwarn gets added to the warn event', t => { t.test('onentry gets added to entry event', t => { t.plan(1) - const p = new Parse({ + const p = new Parser({ onentry: entry => t.equal(entry, 'yes hello this is dog'), }) p.emit('entry', 'yes hello this is dog') @@ -400,36 +470,56 @@ t.test('drain event timings', t => { ].map(chunks => makeTar(chunks)) const expect = [ - 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', 'eight', - 'four', 'five', 'six', 'seven', 'eight', + 'one', + 'two', + 'three', + 'four', + 'five', + 'six', + 'seven', + 'eight', + 'four', + 'five', + 'six', + 'seven', + 'eight', 'nine', - 'one', 'two', 'three', - 'four', 'five', 'six', 'seven', 'eight', - 'four', 'five', 'six', 'seven', 'eight', + 'one', + 'two', + 'three', + 'four', + 'five', + 'six', + 'seven', + 'eight', + 'four', + 'five', + 'six', + 'seven', + 'eight', 'nine', ] class SlowStream extends EE { - write () { - setTimeout(_ => this.emit('drain')) + write() { + setTimeout(() => this.emit('drain')) return false } - end () { + end() { return this.write() } } let currentEntry const autoPipe = true - const p = new Parse({ + const p = new Parser({ ondone, onentry: entry => { t.equal(entry.path, expect.shift()) currentEntry = entry if (autoPipe) { - setTimeout(_ => entry.pipe(new SlowStream())) + setTimeout(() => entry.pipe(new SlowStream())) } }, }) @@ -441,7 +531,7 @@ t.test('drain event timings', t => { }) let interval - const go = _ => { + const go = () => { const d = data.shift() if (d === undefined) { return p.end() @@ -454,19 +544,21 @@ t.test('drain event timings', t => { } const hunklen = Math.floor(d.length / 2) - const hunks = [ - d.slice(0, hunklen), - d.slice(hunklen), - ] + const hunks = [d.subarray(0, hunklen), d.subarray(hunklen)] p.write(hunks[0]) if (currentEntry && !paused) { - console.error('has current entry') currentEntry.pause() paused = true } - if (!t.equal(p.write(hunks[1]), false, 'write should return false: ' + d)) { + if ( + !t.equal( + p.write(hunks[1]), + false, + 'write should return false: ' + d, + ) + ) { return t.end() } @@ -478,7 +570,7 @@ t.test('drain event timings', t => { } p.once('drain', go) - p.on('end', _ => { + p.on('end', () => { clearInterval(interval) t.ok(sawOndone) t.end() @@ -542,18 +634,18 @@ t.test('consume while consuming', t => { ]) const runTest = (t, size) => { - const p = new Parse() - const first = data.slice(0, size) - const rest = data.slice(size) - p.once('entry', entry => { + const p = new Parser() + const first = data.subarray(0, size) + const rest = data.subarray(size) + p.once('entry', _entry => { for (let pos = 0; pos < rest.length; pos += size) { - p.write(rest.slice(pos, pos + size)) + p.write(rest.subarray(pos, pos + size)) } p.end() }) .on('entry', entry => entry.resume()) - .on('end', _ => t.end()) + .on('end', () => t.end()) .write(first) } @@ -579,7 +671,9 @@ t.test('truncated input', t => { t.test('truncated at block boundary', t => { const warnings = [] - const p = new Parse({ onwarn: (c, message) => warnings.push(message) }) + const p = new Parser({ + onwarn: (_c, message) => warnings.push(message), + }) p.end(data) t.same(warnings, [ 'Truncated input (needed 512 more bytes, only 0 available)', @@ -589,7 +683,9 @@ t.test('truncated input', t => { t.test('truncated mid-block', t => { const warnings = [] - const p = new Parse({ onwarn: (c, message) => warnings.push(message) }) + const p = new Parser({ + onwarn: (_c, message) => warnings.push(message), + }) p.write(data) p.end(Buffer.from('not a full block')) t.same(warnings, [ @@ -617,33 +713,37 @@ t.test('truncated gzip input', t => { '', ]) const tgz = zlib.gzipSync(raw) - const split = Math.floor(tgz.length * 2 / 3) - const trunc = tgz.slice(0, split) + const split = Math.floor((tgz.length * 2) / 3) + const trunc = tgz.subarray(0, split) const skipEarlyEnd = process.version.match(/^v4\./) - t.test('early end', { - skip: skipEarlyEnd ? 'not a zlib error on v4' : false, - }, t => { - const warnings = [] - const p = new Parse() - p.on('error', er => warnings.push(er.message)) - let aborted = false - p.on('abort', _ => aborted = true) - p.end(trunc) - t.equal(aborted, true, 'aborted writing') - t.same(warnings, ['zlib: unexpected end of file']) - t.end() - }) + t.test( + 'early end', + { + skip: skipEarlyEnd ? 'not a zlib error on v4' : false, + }, + t => { + const warnings = [] + const p = new Parser() + p.on('error', er => warnings.push(er.message)) + let aborted = false + p.on('abort', () => (aborted = true)) + p.end(trunc) + t.equal(aborted, true, 'aborted writing') + t.same(warnings, ['zlib: unexpected end of file']) + t.end() + }, + ) t.test('just wrong', t => { const warnings = [] - const p = new Parse() + const p = new Parser() p.on('error', er => warnings.push(er.message)) let aborted = false - p.on('abort', _ => aborted = true) + p.on('abort', () => (aborted = true)) p.write(trunc) p.write(trunc) - p.write(tgz.slice(split)) + p.write(tgz.subarray(split)) p.end() t.equal(aborted, true, 'aborted writing') t.match(warnings, [/^zlib: /]) @@ -655,40 +755,42 @@ t.test('truncated gzip input', t => { t.test('end while consuming', t => { // https://github.com/npm/node-tar/issues/157 - const data = zlib.gzipSync(makeTar([ - { - path: 'package/package.json', - type: 'File', - size: 130, - }, - new Array(131).join('x'), - { - path: 'package/node_modules/@c/d/node_modules/e/package.json', - type: 'File', - size: 30, - }, - new Array(31).join('e'), - { - path: 'package/node_modules/@c/d/package.json', - type: 'File', - size: 33, - }, - new Array(34).join('d'), - { - path: 'package/node_modules/a/package.json', - type: 'File', - size: 59, - }, - new Array(60).join('a'), - { - path: 'package/node_modules/b/package.json', - type: 'File', - size: 30, - }, - new Array(31).join('b'), - '', - '', - ])) + const data = zlib.gzipSync( + makeTar([ + { + path: 'package/package.json', + type: 'File', + size: 130, + }, + new Array(131).join('x'), + { + path: 'package/node_modules/@c/d/node_modules/e/package.json', + type: 'File', + size: 30, + }, + new Array(31).join('e'), + { + path: 'package/node_modules/@c/d/package.json', + type: 'File', + size: 33, + }, + new Array(34).join('d'), + { + path: 'package/node_modules/a/package.json', + type: 'File', + size: 59, + }, + new Array(60).join('a'), + { + path: 'package/node_modules/b/package.json', + type: 'File', + size: 30, + }, + new Array(31).join('b'), + '', + '', + ]), + ) const actual = [] const expect = [ @@ -700,7 +802,7 @@ t.test('end while consuming', t => { ] const mp = new Minipass() - const p = new Parse({ + const p = new Parser({ onentry: entry => { actual.push(entry.path) entry.resume() @@ -716,7 +818,7 @@ t.test('end while consuming', t => { }) t.test('bad archives', t => { - const p = new Parse() + const p = new Parser() const warnings = [] p.on('warn', (code, msg, data) => { warnings.push([code, msg, data]) @@ -735,8 +837,8 @@ t.test('bad archives', t => { }) t.test('header that throws', t => { - const p = new Parse() - p.on('warn', (c, m, d) => { + const p = new Parser() + p.on('warn', (_c, m, d) => { t.equal(m, 'invalid base256 encoding') t.match(d, { code: 'TAR_ENTRY_INVALID', @@ -753,14 +855,19 @@ t.test('header that throws', t => { }) h.encode() const buf = h.block - const bad = Buffer.from([0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]) + const bad = Buffer.from([ + 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + ]) bad.copy(buf, 100) - t.throws(() => new Header(buf), 'the header with that buffer throws') + t.throws( + () => new Header(buf), + 'the header with that buffer throws', + ) p.write(buf) }) t.test('warnings that are not so bad', t => { - const p = new Parse() + const p = new Parser() const warnings = [] p.on('warn', (code, m, d) => { warnings.push([code, m, d]) @@ -768,7 +875,7 @@ t.test('warnings that are not so bad', t => { }) // the parser doesn't actually decide what's "ok" or "supported", // it just parses. So we have to set it ourselves like unpack does - p.once('entry', entry => entry.invalid = true) + p.once('entry', entry => (entry.invalid = true)) p.on('entry', entry => entry.resume()) const data = makeTar([ { diff --git a/test/path-reservations.js b/test/path-reservations.js index 9a1d7a77..6d9f7452 100644 --- a/test/path-reservations.js +++ b/test/path-reservations.js @@ -1,19 +1,25 @@ -const t = require('tap') +import t from 'tap' + +import { posix, win32 } from 'node:path' // load up the posix and windows versions of the reserver if (process.platform === 'win32') { process.env.TESTING_TAR_FAKE_PLATFORM = 'posix' } -const { reserve } = t.mock('../lib/path-reservations.js', { - path: require('path').posix, -})() + + +const { PathReservations } = await t.mockImport('../dist/esm/path-reservations.js', { + path: posix, +}) + delete process.env.TESTING_TAR_FAKE_PLATFORM if (process.platform !== 'win32') { process.env.TESTING_TAR_FAKE_PLATFORM = 'win32' } -const { reserve: winReserve } = t.mock('../lib/path-reservations.js', { - path: require('path').win32, -})() + +const { PathReservations: WinPathReservations } = await t.mockImport('../dist/esm/path-reservations.js', { + path: win32, +}) t.test('basic race', t => { // simulate the race conditions we care about @@ -62,11 +68,13 @@ t.test('basic race', t => { t.end() } - t.ok(reserve(['a/b/c/d'], file), 'file starts right away') - t.notOk(reserve(['a/B/c////D', 'a/b/e'], link), 'link waits') - t.notOk(reserve(['a/b/e/f'], dir), 'dir waits') - t.notOk(reserve(['a/b'], dir2), 'dir2 waits') - t.notOk(reserve(['a/b/x'], dir3), 'dir3 waits') + const r = new PathReservations() + + t.ok(r.reserve(['a/b/c/d'], file), 'file starts right away') + t.notOk(r.reserve(['a/B/c////D', 'a/b/e'], link), 'link waits') + t.notOk(r.reserve(['a/b/e/f'], dir), 'dir waits') + t.notOk(r.reserve(['a/b'], dir2), 'dir2 waits') + t.notOk(r.reserve(['a/b/x'], dir3), 'dir3 waits') }) t.test('unicode shenanigans', t => { @@ -89,8 +97,9 @@ t.test('unicode shenanigans', t => { } const cafePath1 = `c/a/f/${e1}` const cafePath2 = `c/a/f/${e2}` - t.ok(reserve([cafePath1], cafe1)) - t.notOk(reserve([cafePath2], cafe2)) + const r = new PathReservations() + t.ok(r.reserve([cafePath1], cafe1)) + t.notOk(r.reserve([cafePath2], cafe2)) }) t.test('absolute paths and trailing slash', t => { @@ -128,14 +137,15 @@ t.test('absolute paths and trailing slash', t => { t.end() } } - t.ok(reserve(['/p/a/t/h'], a1)) - t.notOk(reserve(['/p/a/t/h/'], a2)) - t.ok(reserve(['p/a/t/h'], r1)) - t.notOk(reserve(['p/a/t/h/'], r2)) + const r = new PathReservations() + t.ok(r.reserve(['/p/a/t/h'], a1)) + t.notOk(r.reserve(['/p/a/t/h/'], a2)) + t.ok(r.reserve(['p/a/t/h'], r1)) + t.notOk(r.reserve(['p/a/t/h/'], r2)) }) t.test('on windows, everything collides with everything', t => { - const reserve = winReserve + const r = new WinPathReservations() let called1 = false let called2 = false const f1 = done => { @@ -151,6 +161,6 @@ t.test('on windows, everything collides with everything', t => { done() t.end() } - t.equal(reserve(['some/path'], f1), true) - t.equal(reserve(['other/path'], f2), false) + t.equal(r.reserve(['some/path'], f1), true) + t.equal(r.reserve(['other/path'], f2), false) }) diff --git a/test/pax.js b/test/pax.js index cef9fc51..eb7f9260 100644 --- a/test/pax.js +++ b/test/pax.js @@ -1,6 +1,5 @@ -'use strict' -const t = require('tap') -const Pax = require('../lib/pax.js') +import t from 'tap' +import { Pax } from '../dist/esm/pax.js' t.test('create a pax', t => { const p = new Pax({ @@ -18,8 +17,6 @@ t.test('create a pax', t => { nlink: 1, }) - // console.log(p.encode().toString('hex').split('').reduce((s,c)=>{if(s[s.length-1].length<64)s[s.length-1]+=c;else s.push(c);return s},[''])) - const buf = Buffer.from( // pax entry header '5061784865616465722f666f6f2e747874000000000000000000000000000000' + @@ -59,13 +56,13 @@ t.test('create a pax', t => { 'hex') const actual = p.encode() - t.equal(actual.toString('hex'), buf.toString('hex')) + t.match(actual, buf) t.end() }) t.test('null pax', t => { const p = new Pax({}) - t.equal(p.encode(), null) + t.same(p.encode(), Buffer.allocUnsafe(0)) t.end() }) @@ -74,8 +71,6 @@ t.test('tiny pax', t => { // an error? const p = new Pax({ path: 'ab' }, true) const actual = p.encode() - // console.log(actual.toString('hex').split('').reduce((s,c)=>{if(s[s.length-1].length<64)s[s.length-1]+=c;else s.push(c);return s},[''])) - // return Promise.resolve() const buf = Buffer.from( // header @@ -120,104 +115,112 @@ t.test('tiny pax', t => { '0000000000000000000000000000000000000000000000000000000000000000', 'hex') - t.equal(actual.toString('hex'), buf.toString('hex')) + t.same(actual, buf) t.end() }) t.test('parse', t => { - t.same(Pax.parse('11 path=ab\n', { uid: 24561 }, true), { - atime: null, - charset: null, - comment: null, - ctime: null, - gid: null, - gname: null, - linkpath: null, - mtime: null, + const p = Pax.parse('11 path=ab\n', { uid: 24561 }, true) + t.same(p, Object.assign(Object.create(Pax.prototype), { + atime: undefined, + mode: undefined, + charset: undefined, + comment: undefined, + ctime: undefined, + gid: undefined, + gname: undefined, + linkpath: undefined, + mtime: undefined, path: 'ab', - size: null, + size: undefined, uid: 24561, - uname: null, - dev: null, - ino: null, - nlink: null, + uname: undefined, + dev: undefined, + ino: undefined, + nlink: undefined, global: true, - }) + })) - t.same(Pax.parse('11 path=ab\n', null, false), { - atime: null, - charset: null, - comment: null, - ctime: null, - gid: null, - gname: null, - linkpath: null, - mtime: null, + t.same(Pax.parse('11 path=ab\n'), Object.assign(Object.create(Pax.prototype), { + atime: undefined, + mtime: undefined, + ctime: undefined, + charset: undefined, + comment: undefined, + gid: undefined, + gname: undefined, + uname: undefined, + linkpath: undefined, path: 'ab', - size: null, - uid: null, - uname: null, - dev: null, - ino: null, - nlink: null, + size: undefined, + mode: undefined, + uid: undefined, + uname: undefined, + dev: undefined, + ino: undefined, + nlink: undefined, global: false, - }) + })) - t.same(Pax.parse('9 gid=20\n9 path=x\n', null, false), { - atime: null, - charset: null, - comment: null, - ctime: null, + t.same(Pax.parse('9 gid=20\n9 path=x\n'), { + atime: undefined, + mtime: undefined, + ctime: undefined, + charset: undefined, + comment: undefined, gid: 20, - gname: null, - linkpath: null, - mtime: null, + gname: undefined, + linkpath: undefined, + mtime: undefined, path: 'x', - size: null, - uid: null, - uname: null, - dev: null, - ino: null, - nlink: null, + size: undefined, + uid: undefined, + uname: undefined, + dev: undefined, + ino: undefined, + nlink: undefined, + mode: undefined, global: false, }) - t.same(Pax.parse('9 gid=20\n9 path=x\n', null, false), { - atime: null, - charset: null, - comment: null, - ctime: null, + t.same(Pax.parse('9 gid=20\n9 path=x\n'), { + atime: undefined, + charset: undefined, + comment: undefined, + ctime: undefined, gid: 20, - gname: null, - linkpath: null, - mtime: null, + gname: undefined, + linkpath: undefined, + mtime: undefined, path: 'x', - size: null, - uid: null, - uname: null, - dev: null, - ino: null, - nlink: null, + size: undefined, + uid: undefined, + uname: undefined, + dev: undefined, + ino: undefined, + mode: undefined, + nlink: undefined, global: false, }) - t.same(Pax.parse('20 mtime=1491436800\n', null, false), { - atime: null, - charset: null, - comment: null, - ctime: null, - gid: null, - gname: null, - linkpath: null, + t.same(Pax.parse('20 mtime=1491436800\n'), { + atime: undefined, + charset: undefined, + comment: undefined, + ctime: undefined, + gid: undefined, + gname: undefined, + linkpath: undefined, mtime: new Date('2017-04-06'), - path: null, - size: null, - uid: null, - uname: null, - dev: null, - ino: null, - nlink: null, + path: undefined, + size: undefined, + uid: undefined, + uname: undefined, + dev: undefined, + ino: undefined, + nlink: undefined, + mode: undefined, global: false, }) @@ -230,22 +233,23 @@ t.test('parse', t => { const noKey = '10 =pathx\n' - t.same(Pax.parse(breaky + '9 gid=20\n10 path=x\n' + noKey, null, false), { - atime: null, - charset: null, - comment: null, - ctime: null, + t.same(Pax.parse(breaky + '9 gid=20\n10 path=x\n' + noKey), { + atime: undefined, + charset: undefined, + comment: undefined, + ctime: undefined, gid: 20, - gname: null, - linkpath: null, - mtime: null, + gname: undefined, + linkpath: undefined, + mtime: undefined, path: 'x', - size: null, - uid: null, - uname: null, - dev: null, - ino: null, - nlink: null, + size: undefined, + uid: undefined, + uname: undefined, + dev: undefined, + ino: undefined, + nlink: undefined, + mode: undefined, global: false, }) diff --git a/test/read-entry.js b/test/read-entry.js index 4e12e87a..6d690390 100644 --- a/test/read-entry.js +++ b/test/read-entry.js @@ -1,7 +1,6 @@ -'use strict' -const t = require('tap') -const ReadEntry = require('../lib/read-entry.js') -const Header = require('../lib/header.js') +import t from 'tap' +import { ReadEntry } from '../dist/esm/read-entry.js' +import { Header } from '../dist/esm/header.js' t.test('create read entry', t => { const h = new Header({ @@ -19,7 +18,11 @@ t.test('create read entry', t => { }) h.encode() - const entry = new ReadEntry(h, { x: 'y', path: 'foo.txt' }, { z: 0, a: null, b: undefined }) + const entry = new ReadEntry( + h, + { x: 'y', path: 'foo.txt' }, + { z: 0, a: null, b: undefined }, + ) t.ok(entry.header.cksumValid, 'header checksum should be valid') @@ -67,8 +70,8 @@ t.test('create read entry', t => { let data = '' let ended = false - entry.on('data', c => data += c) - entry.on('end', _ => ended = true) + entry.on('data', c => (data += c)) + entry.on('end', _ => (ended = true)) const body = Buffer.alloc(512) body.write(new Array(101).join('z'), 0) @@ -81,6 +84,85 @@ t.test('create read entry', t => { t.end() }) +t.test('entry with extended linkpath', t => { + const h = new Header({ + path: 'oof.txt', + mode: 0o755, + uid: 24561, + gid: 20, + size: 0, + mtime: new Date('2016-04-01T22:00Z'), + ctime: new Date('2016-04-01T22:00Z'), + atime: new Date('2016-04-01T22:00Z'), + type: 'SymbolicLink', + uname: 'isaacs', + gname: 'staff', + }) + h.encode() + + const entry = new ReadEntry( + h, + { x: 'y', linkpath: 'bar.txt', path: 'foo.txt' }, + { z: 0, a: null, b: undefined }, + ) + + t.ok(entry.header.cksumValid, 'header checksum should be valid') + + t.match(entry, { + extended: { x: 'y', path: 'foo.txt', linkpath: 'bar.txt' }, + globalExtended: { z: 0, a: null, b: undefined }, + header: { + cksumValid: true, + needPax: false, + path: 'oof.txt', + mode: 0o755, + uid: 24561, + gid: 20, + size: 0, + mtime: new Date('2016-04-01T22:00:00.000Z'), + typeKey: '2', + type: 'SymbolicLink', + linkpath: null, + uname: 'isaacs', + gname: 'staff', + devmaj: 0, + devmin: 0, + atime: new Date('2016-04-01T22:00:00.000Z'), + ctime: new Date('2016-04-01T22:00:00.000Z'), + }, + blockRemain: 0, + remain: 0, + type: 'SymbolicLink', + meta: false, + ignore: false, + path: 'foo.txt', + mode: 0o755, + uid: 24561, + gid: 20, + uname: 'isaacs', + gname: 'staff', + size: 0, + mtime: new Date('2016-04-01T22:00:00.000Z'), + atime: new Date('2016-04-01T22:00:00.000Z'), + ctime: new Date('2016-04-01T22:00:00.000Z'), + linkpath: 'bar.txt', + x: 'y', + z: 0, + }) + + let data = '' + entry.on('data', c => (data += c)) + + const body = Buffer.alloc(512) + body.write(new Array(101).join('z'), 0) + t.throws(() => entry.write(body)) + entry.end() + + t.equal(data, '') + + t.end() +}) + t.test('meta entry', t => { const h = new Header({ path: 'PaxHeader/foo.txt', @@ -102,11 +184,11 @@ t.test('meta entry', t => { let actual = '' const entry = new ReadEntry(h) - entry.on('data', c => actual += c) + entry.on('data', c => (actual += c)) - entry.write(body.slice(0, 1)) - entry.write(body.slice(1, 25)) - entry.write(body.slice(25)) + entry.write(body.subarray(0, 1)) + entry.write(body.subarray(1, 25)) + entry.write(body.subarray(25)) t.throws(_ => entry.write(Buffer.alloc(1024))) t.equal(actual, expect) @@ -128,6 +210,8 @@ t.test('unknown entry type', t => { gname: 'staff', }) h.encode() + // this triggers its type to be Unsupported, which means that any + // data written to it will be thrown away. h.block.write('9', 156, 1, 'ascii') const body = Buffer.alloc(512) @@ -138,12 +222,12 @@ t.test('unknown entry type', t => { const entry = new ReadEntry(new Header(h.block)) - entry.on('data', c => actual += c) + entry.on('data', c => (actual += c)) - entry.write(body.slice(0, 1)) - entry.write(body.slice(1, 25)) - entry.write(body.slice(25)) - t.throws(_ => entry.write(Buffer.alloc(1024))) + entry.write(body.subarray(0, 1)) + entry.write(body.subarray(1, 25)) + entry.write(body.subarray(25)) + t.throws(() => entry.write(Buffer.alloc(1024))) t.equal(actual, expect) t.match(entry, { ignore: true }) @@ -209,8 +293,8 @@ t.test('entry without mode', t => { let data = '' let ended = false - entry.on('data', c => data += c) - entry.on('end', _ => ended = true) + entry.on('data', c => (data += c)) + entry.on('end', _ => (ended = true)) const body = Buffer.alloc(512) body.write(new Array(101).join('z'), 0) diff --git a/test/replace.js b/test/replace.js index 75c97027..22af74d7 100644 --- a/test/replace.js +++ b/test/replace.js @@ -1,25 +1,26 @@ -'use strict' -const t = require('tap') -const r = require('../lib/replace.js') -const path = require('path') -const fs = require('fs') -const mutateFS = require('mutate-fs') -const list = require('../lib/list.js') -const { resolve } = require('path') - +import t from 'tap' +import { replace as r } from '../dist/esm/replace.js' +import path, {dirname, resolve } from 'path' +import fs from 'fs' +import mutateFS from 'mutate-fs' +import { list } from '../dist/esm/list.js' +import {fileURLToPath} from 'url' +import zlib from 'zlib' +import { spawn } from 'child_process' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) const fixtures = path.resolve(__dirname, 'fixtures') const tars = path.resolve(fixtures, 'tars') -const zlib = require('zlib') -const spawn = require('child_process').spawn const data = fs.readFileSync(tars + '/body-byte-counts.tar') -const dataNoNulls = data.slice(0, data.length - 1024) +const dataNoNulls = data.subarray(0, data.length - 1024) const fixtureDef = { 'body-byte-counts.tar': data, 'no-null-eof.tar': dataNoNulls, - 'truncated-head.tar': Buffer.concat([dataNoNulls, data.slice(0, 500)]), - 'truncated-body.tar': Buffer.concat([dataNoNulls, data.slice(0, 700)]), + 'truncated-head.tar': Buffer.concat([dataNoNulls, data.subarray(0, 500)]), + 'truncated-body.tar': Buffer.concat([dataNoNulls, data.subarray(0, 700)]), 'zero.tar': Buffer.from(''), 'empty.tar': Buffer.alloc(512), 'compressed.tgz': zlib.gzipSync(data), @@ -318,7 +319,7 @@ t.test('mtime cache', async t => { path.basename(__filename), ]) const mtc = {} - mtimeCache.forEach((v, k) => mtc[k] = mtimeCache.get(k).toISOString()) + mtimeCache.forEach((_v, k) => mtc[k] = mtimeCache.get(k).toISOString()) t.same(mtc, { '1024-bytes.txt': '2017-04-10T16:57:47.000Z', '512-bytes.txt': '2017-04-10T17:08:55.000Z', diff --git a/test/strip-absolute-path.js b/test/strip-absolute-path.js index 3e871a9f..59529d6f 100644 --- a/test/strip-absolute-path.js +++ b/test/strip-absolute-path.js @@ -1,5 +1,7 @@ -const t = require('tap') -const stripAbsolutePath = require('../lib/strip-absolute-path.js') +import t from 'tap' +import { stripAbsolutePath } from '../dist/esm/strip-absolute-path.js' +import realPath from 'node:path' + const cwd = process.cwd() t.test('basic', t => { @@ -9,34 +11,46 @@ t.test('basic', t => { 'c:///a/b/c': ['c:///', 'a/b/c'], '\\\\foo\\bar\\baz': ['\\\\foo\\bar\\', 'baz'], '//foo//bar//baz': ['//', 'foo//bar//baz'], - 'c:\\c:\\c:\\c:\\\\d:\\e/f/g': ['c:\\c:\\c:\\c:\\\\d:\\', 'e/f/g'], + 'c:\\c:\\c:\\c:\\\\d:\\e/f/g': [ + 'c:\\c:\\c:\\c:\\\\d:\\', + 'e/f/g', + ], } for (const [input, [root, stripped]] of Object.entries(cases)) { - t.strictSame(stripAbsolutePath(input, cwd), [root, stripped], input) + t.strictSame( + stripAbsolutePath(input, cwd), + [root, stripped], + input, + ) } t.end() }) -t.test('drive-local paths', t => { +t.test('drive-local paths', async t => { const env = process.env - t.teardown(() => process.env = env) + t.teardown(() => (process.env = env)) const cwd = 'D:\\safety\\land' - const realPath = require('path') // be windowsy const path = { ...realPath.win32, win32: realPath.win32, posix: realPath.posix, } - const stripAbsolutePath = t.mock('../lib/strip-absolute-path.js', { path }) + const { stripAbsolutePath } = await t.mockImport( + '../dist/esm/strip-absolute-path.js', + { path }, + ) const cases = { '/': ['/', ''], '////': ['////', ''], 'c:///a/b/c': ['c:///', 'a/b/c'], '\\\\foo\\bar\\baz': ['\\\\foo\\bar\\', 'baz'], '//foo//bar//baz': ['//', 'foo//bar//baz'], - 'c:\\c:\\c:\\c:\\\\d:\\e/f/g': ['c:\\c:\\c:\\c:\\\\d:\\', 'e/f/g'], + 'c:\\c:\\c:\\c:\\\\d:\\e/f/g': [ + 'c:\\c:\\c:\\c:\\\\d:\\', + 'e/f/g', + ], 'c:..\\system\\explorer.exe': ['c:', '..\\system\\explorer.exe'], 'd:..\\..\\unsafe\\land': ['d:', '..\\..\\unsafe\\land'], 'c:foo': ['c:', 'foo'], @@ -45,7 +59,13 @@ t.test('drive-local paths', t => { '\\\\?\\X:\\y\\z': ['\\\\?\\X:\\', 'y\\z'], } for (const [input, [root, stripped]] of Object.entries(cases)) { - if (!t.strictSame(stripAbsolutePath(input, cwd), [root, stripped], input)) { + if ( + !t.strictSame( + stripAbsolutePath(input, cwd), + [root, stripped], + input, + ) + ) { break } } diff --git a/test/strip-trailing-slashes.js b/test/strip-trailing-slashes.js index ce0695f8..97f8a16f 100644 --- a/test/strip-trailing-slashes.js +++ b/test/strip-trailing-slashes.js @@ -1,8 +1,8 @@ -const t = require('tap') -const stripSlash = require('../lib/strip-trailing-slashes.js') +import t from 'tap' +import { stripTrailingSlashes } from '../dist/esm/strip-trailing-slashes.js' const short = '///a///b///c///' const long = short.repeat(10) + '/'.repeat(1000000) -t.equal(stripSlash('no slash'), 'no slash') -t.equal(stripSlash(short), '///a///b///c') -t.equal(stripSlash(long), short.repeat(9) + '///a///b///c') +t.equal(stripTrailingSlashes('no slash'), 'no slash') +t.equal(stripTrailingSlashes(short), '///a///b///c') +t.equal(stripTrailingSlashes(long), short.repeat(9) + '///a///b///c') diff --git a/test/symlink-error.js b/test/symlink-error.js new file mode 100644 index 00000000..92a71bd3 --- /dev/null +++ b/test/symlink-error.js @@ -0,0 +1,11 @@ +import t from 'tap' +import { SymlinkError } from '../dist/esm/symlink-error.js' + +t.match(new SymlinkError('symlink', 'path'), { + name: 'SymlinkError', + path: 'path', + symlink: 'symlink', + syscall: 'symlink', + code: 'TAR_SYMLINK_ERROR', + message: 'TAR_SYMLINK_ERROR: Cannot extract through symbolic link', +}) diff --git a/test/types.js b/test/types.js index c2ca5f67..93425d39 100644 --- a/test/types.js +++ b/test/types.js @@ -1,6 +1,8 @@ -'use strict' -// not much to test here, just 2 maps. -const t = require('tap') -const types = require('../lib/types.js') +import t from 'tap' +import * as types from '../dist/esm/types.js' t.equal(types.name.get('0'), 'File') t.equal(types.code.get('File'), '0') +t.equal(types.isCode('0'), true) +t.equal(types.isCode('Z'), false) +t.equal(types.isName('TapeVolumeHeader'), true) +t.equal(types.isName('Unsupported'), false) diff --git a/test/unpack.js b/test/unpack.js index 2f1d3026..51ba1220 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -1,35 +1,38 @@ -'use strict' - process.umask(0o022) -const Unpack = require('../lib/unpack.js') -const UnpackSync = Unpack.Sync -const t = require('tap') -const { Minipass } = require('minipass') +import { Unpack, UnpackSync } from '../dist/esm/unpack.js' + +import fs from 'fs' +import { Minipass } from 'minipass' +import * as z from 'minizlib' +import path from 'path' +import { rimraf } from 'rimraf' +import t from 'tap' +import { fileURLToPath } from 'url' +import { Header } from '../dist/esm/header.js' +import { makeTar } from './fixtures/make-tar.js' -const makeTar = require('./make-tar.js') -const Header = require('../lib/header.js') -const z = require('minizlib') -const fs = require('fs') -const path = require('path') +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) const fixtures = path.resolve(__dirname, 'fixtures') const tars = path.resolve(fixtures, 'tars') const parses = path.resolve(fixtures, 'parse') const unpackdir = path.resolve(fixtures, 'unpack') -const { promisify } = require('util') -const rimraf = promisify(require('rimraf')) -const mkdirp = require('mkdirp') -const mutateFS = require('mutate-fs') -const eos = require('end-of-stream') -const normPath = require('../lib/normalize-windows-path.js') -const ReadEntry = require('../lib/read-entry.js') + +import eos from 'end-of-stream' +import { mkdirp } from 'mkdirp' +import mutateFS from 'mutate-fs' +import { normalizeWindowsPath as normPath } from '../dist/esm/normalize-windows-path.js' + +import { ReadEntry } from '../dist/esm/read-entry.js' // On Windows in particular, the "really deep folder path" file // often tends to cause problems, which don't indicate a failure // of this library, it's just what happens on Windows with super // long file paths. const isWindows = process.platform === 'win32' -const isLongFile = f => f.match(/r.e.a.l.l.y.-.d.e.e.p.-.f.o.l.d.e.r.-.p.a.t.h/) +const isLongFile = f => + f.match(/r.e.a.l.l.y.-.d.e.e.p.-.f.o.l.d.e.r.-.p.a.t.h/) t.teardown(_ => rimraf(unpackdir)) @@ -56,7 +59,8 @@ t.test('basic file unpack tests', t => { 'utf8.tar': { '🌟.txt': 'đŸŒŸâœ§âœŠâ­ī¸ŽâœĒâœĢâœŦ✭✎⚝✯✰âœĩâœļ✷✸✹❂⭑⭒★☆✡â˜Ēâœ´ī¸ŽâœĻâœĄī¸đŸ”¯âœ´ī¸đŸŒ \n', 'Ί.txt': 'Ί', - 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt': 'Ί', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt': + 'Ί', }, 'file.tar': { 'one-byte.txt': 'a', @@ -65,17 +69,26 @@ t.test('basic file unpack tests', t => { 'one-byte.txt': 'a', }, 'long-pax.tar': { - '120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', }, 'long-paths.tar': { - '100-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', - '120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', - '170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', - 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt': 'short\n', - 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', - 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', - 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', - 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt': 'Ί', + '100-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '120-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + '170-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt': + 'short\n', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt': + 'Ί', }, } @@ -199,8 +212,10 @@ t.test('links!', t => { t.test('async', t => { const unpack = new Unpack({ cwd: dir }) let finished = false - unpack.on('finish', _ => finished = true) - unpack.on('close', _ => t.ok(finished, 'emitted finish before close')) + unpack.on('finish', _ => (finished = true)) + unpack.on('close', _ => + t.ok(finished, 'emitted finish before close'), + ) unpack.on('close', _ => check(t)) unpack.end(data) }) @@ -220,8 +235,10 @@ t.test('links!', t => { t.test('async strip', t => { const unpack = new Unpack({ cwd: dir, strip: 1 }) let finished = false - unpack.on('finish', _ => finished = true) - unpack.on('close', _ => t.ok(finished, 'emitted finish before close')) + unpack.on('finish', _ => (finished = true)) + unpack.on('close', _ => + t.ok(finished, 'emitted finish before close'), + ) unpack.on('close', _ => checkForStrip(t)) unpack.end(stripData) }) @@ -235,8 +252,10 @@ t.test('links!', t => { t.test('async strip 3', t => { const unpack = new Unpack({ cwd: dir, strip: 3 }) let finished = false - unpack.on('finish', _ => finished = true) - unpack.on('close', _ => t.ok(finished, 'emitted finish before close')) + unpack.on('finish', _ => (finished = true)) + unpack.on('close', _ => + t.ok(finished, 'emitted finish before close'), + ) unpack.on('close', _ => checkForStrip3(t)) unpack.end(stripData) }) @@ -277,9 +296,10 @@ t.test('links without cleanup (exercise clobbering code)', t => { t.test('async', t => { const unpack = new Unpack({ cwd: dir }) let prefinished = false - unpack.on('prefinish', _ => prefinished = true) + unpack.on('prefinish', _ => (prefinished = true)) unpack.on('finish', _ => - t.ok(prefinished, 'emitted prefinish before finish')) + t.ok(prefinished, 'emitted prefinish before finish'), + ) unpack.on('close', _ => check(t)) unpack.end(data) }) @@ -321,9 +341,12 @@ t.test('nested dir dupe', t => { t.teardown(_ => rimraf(dir)) const expect = { 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt': 'short\n', - 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', - 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', - 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': + 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt': 'Ί', } @@ -347,274 +370,346 @@ t.test('nested dir dupe', t => { zip.end(data) }) -t.test('symlink in dir path', { - skip: isWindows && 'symlinks not fully supported', -}, t => { - const dir = path.resolve(unpackdir, 'symlink-junk') +t.test( + 'symlink in dir path', + { + skip: isWindows && 'symlinks not fully supported', + }, + t => { + const dir = path.resolve(unpackdir, 'symlink-junk') - t.teardown(_ => rimraf(dir)) - t.beforeEach(async () => { - await rimraf(dir) - await mkdirp(dir) - }) + t.teardown(_ => rimraf(dir)) + t.beforeEach(async () => { + await rimraf(dir) + await mkdirp(dir) + }) - const data = makeTar([ - { - path: 'd/i', - type: 'Directory', - }, - { - path: 'd/i/r/dir', - type: 'Directory', - mode: 0o751, - mtime: new Date('2011-03-27T22:16:31.000Z'), - }, - { - path: 'd/i/r/file', - type: 'File', - size: 1, - atime: new Date('1979-07-01T19:10:00.000Z'), - ctime: new Date('2011-03-27T22:16:31.000Z'), - }, - 'a', - { - path: 'd/i/r/link', - type: 'Link', - linkpath: 'd/i/r/file', - atime: new Date('1979-07-01T19:10:00.000Z'), - ctime: new Date('2011-03-27T22:16:31.000Z'), - mtime: new Date('2011-03-27T22:16:31.000Z'), - }, - { - path: 'd/i/r/symlink', - type: 'SymbolicLink', - linkpath: './dir', - atime: new Date('1979-07-01T19:10:00.000Z'), - ctime: new Date('2011-03-27T22:16:31.000Z'), - mtime: new Date('2011-03-27T22:16:31.000Z'), - }, - { - path: 'd/i/r/symlink/x', - type: 'File', - size: 0, - atime: new Date('1979-07-01T19:10:00.000Z'), - ctime: new Date('2011-03-27T22:16:31.000Z'), - mtime: new Date('2011-03-27T22:16:31.000Z'), - }, - '', - '', - ]) + const data = makeTar([ + { + path: 'd/i', + type: 'Directory', + }, + { + path: 'd/i/r/dir', + type: 'Directory', + mode: 0o751, + mtime: new Date('2011-03-27T22:16:31.000Z'), + }, + { + path: 'd/i/r/file', + type: 'File', + size: 1, + atime: new Date('1979-07-01T19:10:00.000Z'), + ctime: new Date('2011-03-27T22:16:31.000Z'), + }, + 'a', + { + path: 'd/i/r/link', + type: 'Link', + linkpath: 'd/i/r/file', + atime: new Date('1979-07-01T19:10:00.000Z'), + ctime: new Date('2011-03-27T22:16:31.000Z'), + mtime: new Date('2011-03-27T22:16:31.000Z'), + }, + { + path: 'd/i/r/symlink', + type: 'SymbolicLink', + linkpath: './dir', + atime: new Date('1979-07-01T19:10:00.000Z'), + ctime: new Date('2011-03-27T22:16:31.000Z'), + mtime: new Date('2011-03-27T22:16:31.000Z'), + }, + { + path: 'd/i/r/symlink/x', + type: 'File', + size: 0, + atime: new Date('1979-07-01T19:10:00.000Z'), + ctime: new Date('2011-03-27T22:16:31.000Z'), + mtime: new Date('2011-03-27T22:16:31.000Z'), + }, + '', + '', + ]) - t.test('no clobbering', t => { - const warnings = [] - const u = new Unpack({ - cwd: dir, - onwarn: (c, w, d) => warnings.push([c, w, d]), + t.test('no clobbering', t => { + const warnings = [] + const u = new Unpack({ + cwd: dir, + onwarn: (c, w, d) => warnings.push([c, w, d]), + }) + u.on('close', _ => { + t.equal( + fs.lstatSync(dir + '/d/i').mode & 0o7777, + isWindows ? 0o666 : 0o755, + ) + t.equal( + fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, + isWindows ? 0o666 : 0o751, + ) + t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + if (!isWindows) { + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + 'got symlink', + ) + t.throws(_ => fs.statSync(dir + '/d/i/r/symlink/x')) + } + t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') + if (!isWindows) { + t.equal( + warnings[0][1], + 'TAR_SYMLINK_ERROR: Cannot extract through symbolic link', + ) + t.match(warnings[0][2], { + name: 'SymlinkError', + code: 'TAR_SYMLINK_ERROR', + tarCode: 'TAR_ENTRY_ERROR', + path: dir + '/d/i/r/symlink/', + symlink: dir + '/d/i/r/symlink', + }) + } + t.equal(warnings.length, 1) + t.end() + }) + u.end(data) }) - u.on('close', _ => { - t.equal(fs.lstatSync(dir + '/d/i').mode & 0o7777, isWindows ? 0o666 : 0o755) - t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, isWindows ? 0o666 : 0o751) + + t.test('no clobbering, sync', t => { + const warnings = [] + const u = new UnpackSync({ + cwd: dir, + onwarn: (c, w, d) => warnings.push([c, w, d]), + }) + u.end(data) + t.equal( + fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, + isWindows ? 0o666 : 0o751, + ) t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') if (!isWindows) { - t.ok(fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'got symlink') + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + 'got symlink', + ) t.throws(_ => fs.statSync(dir + '/d/i/r/symlink/x')) } - t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') - if (!isWindows) { - t.equal(warnings[0][1], 'Cannot extract through symbolic link') - t.match(warnings[0][2], { - name: 'SylinkError', - path: dir + '/d/i/r/symlink/', - symlink: dir + '/d/i/r/symlink', - }) - } t.equal(warnings.length, 1) + t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') + t.equal( + warnings[0][1], + 'TAR_SYMLINK_ERROR: Cannot extract through symbolic link', + ) + t.match(warnings[0][2], { + name: 'SymlinkError', + path: dir + '/d/i/r/symlink/', + symlink: dir + '/d/i/r/symlink', + }) t.end() }) - u.end(data) - }) - t.test('no clobbering, sync', t => { - const warnings = [] - const u = new UnpackSync({ - cwd: dir, - onwarn: (c, w, d) => warnings.push([c, w, d]), - }) - u.end(data) - t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, isWindows ? 0o666 : 0o751) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') - if (!isWindows) { - t.ok(fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'got symlink') - t.throws(_ => fs.statSync(dir + '/d/i/r/symlink/x')) - } - t.equal(warnings.length, 1) - t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') - t.equal(warnings[0][1], 'Cannot extract through symbolic link') - t.match(warnings[0][2], { - name: 'SylinkError', - path: dir + '/d/i/r/symlink/', - symlink: dir + '/d/i/r/symlink', + t.test('extract through symlink', t => { + const warnings = [] + const u = new Unpack({ + cwd: dir, + onwarn: (c, w, d) => warnings.push([c, w, d]), + preservePaths: true, + }) + u.on('close', _ => { + t.same(warnings, []) + t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) + t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + 'got symlink', + ) + t.ok( + fs.lstatSync(dir + '/d/i/r/dir/x').isFile(), + 'x thru link', + ) + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), + 'x thru link', + ) + t.end() + }) + u.end(data) }) - t.end() - }) - t.test('extract through symlink', t => { - const warnings = [] - const u = new Unpack({ - cwd: dir, - onwarn: (c, w, d) => warnings.push([c, w, d]), - preservePaths: true, - }) - u.on('close', _ => { + t.test('extract through symlink sync', t => { + const warnings = [] + const u = new UnpackSync({ + cwd: dir, + onwarn: (c, w, d) => warnings.push([c, w, d]), + preservePaths: true, + }) + u.end(data) t.same(warnings, []) t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') - t.ok(fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'got symlink') + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + 'got symlink', + ) t.ok(fs.lstatSync(dir + '/d/i/r/dir/x').isFile(), 'x thru link') - t.ok(fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), 'x thru link') + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), + 'x thru link', + ) t.end() }) - u.end(data) - }) - t.test('extract through symlink sync', t => { - const warnings = [] - const u = new UnpackSync({ - cwd: dir, - onwarn: (c, w, d) => warnings.push([c, w, d]), - preservePaths: true, + t.test('clobber through symlink', t => { + const warnings = [] + const u = new Unpack({ + cwd: dir, + onwarn: (c, w, d) => warnings.push([c, w, d]), + unlink: true, + }) + u.on('close', _ => { + t.same(warnings, []) + t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) + t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + t.notOk( + fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + 'no link', + ) + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink').isDirectory(), + 'sym is dir', + ) + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), + 'x thru link', + ) + t.end() + }) + u.end(data) }) - u.end(data) - t.same(warnings, []) - t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') - t.ok(fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'got symlink') - t.ok(fs.lstatSync(dir + '/d/i/r/dir/x').isFile(), 'x thru link') - t.ok(fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), 'x thru link') - t.end() - }) - t.test('clobber through symlink', t => { - const warnings = [] - const u = new Unpack({ - cwd: dir, - onwarn: (c, w, d) => warnings.push([c, w, d]), - unlink: true, + t.test('clobber through symlink with busted unlink', t => { + const poop = new Error('poop') + // for some reason, resetting fs.unlink in the teardown was breaking + const reset = mutateFS.fail('unlink', poop) + const warnings = [] + const u = new Unpack({ + cwd: dir, + onwarn: (c, w, d) => warnings.push([c, w, d]), + unlink: true, + }) + u.on('close', _ => { + t.same(warnings, [['TAR_ENTRY_ERROR', 'poop', poop]]) + reset() + t.end() + }) + u.end(data) }) - u.on('close', _ => { - t.same(warnings, []) + + t.test('clobber through symlink sync', t => { + const warnings = [] + const u = new UnpackSync({ + cwd: dir, + onwarn: (c, w, d) => warnings.push([c, w, d]), + unlink: true, + }) + u.end(data) t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') - t.notOk(fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'no link') - t.ok(fs.lstatSync(dir + '/d/i/r/symlink').isDirectory(), 'sym is dir') - t.ok(fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), 'x thru link') + t.notOk( + fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + 'no link', + ) + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink').isDirectory(), + 'sym is dir', + ) + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), + 'x thru link', + ) t.end() }) - u.end(data) - }) - t.test('clobber through symlink with busted unlink', t => { - const poop = new Error('poop') - // for some reason, resetting fs.unlink in the teardown was breaking - const reset = mutateFS.fail('unlink', poop) - const warnings = [] - const u = new Unpack({ - cwd: dir, - onwarn: (c, w, d) => warnings.push([c, w, d]), - unlink: true, - }) - u.on('close', _ => { - t.same(warnings, [['TAR_ENTRY_ERROR', 'poop', poop]]) - reset() - t.end() - }) - u.end(data) - }) - - t.test('clobber through symlink sync', t => { - const warnings = [] - const u = new UnpackSync({ - cwd: dir, - onwarn: (c, w, d) => warnings.push([c, w, d]), - unlink: true, + t.test('clobber dirs', t => { + mkdirp.sync(dir + '/d/i/r/dir') + mkdirp.sync(dir + '/d/i/r/file') + mkdirp.sync(dir + '/d/i/r/link') + mkdirp.sync(dir + '/d/i/r/symlink') + const warnings = [] + const u = new Unpack({ + cwd: dir, + onwarn: (c, w, d) => { + warnings.push([c, w, d]) + }, + }) + u.on('close', _ => { + t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) + t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + 'got symlink', + ) + t.throws(_ => fs.statSync(dir + '/d/i/r/symlink/x')) + t.equal(warnings.length, 1) + t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') + t.equal( + warnings[0][1], + 'TAR_SYMLINK_ERROR: Cannot extract through symbolic link', + ) + t.match(warnings[0][2], { + name: 'SymlinkError', + path: dir + '/d/i/r/symlink/', + symlink: dir + '/d/i/r/symlink', + }) + t.end() + }) + u.end(data) }) - u.end(data) - t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') - t.notOk(fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'no link') - t.ok(fs.lstatSync(dir + '/d/i/r/symlink').isDirectory(), 'sym is dir') - t.ok(fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), 'x thru link') - t.end() - }) - t.test('clobber dirs', t => { - mkdirp.sync(dir + '/d/i/r/dir') - mkdirp.sync(dir + '/d/i/r/file') - mkdirp.sync(dir + '/d/i/r/link') - mkdirp.sync(dir + '/d/i/r/symlink') - const warnings = [] - const u = new Unpack({ - cwd: dir, - onwarn: (c, w, d) => { - warnings.push([c, w, d]) - }, - }) - u.on('close', _ => { + t.test('clobber dirs sync', t => { + mkdirp.sync(dir + '/d/i/r/dir') + mkdirp.sync(dir + '/d/i/r/file') + mkdirp.sync(dir + '/d/i/r/link') + mkdirp.sync(dir + '/d/i/r/symlink') + const warnings = [] + const u = new UnpackSync({ + cwd: dir, + onwarn: (c, w, d) => { + warnings.push([c, w, d]) + }, + }) + u.end(data) t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') - t.ok(fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'got symlink') + t.ok( + fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + 'got symlink', + ) t.throws(_ => fs.statSync(dir + '/d/i/r/symlink/x')) t.equal(warnings.length, 1) t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') - t.equal(warnings[0][1], 'Cannot extract through symbolic link') + t.equal( + warnings[0][1], + 'TAR_SYMLINK_ERROR: Cannot extract through symbolic link', + ) t.match(warnings[0][2], { - name: 'SylinkError', + name: 'SymlinkError', path: dir + '/d/i/r/symlink/', symlink: dir + '/d/i/r/symlink', }) t.end() }) - u.end(data) - }) - t.test('clobber dirs sync', t => { - mkdirp.sync(dir + '/d/i/r/dir') - mkdirp.sync(dir + '/d/i/r/file') - mkdirp.sync(dir + '/d/i/r/link') - mkdirp.sync(dir + '/d/i/r/symlink') - const warnings = [] - const u = new UnpackSync({ - cwd: dir, - onwarn: (c, w, d) => { - warnings.push([c, w, d]) - }, - }) - u.end(data) - t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') - t.ok(fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'got symlink') - t.throws(_ => fs.statSync(dir + '/d/i/r/symlink/x')) - t.equal(warnings.length, 1) - t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') - t.equal(warnings[0][1], 'Cannot extract through symbolic link') - t.match(warnings[0][2], { - name: 'SylinkError', - path: dir + '/d/i/r/symlink/', - symlink: dir + '/d/i/r/symlink', - }) t.end() - }) - - t.end() -}) + }, +) t.test('unsupported entries', t => { const dir = path.resolve(unpackdir, 'unsupported-entries') mkdirp.sync(dir) t.teardown(_ => rimraf(dir)) - const unknown = new Header({ path: 'qux', type: 'File', size: 4 }) - unknown.type = 'Z' + const unknown = new Header({ path: 'qux', size: 4 }) unknown.encode() + unknown.block?.write('Z', 156) const data = makeTar([ { path: 'dev/random', @@ -639,15 +734,33 @@ t.test('unsupported entries', t => { t.test('basic, warns', t => { const warnings = [] - const u = new Unpack({ cwd: dir, onwarn: (c, w, d) => warnings.push([c, w, d]) }) + const u = new Unpack({ + cwd: dir, + onwarn: (c, w, d) => warnings.push([c, w, d]), + }) const c = 'TAR_ENTRY_UNSUPPORTED' const expect = [ - [c, 'unsupported entry type: CharacterDevice', { - entry: { path: 'dev/random' } }], - [c, 'unsupported entry type: BlockDevice', { - entry: { path: 'dev/hd0' } }], - [c, 'unsupported entry type: FIFO', { - entry: { path: 'dev/fifo0' } }], + [ + c, + 'unsupported entry type: CharacterDevice', + { + entry: { path: 'dev/random' }, + }, + ], + [ + c, + 'unsupported entry type: BlockDevice', + { + entry: { path: 'dev/hd0' }, + }, + ], + [ + c, + 'unsupported entry type: FIFO', + { + entry: { path: 'dev/fifo0' }, + }, + ], ] u.on('close', _ => { t.equal(fs.readdirSync(dir).length, 0) @@ -752,7 +865,9 @@ t.test('file in dir path', t => { t.plan(2) t.test('async', t => { - new Unpack({ cwd: dir, unlink: true }).on('close', _ => check(t)).end(data) + new Unpack({ cwd: dir, unlink: true }) + .on('close', _ => check(t)) + .end(data) }) t.test('sync', t => { @@ -782,11 +897,19 @@ t.test('set umask option', t => { new Unpack({ umask: 0o027, cwd: dir, - }).on('close', _ => { - t.equal(fs.statSync(dir + '/d/i/r').mode & 0o7777, isWindows ? 0o666 : 0o750) - t.equal(fs.statSync(dir + '/d/i/r/dir').mode & 0o7777, isWindows ? 0o666 : 0o751) - t.end() - }).end(data) + }) + .on('close', _ => { + t.equal( + fs.statSync(dir + '/d/i/r').mode & 0o7777, + isWindows ? 0o666 : 0o750, + ) + t.equal( + fs.statSync(dir + '/d/i/r/dir').mode & 0o7777, + isWindows ? 0o666 : 0o751, + ) + t.end() + }) + .end(data) }) t.test('absolute paths', t => { @@ -823,11 +946,16 @@ t.test('absolute paths', t => { t.test('warn and correct', t => { const check = t => { const r = normPath(root) - t.match(warnings, [[ - `stripping ${r}${r}${r}${r} from absolute path`, - { path: normPath(absolute), code: 'TAR_ENTRY_INFO' }, - ]]) - t.ok(fs.lstatSync(path.resolve(dir, relative)).isFile(), 'is file') + t.match(warnings, [ + [ + `stripping ${r}${r}${r}${r} from absolute path`, + { path: normPath(absolute), code: 'TAR_ENTRY_INFO' }, + ], + ]) + t.ok( + fs.lstatSync(path.resolve(dir, relative)).isFile(), + 'is file', + ) t.end() } @@ -837,15 +965,17 @@ t.test('absolute paths', t => { warnings.length = 0 new Unpack({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), - }).on('close', _ => check(t)).end(data) + onwarn: (_c, w, d) => warnings.push([w, d]), + }) + .on('close', _ => check(t)) + .end(data) }) t.test('sync', t => { warnings.length = 0 new UnpackSync({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), + onwarn: (_c, w, d) => warnings.push([w, d]), }).end(data) check(t) }) @@ -883,8 +1013,10 @@ t.test('absolute paths', t => { new Unpack({ preservePaths: true, cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), - }).on('close', _ => check(t)).end(data) + onwarn: (_c, w, d) => warnings.push([w, d]), + }) + .on('close', _ => check(t)) + .end(data) }) t.test('sync', t => { @@ -892,7 +1024,7 @@ t.test('absolute paths', t => { new UnpackSync({ preservePaths: true, cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), + onwarn: (_c, w, d) => warnings.push([w, d]), }).end(data) check(t) }) @@ -931,10 +1063,12 @@ t.test('.. paths', t => { t.test('warn and skip', t => { const check = t => { - t.match(warnings, [[ - 'path contains \'..\'', - { path: dotted, code: 'TAR_ENTRY_ERROR' }, - ]]) + t.match(warnings, [ + [ + "path contains '..'", + { path: dotted, code: 'TAR_ENTRY_ERROR' }, + ], + ]) t.throws(_ => fs.lstatSync(resolved)) t.end() } @@ -946,8 +1080,10 @@ t.test('.. paths', t => { new Unpack({ fmode: fmode, cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), - }).on('close', _ => check(t)).end(data) + onwarn: (_c, w, d) => warnings.push([w, d]), + }) + .on('close', _ => check(t)) + .end(data) }) t.test('sync', t => { @@ -955,7 +1091,7 @@ t.test('.. paths', t => { new UnpackSync({ fmode: fmode, cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), + onwarn: (_c, w, d) => warnings.push([w, d]), }).end(data) check(t) }) @@ -967,7 +1103,10 @@ t.test('.. paths', t => { const check = t => { t.same(warnings, []) t.ok(fs.lstatSync(resolved).isFile(), 'is file') - t.equal(fs.lstatSync(resolved).mode & 0o777, isWindows ? 0o666 : fmode) + t.equal( + fs.lstatSync(resolved).mode & 0o777, + isWindows ? 0o666 : fmode, + ) t.end() } @@ -979,8 +1118,10 @@ t.test('.. paths', t => { fmode: fmode, preservePaths: true, cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), - }).on('close', _ => check(t)).end(data) + onwarn: (_c, w, d) => warnings.push([w, d]), + }) + .on('close', _ => check(t)) + .end(data) }) t.test('sync', t => { @@ -989,7 +1130,7 @@ t.test('.. paths', t => { fmode: fmode, preservePaths: true, cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), + onwarn: (_c, w, d) => warnings.push([w, d]), }).end(data) check(t) }) @@ -1004,36 +1145,36 @@ t.test('fail all stats', t => { const poop = new Error('poop') poop.code = 'EPOOP' const dir = normPath(path.join(unpackdir, 'stat-fail')) - const { - stat, - fstat, - lstat, - statSync, - fstatSync, - lstatSync, - } = fs - const unmutate = () => Object.assign(fs, { - stat, - fstat, - lstat, - statSync, - fstatSync, - lstatSync, - }) + const { stat, fstat, lstat, statSync, fstatSync, lstatSync } = fs + const unmutate = () => + Object.assign(fs, { + stat, + fstat, + lstat, + statSync, + fstatSync, + lstatSync, + }) const mutate = () => { - fs.stat = fs.lstat = fs.fstat = (...args) => { - // don't fail statting the cwd, or we get different errors - if (normPath(args[0]) === dir) { - return lstat(dir, args.pop()) - } - process.nextTick(() => args.pop()(poop)) - } - fs.statSync = fs.lstatSync = fs.fstatSync = (...args) => { - if (normPath(args[0]) === dir) { - return lstatSync(dir) - } - throw poop - } + fs.stat = + fs.lstat = + fs.fstat = + (...args) => { + // don't fail statting the cwd, or we get different errors + if (normPath(args[0]) === dir) { + return lstat(dir, args.pop()) + } + process.nextTick(() => args.pop()(poop)) + } + fs.statSync = + fs.lstatSync = + fs.fstatSync = + (...args) => { + if (normPath(args[0]) === dir) { + return lstatSync(dir) + } + throw poop + } } const warnings = [] @@ -1105,8 +1246,10 @@ t.test('fail all stats', t => { ] new Unpack({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), - }).on('close', _ => check(t, expect)).end(data) + onwarn: (_c, w, d) => warnings.push([w, d]), + }) + .on('close', _ => check(t, expect)) + .end(data) }) t.test('sync', t => { @@ -1130,7 +1273,7 @@ t.test('fail all stats', t => { ] new UnpackSync({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), + onwarn: (_c, w, d) => warnings.push([w, d]), }).end(data) check(t, expect) }) @@ -1186,15 +1329,17 @@ t.test('fail symlink', t => { const expect = [['poop', poop]] new Unpack({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), - }).on('close', _ => check(t, expect)).end(data) + onwarn: (_c, w, d) => warnings.push([w, d]), + }) + .on('close', _ => check(t, expect)) + .end(data) }) t.test('sync', t => { const expect = [['poop', poop]] new UnpackSync({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), + onwarn: (_c, w, d) => warnings.push([w, d]), }).end(data) check(t, expect) }) @@ -1249,15 +1394,17 @@ t.test('fail chmod', t => { const expect = [['poop', poop]] new Unpack({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), - }).on('close', _ => check(t, expect)).end(data) + onwarn: (_c, w, d) => warnings.push([w, d]), + }) + .on('close', _ => check(t, expect)) + .end(data) }) t.test('sync', t => { const expect = [['poop', poop]] new UnpackSync({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), + onwarn: (_c, w, d) => warnings.push([w, d]), }).end(data) check(t, expect) }) @@ -1294,14 +1441,16 @@ t.test('fail mkdir', t => { '', ]) - const expect = [[ - 'ENOENT: no such file or directory', - { - code: 'ENOENT', - syscall: 'lstat', - path: normPath(path.resolve(dir, 'dir')), - }, - ]] + const expect = [ + [ + 'ENOENT: no such file or directory', + { + code: 'ENOENT', + syscall: 'lstat', + path: normPath(path.resolve(dir, 'dir')), + }, + ], + ] const check = t => { t.match(warnings, expect) @@ -1312,7 +1461,7 @@ t.test('fail mkdir', t => { t.test('sync', t => { new UnpackSync({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), + onwarn: (_c, w, d) => warnings.push([w, d]), }).end(data) check(t) }) @@ -1320,8 +1469,10 @@ t.test('fail mkdir', t => { t.test('async', t => { new Unpack({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), - }).on('close', _ => check(t)).end(data) + onwarn: (_c, w, d) => warnings.push([w, d]), + }) + .on('close', _ => check(t)) + .end(data) }) t.end() @@ -1368,14 +1519,16 @@ t.test('fail write', t => { t.test('async', t => { new Unpack({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), - }).on('close', _ => check(t)).end(data) + onwarn: (_c, w, d) => warnings.push([w, d]), + }) + .on('close', _ => check(t)) + .end(data) }) t.test('sync', t => { new UnpackSync({ cwd: dir, - onwarn: (c, w, d) => warnings.push([w, d]), + onwarn: (_c, w, d) => warnings.push([w, d]), }).end(data) check(t) }) @@ -1421,7 +1574,9 @@ t.test('skip existing', t => { new Unpack({ cwd: dir, keep: true, - }).on('close', _ => check(t)).end(data) + }) + .on('close', _ => check(t)) + .end(data) }) t.test('sync', t => { @@ -1473,7 +1628,9 @@ t.test('skip newer', t => { new Unpack({ cwd: dir, newer: true, - }).on('close', _ => check(t)).end(data) + }) + .on('close', _ => check(t)) + .end(data) }) t.test('sync', t => { @@ -1537,7 +1694,9 @@ t.test('no mtime', t => { new Unpack({ cwd: dir, noMtime: true, - }).on('close', _ => check(t)).end(data) + }) + .on('close', _ => check(t)) + .end(data) }) t.test('sync', t => { @@ -1563,7 +1722,8 @@ t.test('unpack big enough to pause/drain', t => { }) u.on('ignoredEntry', entry => - t.fail('should not get ignored entry: ' + entry.path)) + t.fail('should not get ignored entry: ' + entry.path), + ) u.on('close', _ => { t.pass('extraction finished') @@ -1584,7 +1744,9 @@ t.test('set owner', t => { const getgid = process.getgid process.getuid = _ => myUid process.getgid = _ => myGid - t.teardown(_ => (process.getuid = getuid, process.getgid = getgid)) + t.teardown( + _ => ((process.getuid = getuid), (process.getgid = getgid)), + ) // can't actually do this because it requires root, but we can // verify that chown gets called. @@ -1688,10 +1850,10 @@ t.test('set owner', t => { mkdirp.sync(dir) t.teardown(_ => rimraf(dir)) let warned = false - const u = new Unpack.Sync({ + const u = new UnpackSync({ cwd: dir, preserveOwner: true, - onwarn: (c, m, er) => { + onwarn: (_c, _m, er) => { if (!warned) { warned = true t.equal(er, poop) @@ -1709,7 +1871,7 @@ t.test('set owner', t => { const u = new Unpack({ cwd: dir, preserveOwner: true, - onwarn: (c, m, er) => { + onwarn: (_c, _m, er) => { if (!warned) { warned = true t.equal(er, poop) @@ -1732,10 +1894,13 @@ t.test('set owner', t => { const fchownSync = fs.fchownSync const lchownSync = fs.lchownSync let called = 0 - fs.fchown = fs.chown = fs.lchown = (path, owner, group, cb) => { - called++ - cb() - } + fs.fchown = + fs.chown = + fs.lchown = + (_path, _owner, _group, cb) => { + called++ + cb() + } fs.chownSync = fs.lchownSync = fs.fchownSync = _ => called++ t.teardown(_ => { @@ -1751,7 +1916,7 @@ t.test('set owner', t => { mkdirp.sync(dir) t.teardown(_ => rimraf(dir)) called = 0 - const u = new Unpack.Sync({ cwd: dir, preserveOwner: true }) + const u = new UnpackSync({ cwd: dir, preserveOwner: true }) u.end(data) t.ok(called >= 5, 'called chowns') t.end() @@ -1797,13 +1962,15 @@ t.test('set owner', t => { t.not(fileStat.gid, 813708013) const dirStat2 = fs.statSync(dir + '/foo/different-uid-nogid') t.not(dirStat2.uid, 2456124561) - const fileStat2 = fs.statSync(dir + '/foo/different-uid-nogid/bar') + const fileStat2 = fs.statSync( + dir + '/foo/different-uid-nogid/bar', + ) t.not(fileStat2.uid, 2456124561) t.end() } t.test('sync', t => { - const u = new Unpack.Sync({ cwd: dir, preserveOwner: false }) + const u = new UnpackSync({ cwd: dir, preserveOwner: false }) u.end(data) check(t) }) @@ -1842,13 +2009,16 @@ t.test('unpack when dir is not writable', t => { t.afterEach(() => rimraf(dir)) const check = t => { - t.equal(fs.statSync(dir + '/a').mode & 0o7777, isWindows ? 0o666 : 0o744) + t.equal( + fs.statSync(dir + '/a').mode & 0o7777, + isWindows ? 0o666 : 0o744, + ) t.equal(fs.readFileSync(dir + '/a/b', 'utf8'), 'a') t.end() } t.test('sync', t => { - const u = new Unpack.Sync({ cwd: dir, strict: true }) + const u = new UnpackSync({ cwd: dir, strict: true }) u.end(data) check(t) }) @@ -1898,7 +2068,7 @@ t.test('transmute chars on windows', t => { }) t.test('sync', t => { - const u = new Unpack.Sync({ + const u = new UnpackSync({ cwd: dir, win32: true, }) @@ -1972,7 +2142,7 @@ t.test('use explicit chmod when required by umask', t => { return t.test('sync', t => { mkdirp.sync(basedir) - const unpack = new Unpack.Sync({ cwd: basedir }) + const unpack = new UnpackSync({ cwd: basedir }) unpack.end(data) check(t) }) @@ -1981,7 +2151,7 @@ t.test('use explicit chmod when required by umask', t => { t.test('dont use explicit chmod if noChmod flag set', t => { process.umask(0o022) const { umask } = process - t.teardown(() => process.umask = umask) + t.teardown(() => (process.umask = umask)) process.umask = () => { throw new Error('should not call process.umask()') } @@ -2014,7 +2184,7 @@ t.test('dont use explicit chmod if noChmod flag set', t => { return t.test('sync', t => { mkdirp.sync(basedir) - const unpack = new Unpack.Sync({ cwd: basedir, noChmod: true }) + const unpack = new UnpackSync({ cwd: basedir, noChmod: true }) unpack.end(data) check(t) }) @@ -2046,18 +2216,24 @@ t.test('chown implicit dirs and also the entries', t => { let chowns = 0 let currentTest = null - fs.lchown = fs.fchown = fs.chown = (path, uid, gid, cb) => { - currentTest.equal(uid, 420, 'chown(' + path + ') uid') - currentTest.equal(gid, 666, 'chown(' + path + ') gid') - chowns++ - cb() - } + fs.lchown = + fs.fchown = + fs.chown = + (path, uid, gid, cb) => { + currentTest.equal(uid, 420, 'chown(' + path + ') uid') + currentTest.equal(gid, 666, 'chown(' + path + ') gid') + chowns++ + cb() + } - fs.lchownSync = fs.chownSync = fs.fchownSync = (path, uid, gid) => { - currentTest.equal(uid, 420, 'chownSync(' + path + ') uid') - currentTest.equal(gid, 666, 'chownSync(' + path + ') gid') - chowns++ - } + fs.lchownSync = + fs.chownSync = + fs.fchownSync = + (path, uid, gid) => { + currentTest.equal(uid, 420, 'chownSync(' + path + ') uid') + currentTest.equal(gid, 666, 'chownSync(' + path + ') gid') + chowns++ + } const data = makeTar([ { @@ -2091,29 +2267,49 @@ t.test('chown implicit dirs and also the entries', t => { } t.test('throws when setting uid/gid improperly', t => { - t.throws(_ => new Unpack({ uid: 420 }), - TypeError('cannot set owner without number uid and gid')) - t.throws(_ => new Unpack({ gid: 666 }), - TypeError('cannot set owner without number uid and gid')) - t.throws(_ => new Unpack({ uid: 1, gid: 2, preserveOwner: true }), - TypeError('cannot preserve owner in archive and also set owner explicitly')) + t.throws( + _ => new Unpack({ uid: 420 }), + TypeError('cannot set owner without number uid and gid'), + ) + t.throws( + _ => new Unpack({ gid: 666 }), + TypeError('cannot set owner without number uid and gid'), + ) + t.throws( + _ => new Unpack({ uid: 1, gid: 2, preserveOwner: true }), + TypeError( + 'cannot preserve owner in archive and also set owner explicitly', + ), + ) t.end() }) const tests = () => - t.test('async', t => { - currentTest = t - mkdirp.sync(basedir) - const unpack = new Unpack({ cwd: basedir, uid: 420, gid: 666 }) - unpack.on('close', _ => check(t)) - unpack.end(data) - }).then(t.test('sync', t => { - currentTest = t - mkdirp.sync(basedir) - const unpack = new Unpack.Sync({ cwd: basedir, uid: 420, gid: 666 }) - unpack.end(data) - check(t) - })) + t + .test('async', t => { + currentTest = t + mkdirp.sync(basedir) + const unpack = new Unpack({ + cwd: basedir, + uid: 420, + gid: 666, + }) + unpack.on('close', _ => check(t)) + unpack.end(data) + }) + .then( + t.test('sync', t => { + currentTest = t + mkdirp.sync(basedir) + const unpack = new UnpackSync({ + cwd: basedir, + uid: 420, + gid: 666, + }) + unpack.end(data) + check(t) + }), + ) tests() @@ -2158,64 +2354,72 @@ t.test('bad cwd setting', t => { fs.writeFileSync(basedir + '/file', 'xyz') - cases.forEach(c => t.test(c.type + ' ' + c.path, t => { - const data = makeTar([ - { - path: c.path, - mode: 0o775, - type: c.type, - size: 0, - uid: null, - gid: null, - }, - '', - '', - ]) - - t.test('cwd is a file', t => { - const cwd = basedir + '/file' - const opt = { cwd: cwd } + cases.forEach(c => + t.test(c.type + ' ' + c.path, t => { + const data = makeTar([ + { + path: c.path, + mode: 0o775, + type: c.type, + size: 0, + uid: null, + gid: null, + }, + '', + '', + ]) - t.throws(_ => new Unpack.Sync(opt).end(data), { - name: 'CwdError', - message: 'ENOTDIR: Cannot cd into \'' + normPath(cwd) + '\'', - path: normPath(cwd), - code: 'ENOTDIR', - }) + t.test('cwd is a file', t => { + const cwd = basedir + '/file' + const opt = { cwd: cwd } - new Unpack(opt).on('error', er => { - t.match(er, { + t.throws(_ => new UnpackSync(opt).end(data), { name: 'CwdError', - message: 'ENOTDIR: Cannot cd into \'' + normPath(cwd) + '\'', + message: "ENOTDIR: Cannot cd into '" + normPath(cwd) + "'", path: normPath(cwd), code: 'ENOTDIR', }) - t.end() - }).end(data) - }) - - return t.test('cwd is missing', t => { - const cwd = basedir + '/asdf/asdf/asdf' - const opt = { cwd: cwd } - t.throws(_ => new Unpack.Sync(opt).end(data), { - name: 'CwdError', - message: 'ENOENT: Cannot cd into \'' + normPath(cwd) + '\'', - path: normPath(cwd), - code: 'ENOENT', + new Unpack(opt) + .on('error', er => { + t.match(er, { + name: 'CwdError', + message: + "ENOTDIR: Cannot cd into '" + normPath(cwd) + "'", + path: normPath(cwd), + code: 'ENOTDIR', + }) + t.end() + }) + .end(data) }) - new Unpack(opt).on('error', er => { - t.match(er, { + return t.test('cwd is missing', t => { + const cwd = basedir + '/asdf/asdf/asdf' + const opt = { cwd: cwd } + + t.throws(_ => new UnpackSync(opt).end(data), { name: 'CwdError', - message: 'ENOENT: Cannot cd into \'' + normPath(cwd) + '\'', + message: "ENOENT: Cannot cd into '" + normPath(cwd) + "'", path: normPath(cwd), code: 'ENOENT', }) - t.end() - }).end(data) - }) - })) + + new Unpack(opt) + .on('error', er => { + t.match(er, { + name: 'CwdError', + message: + "ENOENT: Cannot cd into '" + normPath(cwd) + "'", + path: normPath(cwd), + code: 'ENOENT', + }) + t.end() + }) + .end(data) + }) + }), + ) t.end() }) @@ -2238,7 +2442,8 @@ t.test('transform', t => { 'utf8.tar': { '🌟.txt': 'đŸŒŸâœ§âœŠâ­ī¸ŽâœĒâœĢâœŦ✭✎⚝✯✰âœĩâœļ✷✸✹❂⭑⭒★☆✡â˜Ēâœ´ī¸ŽâœĻâœĄī¸đŸ”¯âœ´ī¸đŸŒ \n', 'Ί.txt': '[Ί]', - 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt': '[Ί]', + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt': + '[Ί]', }, } @@ -2256,8 +2461,12 @@ t.test('transform', t => { } class Bracer extends Minipass { - write (data) { - const d = data.toString().split('').map(c => '[' + c + ']').join('') + write(data) { + const d = data + .toString() + .split('') + .map(c => '[' + c + ']') + .join('') return super.write(d) } } @@ -2289,7 +2498,11 @@ t.test('transform', t => { t.test('async unpack', t => { t.plan(2) t.test('strict', t => { - const unpack = new Unpack({ cwd: dir, strict: true, transform: txFn }) + const unpack = new Unpack({ + cwd: dir, + strict: true, + transform: txFn, + }) fs.createReadStream(tf).pipe(unpack) eos(unpack, _ => check(t)) }) @@ -2303,7 +2516,11 @@ t.test('transform', t => { t.test('sync unpack', t => { t.plan(2) t.test('strict', t => { - const unpack = new UnpackSync({ cwd: dir, strict: true, transform: txFn }) + const unpack = new UnpackSync({ + cwd: dir, + strict: true, + transform: txFn, + }) unpack.end(fs.readFileSync(tf)) check(t) }) @@ -2335,7 +2552,11 @@ t.test('transform error', t => { t.test('sync unpack', t => { t.test('strict', t => { - const unpack = new UnpackSync({ cwd: dir, strict: true, transform: txFn }) + const unpack = new UnpackSync({ + cwd: dir, + strict: true, + transform: txFn, + }) const expect = 3 let actual = 0 unpack.on('error', er => { @@ -2350,7 +2571,7 @@ t.test('transform error', t => { const unpack = new UnpackSync({ cwd: dir, transform: txFn }) const expect = 3 let actual = 0 - unpack.on('warn', (code, msg, er) => { + unpack.on('warn', (_code, _msg, er) => { t.equal(er, poop) actual++ }) @@ -2363,7 +2584,11 @@ t.test('transform error', t => { t.test('async unpack', t => { // the last error is about the folder being deleted, just ignore that one t.test('strict', t => { - const unpack = new Unpack({ cwd: dir, strict: true, transform: txFn }) + const unpack = new Unpack({ + cwd: dir, + strict: true, + transform: txFn, + }) t.plan(3) t.teardown(() => { unpack.removeAllListeners('error') @@ -2376,7 +2601,7 @@ t.test('transform error', t => { const unpack = new Unpack({ cwd: dir, transform: txFn }) t.plan(3) t.teardown(() => unpack.removeAllListeners('warn')) - unpack.on('warn', (code, msg, er) => t.equal(er, poop)) + unpack.on('warn', (_code, _msg, er) => t.equal(er, poop)) unpack.end(tardata) }) t.end() @@ -2413,13 +2638,17 @@ t.test('futimes/fchown failures', t => { t.test('async unpack', t => { t.plan(2) t.test('strict', t => { - const unpack = new Unpack({ cwd: dir, strict: true, forceChown: fc }) - unpack.on('finish', t.end) + const unpack = new Unpack({ + cwd: dir, + strict: true, + forceChown: fc, + }) + unpack.on('finish', () => t.end()) unpack.end(tardata) }) t.test('loose', t => { const unpack = new Unpack({ cwd: dir, forceChown: fc }) - unpack.on('finish', t.end) + unpack.on('finish', () => t.end()) unpack.on('warn', t.fail) unpack.end(tardata) }) @@ -2427,12 +2656,16 @@ t.test('futimes/fchown failures', t => { t.test('sync unpack', t => { t.plan(2) t.test('strict', t => { - const unpack = new Unpack.Sync({ cwd: dir, strict: true, forceChown: fc }) + const unpack = new UnpackSync({ + cwd: dir, + strict: true, + forceChown: fc, + }) unpack.end(tardata) t.end() }) t.test('loose', t => { - const unpack = new Unpack.Sync({ cwd: dir, forceChown: fc }) + const unpack = new UnpackSync({ cwd: dir, forceChown: fc }) unpack.on('warn', t.fail) unpack.end(tardata) t.end() @@ -2451,7 +2684,11 @@ t.test('futimes/fchown failures', t => { t.test('async unpack', t => { t.plan(2) t.test('strict', t => { - const unpack = new Unpack({ cwd: dir, strict: true, forceChown: fc }) + const unpack = new Unpack({ + cwd: dir, + strict: true, + forceChown: fc, + }) t.plan(3) unpack.on('error', er => t.equal(er, poop)) unpack.end(tardata) @@ -2459,22 +2696,26 @@ t.test('futimes/fchown failures', t => { t.test('loose', t => { const unpack = new Unpack({ cwd: dir, forceChown: fc }) t.plan(3) - unpack.on('warn', (code, m, er) => t.equal(er, poop)) + unpack.on('warn', (_code, _m, er) => t.equal(er, poop)) unpack.end(tardata) }) }) t.test('sync unpack', t => { t.plan(2) t.test('strict', t => { - const unpack = new Unpack.Sync({ cwd: dir, strict: true, forceChown: fc }) + const unpack = new UnpackSync({ + cwd: dir, + strict: true, + forceChown: fc, + }) t.plan(3) unpack.on('error', er => t.equal(er, poop)) unpack.end(tardata) }) t.test('loose', t => { - const unpack = new Unpack.Sync({ cwd: dir, forceChown: fc }) + const unpack = new UnpackSync({ cwd: dir, forceChown: fc }) t.plan(3) - unpack.on('warn', (c, m, er) => t.equal(er, poop)) + unpack.on('warn', (_c, _m, er) => t.equal(er, poop)) unpack.end(tardata) }) }) @@ -2490,7 +2731,7 @@ t.test('onentry option is preserved', t => { t.teardown(() => rimraf(basedir)) let oecalls = 0 - const onentry = entry => oecalls++ + const onentry = _entry => oecalls++ const data = makeTar([ { path: 'd/i', @@ -2581,7 +2822,11 @@ t.test('do not reuse hardlinks, only nlink=1 files', t => { const check = t => { for (const f in checks) { - t.equal(fs.readFileSync(basedir + '/' + f, 'utf8'), checks[f], f) + t.equal( + fs.readFileSync(basedir + '/' + f, 'utf8'), + checks[f], + f, + ) t.equal(fs.statSync(basedir + '/' + f).nlink, 1, f) } t.end() @@ -2623,10 +2868,15 @@ t.test('trying to unpack a non-zlib gzip file should fail', t => { new Unpack(opts) .once('error', er => t.match(er, expect, 'async emits')) .end(dataGzip) - const skip = !/^v([0-9]|1[0-3])\./.test(process.version) ? false + const skip = !/^v([0-9]|1[0-3])\./.test(process.version) + ? false : 'node prior to v14 did not raise sync zlib errors properly' - t.throws(() => new UnpackSync(opts).end(dataGzip), - expect, 'sync throws', { skip }) + t.throws( + () => new UnpackSync(opts).end(dataGzip), + expect, + 'sync throws', + { skip }, + ) }) t.test('bad archive if no gzip', t => { @@ -2639,7 +2889,11 @@ t.test('trying to unpack a non-zlib gzip file should fail', t => { new Unpack(opts) .on('error', er => t.match(er, expect, 'async emits')) .end(data) - t.throws(() => new UnpackSync(opts).end(data), expect, 'sync throws') + t.throws( + () => new UnpackSync(opts).end(data), + expect, + 'sync throws', + ) }) t.end() @@ -2650,7 +2904,7 @@ t.test('handle errors on fs.close', t => { const { close, closeSync } = fs // have to actually close them, or else windows gets mad fs.close = (fd, cb) => close(fd, () => cb(poop)) - fs.closeSync = (fd) => { + fs.closeSync = fd => { closeSync(fd) throw poop } @@ -2676,65 +2930,77 @@ t.test('handle errors on fs.close', t => { new Unpack({ cwd: dir + '/async', strict: true }) .on('error', er => t.equal(er, poop, 'async')) .end(data) - t.throws(() => new UnpackSync({ - cwd: normPath(dir + '/sync'), strict: true, - }).end(data), poop, 'sync') + t.throws( + () => + new UnpackSync({ + cwd: normPath(dir + '/sync'), + strict: true, + }).end(data), + poop, + 'sync', + ) }) -t.test('drop entry from dirCache if no longer a directory', { - skip: isWindows && 'symlinks not fully supported', -}, t => { - const dir = path.resolve(unpackdir, 'dir-cache-error') - mkdirp.sync(dir + '/sync/y') - mkdirp.sync(dir + '/async/y') - const data = makeTar([ - { - path: 'x', - type: 'Directory', - }, - { - path: 'x', - type: 'SymbolicLink', - linkpath: './y', - }, - { - path: 'x/ginkoid', - type: 'File', - size: 'ginkoid'.length, - }, - 'ginkoid', - '', - '', - ]) - t.plan(2) - const WARNINGS = {} - const check = (t, path) => { - t.equal(fs.statSync(path + '/x').isDirectory(), true) - t.equal(fs.lstatSync(path + '/x').isSymbolicLink(), true) - t.equal(fs.statSync(path + '/y').isDirectory(), true) - t.strictSame(fs.readdirSync(path + '/y'), []) - t.throws(() => fs.readFileSync(path + '/x/ginkoid'), { code: 'ENOENT' }) - t.strictSame(WARNINGS[path], [ - 'TAR_ENTRY_ERROR', - 'Cannot extract through symbolic link', +t.test( + 'drop entry from dirCache if no longer a directory', + { + skip: isWindows && 'symlinks not fully supported', + }, + t => { + const dir = path.resolve(unpackdir, 'dir-cache-error') + mkdirp.sync(dir + '/sync/y') + mkdirp.sync(dir + '/async/y') + const data = makeTar([ + { + path: 'x', + type: 'Directory', + }, + { + path: 'x', + type: 'SymbolicLink', + linkpath: './y', + }, + { + path: 'x/ginkoid', + type: 'File', + size: 'ginkoid'.length, + }, + 'ginkoid', + '', + '', ]) - t.end() - } - t.test('async', t => { - const path = dir + '/async' - new Unpack({ cwd: path }) - .on('warn', (code, msg) => WARNINGS[path] = [code, msg]) - .on('end', () => check(t, path)) - .end(data) - }) - t.test('sync', t => { - const path = dir + '/sync' - new UnpackSync({ cwd: path }) - .on('warn', (code, msg) => WARNINGS[path] = [code, msg]) - .end(data) - check(t, path) - }) -}) + t.plan(2) + const WARNINGS = {} + const check = (t, path) => { + t.equal(fs.statSync(path + '/x').isDirectory(), true) + t.equal(fs.lstatSync(path + '/x').isSymbolicLink(), true) + t.equal(fs.statSync(path + '/y').isDirectory(), true) + t.strictSame(fs.readdirSync(path + '/y'), []) + t.throws(() => fs.readFileSync(path + '/x/ginkoid'), { + code: 'ENOENT', + }) + t.strictSame(WARNINGS[path], [ + 'TAR_ENTRY_ERROR', + 'TAR_SYMLINK_ERROR: Cannot extract through symbolic link', + ]) + t.end() + } + t.test('async', t => { + const path = dir + '/async' + new Unpack({ cwd: path }) + .on('warn', (code, msg) => (WARNINGS[path] = [code, msg])) + .on('end', () => check(t, path)) + .end(data) + }) + t.test('sync', t => { + const path = dir + '/sync' + new UnpackSync({ cwd: path }) + .on('warn', (code, msg) => (WARNINGS[path] = [code, msg])) + .end(data) + check(t, path) + }) + }, +) t.test('using strip option when top level file exists', t => { const dir = path.resolve(unpackdir, 'strip-with-top-file') @@ -2792,7 +3058,8 @@ t.test('using strip option when top level file exists', t => { t.test('handle EPERMs when creating symlinks', t => { // https://github.com/npm/node-tar/issues/265 - const msg = 'You do not have sufficient privilege to perform this operation.' + const msg = + 'You do not have sufficient privilege to perform this operation.' const er = Object.assign(new Error(msg), { code: 'EPERM', }) @@ -2838,11 +3105,15 @@ t.test('handle EPERMs when creating symlinks', t => { mkdirp.sync(`${dir}/async`) const check = path => { - t.match(WARNINGS, [ - ['TAR_ENTRY_ERROR', msg], - ['TAR_ENTRY_ERROR', msg], - ['TAR_ENTRY_ERROR', msg], - ], 'got expected warnings') + t.match( + WARNINGS, + [ + ['TAR_ENTRY_ERROR', msg], + ['TAR_ENTRY_ERROR', msg], + ['TAR_ENTRY_ERROR', msg], + ], + 'got expected warnings', + ) t.equal(WARNINGS.length, 3) WARNINGS.length = 0 t.equal(fs.readFileSync(`${path}/x/y`, 'utf8'), 'hello, world') @@ -2855,13 +3126,13 @@ t.test('handle EPERMs when creating symlinks', t => { const WARNINGS = [] const u = new Unpack({ cwd: `${dir}/async`, - onwarn: (code, msg, er) => WARNINGS.push([code, msg]), + onwarn: (code, msg, _er) => WARNINGS.push([code, msg]), }) u.on('end', () => { check(`${dir}/async`) const u = new UnpackSync({ cwd: `${dir}/sync`, - onwarn: (code, msg, er) => WARNINGS.push([code, msg]), + onwarn: (code, msg, _er) => WARNINGS.push([code, msg]), }) u.end(data) check(`${dir}/sync`) @@ -2888,8 +3159,8 @@ t.test('close fd when error writing', t => { t.teardown(mutateFS.fail('write', new Error('nope'))) const CLOSES = [] const OPENS = {} - const { open } = require('fs') - t.teardown(() => fs.open = open) + const { open } = fs + t.teardown(() => (fs.open = open)) fs.open = (...args) => { const cb = args.pop() args.push((er, fd) => { @@ -2898,10 +3169,12 @@ t.test('close fd when error writing', t => { }) return open.call(fs, ...args) } - t.teardown(mutateFS.mutateArgs('close', ([fd]) => { - CLOSES.push(fd) - return [fd] - })) + t.teardown( + mutateFS.mutateArgs('close', ([fd]) => { + CLOSES.push(fd) + return [fd] + }), + ) const WARNINGS = [] const dir = path.resolve(unpackdir, 'close-on-write-error') mkdirp.sync(dir) @@ -2941,8 +3214,8 @@ t.test('close fd when error setting mtime', t => { t.teardown(mutateFS.fail('utimes', new Error('nooooope'))) const CLOSES = [] const OPENS = {} - const { open } = require('fs') - t.teardown(() => fs.open = open) + const { open } = fs + t.teardown(() => (fs.open = open)) fs.open = (...args) => { const cb = args.pop() args.push((er, fd) => { @@ -2951,10 +3224,12 @@ t.test('close fd when error setting mtime', t => { }) return open.call(fs, ...args) } - t.teardown(mutateFS.mutateArgs('close', ([fd]) => { - CLOSES.push(fd) - return [fd] - })) + t.teardown( + mutateFS.mutateArgs('close', ([fd]) => { + CLOSES.push(fd) + return [fd] + }), + ) const WARNINGS = [] const dir = path.resolve(unpackdir, 'close-on-futimes-error') mkdirp.sync(dir) @@ -2987,7 +3262,10 @@ t.test('do not hang on large files that fail to open()', t => { '', ]) t.teardown(mutateFS.fail('open', new Error('nope'))) - const dir = path.resolve(unpackdir, 'no-hang-for-large-file-failures') + const dir = path.resolve( + unpackdir, + 'no-hang-for-large-file-failures', + ) mkdirp.sync(dir) const WARNINGS = [] const unpack = new Unpack({ @@ -2998,11 +3276,11 @@ t.test('do not hang on large files that fail to open()', t => { t.strictSame(WARNINGS, [['TAR_ENTRY_ERROR', 'nope']]) t.end() }) - unpack.write(data.slice(0, 2048)) + unpack.write(data.subarray(0, 2048)) setTimeout(() => { - unpack.write(data.slice(2048, 4096)) + unpack.write(data.subarray(2048, 4096)) setTimeout(() => { - unpack.write(data.slice(4096)) + unpack.write(data.subarray(4096)) setTimeout(() => { unpack.end() }) @@ -3010,165 +3288,178 @@ t.test('do not hang on large files that fail to open()', t => { }) }) -t.test('dirCache pruning unicode normalized collisions', { - skip: isWindows && 'symlinks not fully supported', -}, t => { - const data = makeTar([ - { - type: 'Directory', - path: 'foo', - }, - { - type: 'File', - path: 'foo/bar', - size: 1, - }, - 'x', - { - type: 'Directory', - // cafeˁ - path: Buffer.from([0x63, 0x61, 0x66, 0xc3, 0xa9]).toString(), - }, - { - type: 'SymbolicLink', - // cafe with a ` - path: Buffer.from([0x63, 0x61, 0x66, 0x65, 0xcc, 0x81]).toString(), - linkpath: 'foo', - }, - { - type: 'Directory', - path: 'foo', - }, - { - type: 'File', - path: Buffer.from([0x63, 0x61, 0x66, 0xc3, 0xa9]).toString() + '/bar', - size: 1, - }, - 'y', - '', - '', - ]) - - const check = (path, dirCache, t) => { - path = path.replace(/\\/g, '/') - t.strictSame([...dirCache.entries()][0], [`${path}/foo`, true]) - t.equal(fs.readFileSync(path + '/foo/bar', 'utf8'), 'x') - t.end() - } - - t.test('sync', t => { - const path = t.testdir() - const dirCache = new Map() - new UnpackSync({ cwd: path, dirCache }).end(data) - check(path, dirCache, t) - }) - t.test('async', t => { - const path = t.testdir() - const dirCache = new Map() - new Unpack({ cwd: path, dirCache }) - .on('close', () => check(path, dirCache, t)) - .end(data) - }) +t.test( + 'dirCache pruning unicode normalized collisions', + { + skip: isWindows && 'symlinks not fully supported', + }, + t => { + const data = makeTar([ + { + type: 'Directory', + path: 'foo', + }, + { + type: 'File', + path: 'foo/bar', + size: 1, + }, + 'x', + { + type: 'Directory', + // cafeˁ + path: Buffer.from([0x63, 0x61, 0x66, 0xc3, 0xa9]).toString(), + }, + { + type: 'SymbolicLink', + // cafe with a ` + path: Buffer.from([ + 0x63, 0x61, 0x66, 0x65, 0xcc, 0x81, + ]).toString(), + linkpath: 'foo', + }, + { + type: 'Directory', + path: 'foo', + }, + { + type: 'File', + path: + Buffer.from([0x63, 0x61, 0x66, 0xc3, 0xa9]).toString() + + '/bar', + size: 1, + }, + 'y', + '', + '', + ]) - t.end() -}) + const check = (path, dirCache, t) => { + path = path.replace(/\\/g, '/') + t.strictSame([...dirCache.entries()][0], [`${path}/foo`, true]) + t.equal(fs.readFileSync(path + '/foo/bar', 'utf8'), 'x') + t.end() + } -t.test('dircache prune all on windows when symlink encountered', t => { - if (process.platform !== 'win32') { - process.env.TESTING_TAR_FAKE_PLATFORM = 'win32' - t.teardown(() => { - delete process.env.TESTING_TAR_FAKE_PLATFORM + t.test('sync', t => { + const path = t.testdir() + const dirCache = new Map() + new UnpackSync({ cwd: path, dirCache }).end(data) + check(path, dirCache, t) + }) + t.test('async', t => { + const path = t.testdir() + const dirCache = new Map() + new Unpack({ cwd: path, dirCache }) + .on('close', () => check(path, dirCache, t)) + .end(data) }) - } - const symlinks = [] - const Unpack = t.mock('../lib/unpack.js', { - fs: { - ...fs, - symlink: (target, dest, cb) => { - symlinks.push(['async', target, dest]) - process.nextTick(cb) - }, - symlinkSync: (target, dest) => symlinks.push(['sync', target, dest]), - }, - }) - const UnpackSync = Unpack.Sync - const data = makeTar([ - { - type: 'Directory', - path: 'foo', - }, - { - type: 'File', - path: 'foo/bar', - size: 1, - }, - 'x', - { - type: 'Directory', - // cafeˁ - path: Buffer.from([0x63, 0x61, 0x66, 0xc3, 0xa9]).toString(), - }, - { - type: 'SymbolicLink', - // cafe with a ` - path: Buffer.from([0x63, 0x61, 0x66, 0x65, 0xcc, 0x81]).toString(), - linkpath: 'safe/actually/but/cannot/be/too/careful', - }, - { - type: 'File', - path: 'bar/baz', - size: 1, - }, - 'z', - '', - '', - ]) + t.end() + }, +) + +t.test( + 'dircache prune all on windows when symlink encountered', + async t => { + if (process.platform !== 'win32') { + process.env.TESTING_TAR_FAKE_PLATFORM = 'win32' + t.teardown(() => { + delete process.env.TESTING_TAR_FAKE_PLATFORM + }) + } + const symlinks = [] + const { Unpack } = await t.mockImport('../dist/esm/unpack.js', { + fs: { + ...fs, + symlink: (target, dest, cb) => { + symlinks.push(['async', target, dest]) + process.nextTick(cb) + }, + symlinkSync: (target, dest) => + symlinks.push(['sync', target, dest]), + }, + }) - const check = (path, dirCache, t) => { - // symlink blew away all dirCache entries before it - path = path.replace(/\\/g, '/') - t.strictSame([...dirCache.entries()], [ - [`${path}/bar`, true], + const data = makeTar([ + { + type: 'Directory', + path: 'foo', + }, + { + type: 'File', + path: 'foo/bar', + size: 1, + }, + 'x', + { + type: 'Directory', + // cafeˁ + path: Buffer.from([0x63, 0x61, 0x66, 0xc3, 0xa9]).toString(), + }, + { + type: 'SymbolicLink', + // cafe with a ` + path: Buffer.from([ + 0x63, 0x61, 0x66, 0x65, 0xcc, 0x81, + ]).toString(), + linkpath: 'safe/actually/but/cannot/be/too/careful', + }, + { + type: 'File', + path: 'bar/baz', + size: 1, + }, + 'z', + '', + '', ]) - t.equal(fs.readFileSync(`${path}/foo/bar`, 'utf8'), 'x') - t.equal(fs.readFileSync(`${path}/bar/baz`, 'utf8'), 'z') - t.end() - } - t.test('sync', t => { - const path = t.testdir() - const dirCache = new Map() - new UnpackSync({ cwd: path, dirCache }).end(data) - check(path, dirCache, t) - }) + const check = (path, dirCache, t) => { + // symlink blew away all dirCache entries before it + path = path.replace(/\\/g, '/') + t.strictSame([...dirCache.entries()], [[`${path}/bar`, true]]) + t.equal(fs.readFileSync(`${path}/foo/bar`, 'utf8'), 'x') + t.equal(fs.readFileSync(`${path}/bar/baz`, 'utf8'), 'z') + t.end() + } - t.test('async', t => { - const path = t.testdir() - const dirCache = new Map() - new Unpack({ cwd: path, dirCache }) - .on('close', () => check(path, dirCache, t)) - .end(data) - }) + t.test('sync', t => { + const path = t.testdir() + const dirCache = new Map() + new UnpackSync({ cwd: path, dirCache }).end(data) + check(path, dirCache, t) + }) - t.end() -}) + t.test('async', t => { + const path = t.testdir() + const dirCache = new Map() + new Unpack({ cwd: path, dirCache }) + .on('close', () => check(path, dirCache, t)) + .end(data) + }) -t.test('recognize C:.. as a dot path part', t => { + t.end() + }, +) + +t.test('recognize C:.. as a dot path part', async t => { if (process.platform !== 'win32') { process.env.TESTING_TAR_FAKE_PLATFORM = 'win32' t.teardown(() => { delete process.env.TESTING_TAR_FAKE_PLATFORM }) } - const Unpack = t.mock('../lib/unpack.js', { - path: { - ...path.win32, - win32: path.win32, - posix: path.posix, + const { Unpack, UnpackSync } = await t.mockImport( + '../dist/esm/unpack.js', + { + path: { + ...path.win32, + win32: path.win32, + posix: path.posix, + }, }, - }) - const UnpackSync = Unpack.Sync + ) const data = makeTar([ { @@ -3202,7 +3493,12 @@ t.test('recognize C:.. as a dot path part', t => { 'C:../x/y/z', 'C:../x/y/z', ], - ['TAR_ENTRY_ERROR', "path contains '..'", 'x:../y/z', 'x:../y/z'], + [ + 'TAR_ENTRY_ERROR', + "path contains '..'", + 'x:../y/z', + 'x:../y/z', + ], [ 'TAR_ENTRY_INFO', 'stripping Y: from absolute path', @@ -3218,7 +3514,8 @@ t.test('recognize C:.. as a dot path part', t => { const path = t.testdir() new Unpack({ cwd: path, - onwarn: (c, w, { entry, path }) => warnings.push([c, w, path, entry.path]), + onwarn: (c, w, { entry, path }) => + warnings.push([c, w, path, entry.path]), }) .on('close', () => check(path, warnings, t)) .end(data) @@ -3229,7 +3526,8 @@ t.test('recognize C:.. as a dot path part', t => { const path = t.testdir() new UnpackSync({ cwd: path, - onwarn: (c, w, { entry, path }) => warnings.push([c, w, path, entry.path]), + onwarn: (c, w, { entry, path }) => + warnings.push([c, w, path, entry.path]), }).end(data) check(path, warnings, t) }) @@ -3246,15 +3544,16 @@ t.test('excessively deep subfolder nesting', async t => { const check = (t, maxDepth = 1024) => { t.match(warnings, [ - ['TAR_ENTRY_ERROR', + [ + 'TAR_ENTRY_ERROR', 'path excessively deep', { entry: ReadEntry, path: /^\.(\/a){1024,}\/foo.txt$/, depth: 222372, maxDepth, - } - ] + }, + ], ]) warnings.length = 0 t.end() @@ -3264,15 +3563,17 @@ t.test('excessively deep subfolder nesting', async t => { const cwd = t.testdir() new Unpack({ cwd, - onwarn - }).on('end', () => check(t)).end(data) + onwarn, + }) + .on('end', () => check(t)) + .end(data) }) t.test('sync', t => { const cwd = t.testdir() new UnpackSync({ cwd, - onwarn + onwarn, }).end(data) check(t) }) @@ -3283,7 +3584,9 @@ t.test('excessively deep subfolder nesting', async t => { cwd, onwarn, maxDepth: 64, - }).on('end', () => check(t, 64)).end(data) + }) + .on('end', () => check(t, 64)) + .end(data) }) t.test('sync set md', t => { diff --git a/test/update.js b/test/update.js index 7034a165..9fb57b6f 100644 --- a/test/update.js +++ b/test/update.js @@ -1,24 +1,27 @@ -'use strict' -const t = require('tap') -const u = require('../lib/update.js') -const path = require('path') -const fs = require('fs') -const mutateFS = require('mutate-fs') - -const { resolve } = require('path') +import t from 'tap' +import { update as u } from '../dist/esm/update.js' + +import path, {dirname} from 'path' +import fs from 'fs' +import mutateFS from 'mutate-fs' + +import { resolve } from 'path' +import {fileURLToPath} from 'url' +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) const fixtures = path.resolve(__dirname, 'fixtures') const tars = path.resolve(fixtures, 'tars') -const zlib = require('zlib') +import zlib from 'zlib' +import { spawn } from 'child_process' -const spawn = require('child_process').spawn const data = fs.readFileSync(tars + '/body-byte-counts.tar') -const dataNoNulls = data.slice(0, data.length - 1024) +const dataNoNulls = data.subarray(0, data.length - 1024) const fixtureDef = { 'body-byte-counts.tar': data, 'no-null-eof.tar': dataNoNulls, - 'truncated-head.tar': Buffer.concat([dataNoNulls, data.slice(0, 500)]), - 'truncated-body.tar': Buffer.concat([dataNoNulls, data.slice(0, 700)]), + 'truncated-head.tar': Buffer.concat([dataNoNulls, data.subarray(0, 500)]), + 'truncated-body.tar': Buffer.concat([dataNoNulls, data.subarray(0, 700)]), 'zero.tar': Buffer.from(''), 'empty.tar': Buffer.alloc(512), 'compressed.tgz': zlib.gzipSync(data), diff --git a/test/warn-mixin.js b/test/warn-method.js similarity index 81% rename from test/warn-mixin.js rename to test/warn-method.js index 36350e47..4d040f42 100644 --- a/test/warn-mixin.js +++ b/test/warn-method.js @@ -1,8 +1,13 @@ -const t = require('tap') -const EE = require('events').EventEmitter -const warner = require('../lib/warn-mixin.js') +import t from 'tap' +import EE from 'events' +import { warnMethod } from '../dist/esm/warn-method.js' + +class Warner extends EE { + warn(code, message, data = {}) { + return warnMethod(this, code, message, data) + } +} -const Warner = warner(EE) const w = new Warner() diff --git a/test/winchars.js b/test/winchars.js index 120c581d..b1ffe12c 100644 --- a/test/winchars.js +++ b/test/winchars.js @@ -1,6 +1,5 @@ -'use strict' -const t = require('tap') -const wc = require('../lib/winchars.js') +import t from 'tap' +import * as wc from '../dist/esm/winchars.js' t.equal(wc.encode('<>'), '\uf03c\uf03e', 'encode') t.equal(wc.decode(wc.encode('<>')), '<>', 'decode') diff --git a/test/write-entry.js b/test/write-entry.js index b72e53a1..27bd364c 100644 --- a/test/write-entry.js +++ b/test/write-entry.js @@ -1,9 +1,27 @@ -'use strict' -const t = require('tap') -const mkdirp = require('mkdirp') +import t from 'tap' +import { mkdirp } from 'mkdirp' +import fs from 'fs' +import { ReadEntry } from '../dist/esm/read-entry.js' +import { makeTar } from './fixtures/make-tar.js' +import { + WriteEntry, + WriteEntrySync, + WriteEntryTar, +} from '../dist/esm/write-entry.js' +import path, { dirname } from 'path' +import { Header } from '../dist/esm/header.js' +import mutateFS from 'mutate-fs' +import { Parser } from '../dist/esm/parse.js' +import { rimraf } from 'rimraf' +import { normalizeWindowsPath as normPath } from '../dist/esm/normalize-windows-path.js' +import { fileURLToPath } from 'url' + +const { default: chmodr } = await import('chmodr') + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) // make our tests verify that windows link targets get turned into / paths -const fs = require('fs') const { readlink, readlinkSync } = fs fs.readlink = (path, cb) => { readlink(path, (er, path) => { @@ -16,20 +34,10 @@ fs.readlink = (path, cb) => { } fs.readlinkSync = path => readlinkSync(path).replace(/\//g, '\\') -const ReadEntry = require('../lib/read-entry.js') -const makeTar = require('./make-tar.js') -const WriteEntry = require('../lib/write-entry.js') -const path = require('path') const fixtures = path.resolve(__dirname, 'fixtures') const files = path.resolve(fixtures, 'files') -const Header = require('../lib/header.js') -const mutateFS = require('mutate-fs') process.env.USER = 'isaacs' -const chmodr = require('chmodr') -const Parser = require('../lib/parse.js') -const rimraf = require('rimraf') const isWindows = process.platform === 'win32' -const normPath = require('../lib/normalize-windows-path.js') t.test('set up', t => { const one = fs.statSync(files + '/hardlink-1') @@ -49,7 +57,8 @@ t.test('100 byte filename', t => { t.plan(2) const runTest = t => { - const f = '100-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' + const f = + '100-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' const ws = new WriteEntry(f, { cwd: files, linkCache: linkCache, @@ -75,7 +84,7 @@ t.test('100 byte filename', t => { }, }) - const wss = new WriteEntry.Sync(f, { + const wss = new WriteEntrySync(f, { cwd: files, linkCache: linkCache, statCache: statCache, @@ -83,8 +92,10 @@ t.test('100 byte filename', t => { linkCache = ws.linkCache statCache = ws.statCache - t.equal(out.slice(512).toString('hex'), - wss.read().slice(512).toString('hex')) + t.equal( + out.slice(512).toString('hex'), + wss.read().subarray(512).toString('hex'), + ) t.equal(out.length, 1024) t.equal(out.slice(0, 100).toString(), f) @@ -102,23 +113,25 @@ t.test('100 byte filename', t => { devmin: 0, }) - t.equal(out.slice(512).toString('hex'), + t.equal( + out.slice(512).toString('hex'), '6363636363636363636363636363636363636363636363636363636363636363' + - '6363636363636363636363636363636363636363636363636363636363636363' + - '6363636363636363636363636363636363636363636363636363636363636363' + - '6363636300000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000') + '6363636363636363636363636363636363636363636363636363636363636363' + + '6363636363636363636363636363636363636363636363636363636363636363' + + '6363636300000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000', + ) t.end() }) @@ -151,7 +164,7 @@ t.test('directory', t => { }) t.equal(out.length, 512) - const wss = new WriteEntry.Sync('dir', { cwd: files }) + const wss = new WriteEntrySync('dir', { cwd: files }) t.equal(wss.read().length, 512) t.match(wss.header, { cksumValid: true, @@ -193,34 +206,38 @@ t.test('empty path for cwd', t => { }) }) -t.test('symlink', { - skip: isWindows && 'symlinks not fully supported', -}, t => { - const ws = new WriteEntry('symlink', { cwd: files }) - let out = [] - ws.on('data', c => out.push(c)) - const header = { - cksumValid: true, - needPax: false, - path: 'symlink', - size: 0, - linkpath: 'hardlink-2', - uname: 'isaacs', - gname: null, - devmaj: 0, - devmin: 0, - } +t.test( + 'symlink', + { + skip: isWindows && 'symlinks not fully supported', + }, + t => { + const ws = new WriteEntry('symlink', { cwd: files }) + let out = [] + ws.on('data', c => out.push(c)) + const header = { + cksumValid: true, + needPax: false, + path: 'symlink', + size: 0, + linkpath: 'hardlink-2', + uname: 'isaacs', + gname: null, + devmaj: 0, + devmin: 0, + } - const wss = new WriteEntry.Sync('symlink', { cwd: files }) - t.match(wss.header, header) + const wss = new WriteEntrySync('symlink', { cwd: files }) + t.match(wss.header, header) - ws.on('end', _ => { - out = Buffer.concat(out) - t.equal(out.length, 512) - t.match(ws.header, header) - t.end() - }) -}) + ws.on('end', _ => { + out = Buffer.concat(out) + t.equal(out.length, 512) + t.match(ws.header, header) + t.end() + }) + }, +) t.test('zero-byte file', t => { const ws = new WriteEntry('files/zero-byte.txt', { cwd: fixtures }) @@ -253,7 +270,8 @@ t.test('zero-byte file, but close fails', t => { const ws = new WriteEntry('files/1024-bytes.txt', { cwd: fixtures }) ws.on('end', _ => - t.fail('should not get an end, because the close fails')) + t.fail('should not get an end, because the close fails'), + ) ws.on('error', er => { t.match(er, { message: 'poop' }) @@ -263,7 +281,7 @@ t.test('zero-byte file, but close fails', t => { }) t.test('hardlinks', t => { - const wss = new WriteEntry.Sync('hardlink-1', { + const wss = new WriteEntrySync('hardlink-1', { cwd: files, }) @@ -298,7 +316,9 @@ t.test('hardlinks far away', t => { const h1 = 'hardlink-1' const f = path.resolve(files, h1) const stat = fs.statSync(f) - const linkCache = new Map([[stat.dev + ':' + stat.ino, '/a/b/c/d/e']]) + const linkCache = new Map([ + [stat.dev + ':' + stat.ino, '/a/b/c/d/e'], + ]) const ws = new WriteEntry('files/hardlink-2', { cwd: fixtures, @@ -327,7 +347,8 @@ t.test('hardlinks far away', t => { }) t.test('really deep path', t => { - const f = 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' + const f = + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' const ws = new WriteEntry(f, { cwd: files }) let out = [] ws.on('data', c => out.push(c)) @@ -352,7 +373,8 @@ t.test('really deep path', t => { }) t.test('no pax', t => { - const f = 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' + const f = + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' const ws = new WriteEntry(f, { cwd: files, noPax: true }) let out = [] ws.on('data', c => out.push(c)) @@ -381,7 +403,7 @@ t.test('nonexistent file', t => { const ws = new WriteEntry('does not exist', { cwd: files }) ws.on('error', er => { t.match(er, { - message: 'ENOENT: no such file or directory, lstat \'' + f + '\'', + message: "ENOENT: no such file or directory, lstat '" + f + "'", code: 'ENOENT', path: f, syscall: 'lstat', @@ -395,7 +417,7 @@ t.test('absolute path', t => { const { root } = path.parse(absolute) const f = root + root + root + absolute const warn = normPath(isWindows ? root : root + root + root + root) - t.test('preservePaths=false strict=false', t => { + t.test('preservePaths=false strict=false warn='+warn, t => { const warnings = [] // on windows, c:\c:\c:\... is a valid path, so just use the // single-root absolute version of it. @@ -408,11 +430,13 @@ t.test('absolute path', t => { ws.on('end', _ => { out = Buffer.concat(out) t.equal(out.length, 1024) - t.match(warnings, [[ - 'TAR_ENTRY_INFO', - `stripping ${warn} from absolute path`, - { path: normPath(isWindows ? absolute : f) }, - ]]) + t.match(warnings, [ + [ + 'TAR_ENTRY_INFO', + `stripping ${warn} from absolute path`, + { path: normPath(isWindows ? absolute : f) }, + ], + ]) t.match(ws.header, { cksumValid: true, @@ -467,22 +491,25 @@ t.test('absolute path', t => { }) t.test('preservePaths=false strict=true', t => { - t.throws(_ => { - new WriteEntry(isWindows ? absolute : f, { - strict: true, - cwd: files, - }) - }, { - message: /stripping .* from absolute path/, - path: normPath(isWindows ? absolute : f), - }) + t.throws( + _ => { + new WriteEntry(isWindows ? absolute : f, { + strict: true, + cwd: files, + }) + }, + { + message: /stripping .* from absolute path/, + path: normPath(isWindows ? absolute : f), + }, + ) t.end() }) t.end() }) -t.throws(_ => new WriteEntry(null), new TypeError('path is required')) +t.throws(() => new WriteEntry(null), TypeError) t.test('no user environ, sets uname to empty string', t => { delete process.env.USER @@ -508,31 +535,35 @@ t.test('no user environ, sets uname to empty string', t => { }) }) -t.test('an unsuppored type', { - skip: isWindows && '/dev/random on windows', -}, t => { - const ws = new WriteEntry('/dev/random', { preservePaths: true }) - ws.on('data', c => { - throw new Error('should not get data from random') - }) - ws.on('stat', stat => { - t.match(stat, { - dev: Number, - mode: 0o020666, - nlink: 1, - rdev: Number, - blksize: Number, - ino: Number, - size: 0, - blocks: 0, +t.test( + 'an unsuppored type', + { + skip: isWindows && '/dev/random on windows', + }, + t => { + const ws = new WriteEntry('/dev/random', { preservePaths: true }) + ws.on('data', (_chunk) => { + throw new Error('should not get data from random') }) - t.ok(stat.isCharacterDevice(), 'random is a character device') - }) - ws.on('end', _ => { - t.match(ws, { type: 'Unsupported', path: '/dev/random' }) - t.end() - }) -}) + ws.on('stat', stat => { + t.match(stat, { + dev: Number, + mode: 0o020666, + nlink: 1, + rdev: Number, + blksize: Number, + ino: Number, + size: 0, + blocks: 0, + }) + t.ok(stat.isCharacterDevice(), 'random is a character device') + }) + ws.on('end', _ => { + t.match(ws, { type: 'Unsupported', path: '/dev/random' }) + t.end() + }) + }, +) t.test('readlink fail', t => { const expect = { @@ -542,23 +573,31 @@ t.test('readlink fail', t => { // pretend everything is a symbolic link, then read something that isn't t.teardown(mutateFS.statType('SymbolicLink')) t.throws(_ => { - return new WriteEntry.Sync('write-entry.js', { cwd: __dirname }) + return new WriteEntrySync('write-entry.js', { cwd: __dirname }) }, expect) - new WriteEntry('write-entry.js', { cwd: __dirname }).on('error', er => { - t.match(er, expect) - t.equal(normPath(er.path), normPath(__filename)) - t.end() - }) + new WriteEntry('write-entry.js', { cwd: __dirname }).on( + 'error', + er => { + t.match(er, expect) + t.equal(normPath(er.path), normPath(__filename)) + t.end() + }, + ) }) t.test('open fail', t => { t.teardown(mutateFS.fail('open', new Error('pwn'))) - t.throws(_ => new WriteEntry.Sync('write-entry.js', { cwd: __dirname }), - { message: 'pwn' }) - new WriteEntry('write-entry.js', { cwd: __dirname }).on('error', er => { - t.match(er, { message: 'pwn' }) - t.end() - }) + t.throws( + _ => new WriteEntrySync('write-entry.js', { cwd: __dirname }), + { message: 'pwn' }, + ) + new WriteEntry('write-entry.js', { cwd: __dirname }).on( + 'error', + er => { + t.match(er, { message: 'pwn' }) + t.end() + }, + ) }) t.test('read fail', t => { @@ -568,16 +607,22 @@ t.test('read fail', t => { syscall: 'read', } // pretend everything is a file, then read something that isn't - t.teardown(mutateFS.statMutate((er, st) => { - if (er) { - return [er, st] - } - st.isFile = () => true - st.size = 123 - })) - t.throws(_ => new WriteEntry.Sync('fixtures', { - cwd: __dirname, - }), expect) + t.teardown( + mutateFS.statMutate((er, st) => { + if (er) { + return [er, st] + } + st.isFile = () => true + st.size = 123 + }), + ) + t.throws( + _ => + new WriteEntrySync('fixtures', { + cwd: __dirname, + }), + expect, + ) new WriteEntry('fixtures', { cwd: __dirname }).on('error', er => { t.match(er, expect) t.end() @@ -585,27 +630,34 @@ t.test('read fail', t => { }) t.test('read invalid EOF', t => { - t.teardown(mutateFS.mutate('read', (er, br) => [er, 0])) + t.teardown(mutateFS.mutate('read', (er, _bytesRead) => [er, 0])) const expect = { message: 'encountered unexpected EOF', path: normPath(__filename), syscall: 'read', code: 'EOF', } - t.throws(_ => new WriteEntry.Sync('write-entry.js', { cwd: __dirname }), - expect) - new WriteEntry('write-entry.js', { cwd: __dirname }).on('error', er => { - t.match(er, expect) - t.end() - }) + t.throws( + _ => new WriteEntrySync('write-entry.js', { cwd: __dirname }), + expect, + ) + new WriteEntry('write-entry.js', { cwd: __dirname }).on( + 'error', + er => { + t.match(er, expect) + t.end() + }, + ) }) t.test('read overflow expectation', t => { - t.teardown(mutateFS.statMutate((er, st) => { - if (st) { - st.size = 3 - } - })) + t.teardown( + mutateFS.statMutate((_er, st) => { + if (st) { + st.size = 3 + } + }), + ) const f = '512-bytes.txt' const expect = { message: 'did not encounter expected EOF', @@ -614,17 +666,23 @@ t.test('read overflow expectation', t => { code: 'EOF', } t.plan(2) - t.throws(_ => new WriteEntry.Sync(f, { cwd: files, maxReadSize: 2 }), expect) - new WriteEntry(f, { cwd: files, maxReadSize: 2 }).on('error', er => { - t.match(er, expect) - }).resume() + t.throws( + _ => new WriteEntrySync(f, { cwd: files, maxReadSize: 2 }), + expect, + ) + new WriteEntry(f, { cwd: files, maxReadSize: 2 }) + .on('error', er => { + t.match(er, expect) + }) + .resume() }) t.test('short reads', t => { t.teardown(mutateFS.zenoRead()) const cases = { '1024-bytes.txt': new Array(1024).join('x') + '\n', - '100-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': new Array(101).join('c'), + '100-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': + new Array(101).join('c'), } const maxReadSize = [null, 1024, 100, 111] @@ -642,12 +700,21 @@ t.test('short reads', t => { ws.on('data', c => out.push(c)) ws.on('end', _ => { out = Buffer.concat(out) - t.equal(out.length, 512 * Math.ceil(1 + contents.length / 512)) - t.equal(out.slice(512).toString().replace(/\0.*$/, ''), contents) - const wss = new WriteEntry.Sync(filename, { cwd: files }) + t.equal( + out.length, + 512 * Math.ceil(1 + contents.length / 512), + ) + t.equal( + out.slice(512).toString().replace(/\0.*$/, ''), + contents, + ) + const wss = new WriteEntrySync(filename, { cwd: files }) const syncOut = wss.read() t.equal(syncOut.length, out.length) - t.equal(syncOut.slice(512).toString(), out.slice(512).toString()) + t.equal( + syncOut.subarray(512).toString(), + out.slice(512).toString(), + ) t.end() }) }) @@ -658,53 +725,67 @@ t.test('short reads', t => { t.end() }) -t.test('win32 path conversion', { - skip: isWindows && 'no need to test on windows', -}, t => { - const ws = new WriteEntry('long-path\\r', { - cwd: files, - win32: true, - }) - t.equal(ws.path, 'long-path/r') - t.end() -}) - -t.test('win32 <|>? in paths', { - skip: isWindows && 'do not create annoying junk on windows systems', -}, t => { - const file = path.resolve(fixtures, '<|>?.txt') - const uglyName = Buffer.from('ef80bcef81bcef80beef80bf2e747874', 'hex').toString() - const ugly = path.resolve(fixtures, uglyName) - t.teardown(_ => { - rimraf.sync(file) - rimraf.sync(ugly) - }) +t.test( + 'win32 path conversion', + { + skip: isWindows && 'no need to test on windows', + }, + t => { + const ws = new WriteEntry('long-path\\r', { + cwd: files, + win32: true, + }) + t.equal(ws.path, 'long-path/r') + t.end() + }, +) + +t.test( + 'win32 <|>? in paths', + { + skip: + isWindows && 'do not create annoying junk on windows systems', + }, + t => { + const file = path.resolve(fixtures, '<|>?.txt') + const uglyName = Buffer.from( + 'ef80bcef81bcef80beef80bf2e747874', + 'hex', + ).toString() + const ugly = path.resolve(fixtures, uglyName) + t.teardown(_ => { + rimraf.sync(file) + rimraf.sync(ugly) + }) - fs.writeFileSync(ugly, '<|>?') + fs.writeFileSync(ugly, '<|>?') - const wc = new WriteEntry(uglyName, { - cwd: fixtures, - win32: true, - }) + const wc = new WriteEntry(uglyName, { + cwd: fixtures, + win32: true, + }) - const out = [] - wc.on('data', c => out.push(c)) - wc.on('end', _ => { - const data = Buffer.concat(out).toString() - t.equal(data.slice(0, 4), '<|>?') - t.end() - }) + const out = [] + wc.on('data', c => out.push(c)) + wc.on('end', _ => { + const data = Buffer.concat(out).toString() + t.equal(data.slice(0, 4), '<|>?') + t.end() + }) - t.equal(wc.path, '<|>?.txt') - t.equal(wc.absolute, ugly) -}) + t.equal(wc.path, '<|>?.txt') + t.equal(wc.absolute, ugly) + }, +) t.test('uid doesnt match, dont set uname', t => { - t.teardown(mutateFS.statMutate((er, st) => { - if (st) { - st.uid -= 1 - } - })) + t.teardown( + mutateFS.statMutate((_er, st) => { + if (st) { + st.uid -= 1 + } + }), + ) const ws = new WriteEntry('long-path/r', { cwd: files, }) @@ -721,17 +802,17 @@ t.test('override absolute to some other file', t => { ws.on('end', _ => { const data = Buffer.concat(out) t.equal(data.length, 1024) - t.match(data.slice(512).toString(), /^a\0{511}$/) + t.match(data.subarray(512).toString(), /^a\0{511}$/) t.match(ws, { path: 'blerg', header: { size: 1 }, }) - const wss = new WriteEntry.Sync('blerg', { + const wss = new WriteEntrySync('blerg', { absolute: files + '/one-byte.txt', }) const sdata = wss.read() t.equal(sdata.length, 1024) - t.match(sdata.slice(512).toString(), /^a\0{511}$/) + t.match(sdata.subarray(512).toString(), /^a\0{511}$/) t.match(wss, { path: 'blerg', header: { size: 1 }, @@ -741,7 +822,8 @@ t.test('override absolute to some other file', t => { }) t.test('portable entries, nothing platform-specific', t => { - const om = 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt' + const om = + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt' const ws = new WriteEntry(om, { cwd: files, portable: true, @@ -775,7 +857,7 @@ t.test('portable entries, nothing platform-specific', t => { } const ps = new Parser() - const wss = new WriteEntry.Sync(om, { + const wss = new WriteEntrySync(om, { cwd: files, portable: true, }) @@ -795,7 +877,8 @@ t.test('portable entries, nothing platform-specific', t => { }) t.test('no mtime', t => { - const om = 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt' + const om = + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt' const ws = new WriteEntry(om, { cwd: files, noMtime: true, @@ -832,7 +915,7 @@ t.test('no mtime', t => { } const ps = new Parser() - const wss = new WriteEntry.Sync(om, { + const wss = new WriteEntrySync(om, { cwd: files, portable: true, noMtime: true, @@ -853,7 +936,8 @@ t.test('no mtime', t => { }) t.test('force mtime', t => { - const om = 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt' + const om = + 'long-path/r/e/a/l/l/y/-/d/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/Ί.txt' const date = new Date('1979-07-01T19:10:00.000Z') const ws = new WriteEntry(om, { cwd: files, @@ -891,7 +975,7 @@ t.test('force mtime', t => { } const ps = new Parser() - const wss = new WriteEntry.Sync(om, { + const wss = new WriteEntrySync(om, { cwd: files, portable: true, mtime: new Date('1979-07-01T19:10:00.000Z'), @@ -930,7 +1014,7 @@ t.test('portable dir entries, no mtime', t => { } const ps = new Parser() - const wss = new WriteEntry.Sync(dir, { + const wss = new WriteEntrySync(dir, { cwd: files, portable: true, }) @@ -985,19 +1069,19 @@ t.test('write entry from read entry', t => { t.test('basic file', t => { const fileEntry = new ReadEntry(new Header(data)) - const wetFile = new WriteEntry.Tar(fileEntry) + const wetFile = new WriteEntryTar(fileEntry) const out = [] let wetFileEnded = false wetFile.on('data', c => out.push(c)) - wetFile.on('end', _ => wetFileEnded = true) - fileEntry.write(data.slice(512, 550)) - fileEntry.write(data.slice(550, 1000)) - fileEntry.end(data.slice(1000, 1024)) + wetFile.on('end', _ => (wetFileEnded = true)) + fileEntry.write(data.subarray(512, 550)) + fileEntry.write(data.subarray(550, 1000)) + fileEntry.end(data.subarray(1000, 1024)) t.equal(wetFileEnded, true) const result = Buffer.concat(out) t.equal(result.length, 1024) t.equal(result.toString().replace(/\0.*$/, ''), '$') - const body = result.slice(512).toString().replace(/\0*$/, '') + const body = result.subarray(512).toString().replace(/\0*$/, '') t.equal(body, '$$$$$$$$$$') t.end() }) @@ -1019,11 +1103,11 @@ t.test('write entry from read entry', t => { '', ]) const fileEntry = new ReadEntry(new Header(data)) - const wetFile = new WriteEntry.Tar(fileEntry, { portable: true }) + const wetFile = new WriteEntryTar(fileEntry, { portable: true }) const out = [] let wetFileEnded = false wetFile.on('data', c => out.push(c)) - wetFile.on('end', _ => wetFileEnded = true) + wetFile.on('end', _ => (wetFileEnded = true)) fileEntry.end() t.equal(wetFileEnded, true) const result = Buffer.concat(out) @@ -1034,19 +1118,19 @@ t.test('write entry from read entry', t => { t.test('with pax header', t => { const fileEntryPax = new ReadEntry(new Header(data)) fileEntryPax.path = new Array(200).join('$') - const wetPax = new WriteEntry.Tar(fileEntryPax) + const wetPax = new WriteEntryTar(fileEntryPax) let wetPaxEnded = false const out = [] wetPax.on('data', c => out.push(c)) - wetPax.on('end', _ => wetPaxEnded = true) - fileEntryPax.write(data.slice(512, 550)) - fileEntryPax.write(data.slice(550, 1000)) - fileEntryPax.end(data.slice(1000, 1024)) + wetPax.on('end', _ => (wetPaxEnded = true)) + fileEntryPax.write(data.subarray(512, 550)) + fileEntryPax.write(data.subarray(550, 1000)) + fileEntryPax.end(data.subarray(1000, 1024)) t.equal(wetPaxEnded, true) const result = Buffer.concat(out) t.equal(result.length, 2048) - t.match(result.slice(1024, 1124).toString(), /^\$+\0?$/) - const body = result.slice(1536).toString().replace(/\0*$/, '') + t.match(result.subarray(1024, 1124).toString(), /^\$+\0?$/) + const body = result.subarray(1536).toString().replace(/\0*$/, '') t.match(new Header(result), { type: 'ExtendedHeader' }) t.equal(body, '$$$$$$$$$$') t.end() @@ -1055,26 +1139,28 @@ t.test('write entry from read entry', t => { t.test('pax and portable', t => { const fileEntryPax = new ReadEntry(new Header(data)) fileEntryPax.path = new Array(200).join('$') - const wetPax = new WriteEntry.Tar(fileEntryPax, { portable: true }) + const wetPax = new WriteEntryTar(fileEntryPax, { + portable: true, + }) let wetPaxEnded = false const out = [] wetPax.on('data', c => out.push(c)) - wetPax.on('end', _ => wetPaxEnded = true) - fileEntryPax.write(data.slice(512, 550)) - fileEntryPax.write(data.slice(550, 1000)) - fileEntryPax.end(data.slice(1000, 1024)) + wetPax.on('end', _ => (wetPaxEnded = true)) + fileEntryPax.write(data.subarray(512, 550)) + fileEntryPax.write(data.subarray(550, 1000)) + fileEntryPax.end(data.subarray(1000, 1024)) t.equal(wetPaxEnded, true) const result = Buffer.concat(out) t.equal(result.length, 2048) - t.match(result.slice(1024, 1124).toString(), /^\$+\0?$/) + t.match(result.subarray(1024, 1124).toString(), /^\$+\0?$/) t.match(new Header(result), { type: 'ExtendedHeader' }) - t.match(new Header(result.slice(1024)), { + t.match(new Header(result.subarray(1024)), { ctime: null, atime: null, uname: '', gname: '', }) - const body = result.slice(1536).toString().replace(/\0*$/, '') + const body = result.subarray(1536).toString().replace(/\0*$/, '') t.equal(body, '$$$$$$$$$$') t.end() }) @@ -1082,30 +1168,30 @@ t.test('write entry from read entry', t => { t.test('pax, portable, and noMtime', t => { const fileEntryPax = new ReadEntry(new Header(data)) fileEntryPax.path = new Array(200).join('$') - const wetPax = new WriteEntry.Tar(fileEntryPax, { + const wetPax = new WriteEntryTar(fileEntryPax, { noMtime: true, portable: true, }) let wetPaxEnded = false const out = [] wetPax.on('data', c => out.push(c)) - wetPax.on('end', _ => wetPaxEnded = true) - fileEntryPax.write(data.slice(512, 550)) - fileEntryPax.write(data.slice(550, 1000)) - fileEntryPax.end(data.slice(1000, 1024)) + wetPax.on('end', _ => (wetPaxEnded = true)) + fileEntryPax.write(data.subarray(512, 550)) + fileEntryPax.write(data.subarray(550, 1000)) + fileEntryPax.end(data.subarray(1000, 1024)) t.equal(wetPaxEnded, true) const result = Buffer.concat(out) t.equal(result.length, 2048) - t.match(result.slice(1024, 1124).toString(), /^\$+\0?$/) + t.match(result.subarray(1024, 1124).toString(), /^\$+\0?$/) t.match(new Header(result), { type: 'ExtendedHeader' }) - t.match(new Header(result.slice(1024)), { + t.match(new Header(result.subarray(1024)), { mtime: null, ctime: null, atime: null, uname: '', gname: '', }) - const body = result.slice(1536).toString().replace(/\0*$/, '') + const body = result.subarray(1536).toString().replace(/\0*$/, '') t.equal(body, '$$$$$$$$$$') t.end() }) @@ -1116,18 +1202,22 @@ t.test('write entry from read entry', t => { t.test('warn', t => { const warnings = [] - new WriteEntry.Tar(fileEntry, { + new WriteEntryTar(fileEntry, { onwarn: (code, msg, data) => warnings.push(code, msg, data), }) - t.match(warnings, ['TAR_ENTRY_INFO', 'stripping / from absolute path', { - path: '/a/b/c', - }]) + t.match(warnings, [ + 'TAR_ENTRY_INFO', + 'stripping / from absolute path', + { + path: '/a/b/c', + }, + ]) t.end() }) t.test('preserve', t => { const warnings = [] - new WriteEntry.Tar(fileEntry, { + new WriteEntryTar(fileEntry, { onwarn: (code, msg, data) => warnings.push(code, msg, data), preservePaths: true, }) @@ -1136,41 +1226,48 @@ t.test('write entry from read entry', t => { }) t.test('throw', t => { - t.throws(_ => new WriteEntry.Tar(fileEntry, { - strict: true, - })) + t.throws( + _ => + new WriteEntryTar(fileEntry, { + strict: true, + }), + ) t.end() }) t.end() }) t.test('no block remain', t => { - const readEntry = new ReadEntry(new Header({ - size: 512, - type: 'File', - path: 'x', - })) - const wet = new WriteEntry.Tar(readEntry) + const readEntry = new ReadEntry( + new Header({ + size: 512, + type: 'File', + path: 'x', + }), + ) + const wet = new WriteEntryTar(readEntry) const out = [] wet.on('data', c => out.push(c)) let wetEnded = false - wet.on('end', _ => wetEnded = true) + wet.on('end', _ => (wetEnded = true)) t.equal(wetEnded, false) readEntry.end(Buffer.from(new Array(513).join('@'))) t.equal(wetEnded, true) const res = Buffer.concat(out) t.equal(res.length, 1024) - t.match(res.slice(512).toString(), /^@+$/) + t.match(res.subarray(512).toString(), /^@+$/) t.end() }) t.test('write more than appropriate', t => { - const readEntry = new ReadEntry(new Header({ - path: 'x', - type: 'File', - size: '1', - })) - const wet = new WriteEntry.Tar(readEntry) + const readEntry = new ReadEntry( + new Header({ + path: 'x', + type: 'File', + size: '1', + }), + ) + const wet = new WriteEntryTar(readEntry) t.throws(_ => wet.write(Buffer.from(new Array(1024).join('x')))) t.end() }) @@ -1212,7 +1309,9 @@ t.test('prefix and hard links', t => { path: 'PaxHeader/yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy', type: 'ExtendedHeader', }, - new RegExp('^266 path=out.x.' + long + '[\\w\\W]*linkpath=out.x.target'), + new RegExp( + '^266 path=out.x.' + long + '[\\w\\W]*linkpath=out.x.target', + ), { path: 'out/x/yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy', type: 'Link', @@ -1251,11 +1350,11 @@ t.test('prefix and hard links', t => { const data = Buffer.concat(out) expect.forEach((e, i) => { if (typeof e === 'string') { - t.equal(data.slice(i * 512, i * 512 + e.length).toString(), e) + t.equal(data.subarray(i * 512, i * 512 + e.length).toString(), e) } else if (e instanceof RegExp) { - t.match(data.slice(i * 512, (i + 1) * 512).toString(), e) + t.match(data.subarray(i * 512, (i + 1) * 512).toString(), e) } else { - t.match(new Header(data.slice(i * 512, (i + 1) * 512)), e) + t.match(new Header(data.subarray(i * 512, (i + 1) * 512)), e) } }) } @@ -1271,11 +1370,12 @@ t.test('prefix and hard links', t => { statCache, } const out = [] - const entry = (path) => new Promise(resolve => { - const p = new Class(path, opt) - p.on('end', resolve) - p.on('data', d => out.push(d)) - }) + const entry = path => + new Promise(resolve => { + const p = new Class(path, opt) + p.on('end', resolve) + p.on('data', d => out.push(d)) + }) await entry(path) if (path === '.') { @@ -1299,8 +1399,8 @@ t.test('prefix and hard links', t => { }) t.test('sync', t => { - t.test('.', t => runTest(t, '.', WriteEntry.Sync)) - return t.test('./', t => runTest(t, './', WriteEntry.Sync)) + t.test('.', t => runTest(t, '.', WriteEntrySync)) + return t.test('./', t => runTest(t, './', WriteEntrySync)) }) t.end() @@ -1328,7 +1428,9 @@ t.test('prefix and hard links from tar entries', t => { path: 'PaxHeader/yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy', type: 'ExtendedHeader', }, - new RegExp('^266 path=out.x.' + long + '[\\w\\W]*linkpath=out.x.target'), + new RegExp( + '^266 path=out.x.' + long + '[\\w\\W]*linkpath=out.x.target', + ), { path: 'out/x/yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy', type: 'Link', @@ -1425,16 +1527,16 @@ t.test('prefix and hard links from tar entries', t => { const data = Buffer.concat(out) expect.forEach((e, i) => { if (typeof e === 'string') { - t.equal(data.slice(i * 512, i * 512 + e.length).toString(), e) + t.equal(data.subarray(i * 512, i * 512 + e.length).toString(), e) } else if (e instanceof RegExp) { - t.match(data.slice(i * 512, (i + 1) * 512).toString(), e) + t.match(data.subarray(i * 512, (i + 1) * 512).toString(), e) } else { - t.match(new Header(data.slice(i * 512, (i + 1) * 512)), e) + t.match(new Header(data.subarray(i * 512, (i + 1) * 512)), e) } }) } - const runTest = async (t, path) => { + const runTest = async (t, _path) => { const linkCache = new Map() const statCache = new Map() const opt = { @@ -1447,7 +1549,7 @@ t.test('prefix and hard links from tar entries', t => { const parser = new Parser({ strict: true, onentry: readEntry => { - const p = new WriteEntry.Tar(readEntry, opt) + const p = new WriteEntryTar(readEntry, opt) p.on('data', d => out.push(d)) }, }) @@ -1520,9 +1622,9 @@ t.test('hard links and no prefix', t => { const data = Buffer.concat(out) expect.forEach((e, i) => { if (typeof e === 'string') { - t.equal(data.slice(i * 512, i * 512 + e.length).toString(), e) + t.equal(data.subarray(i * 512, i * 512 + e.length).toString(), e) } else { - t.match(new Header(data.slice(i * 512, (i + 1) * 512)), e) + t.match(new Header(data.subarray(i * 512, (i + 1) * 512)), e) } }) } @@ -1536,11 +1638,12 @@ t.test('hard links and no prefix', t => { statCache, } const out = [] - const entry = (path) => new Promise(resolve => { - const p = new Class(path, opt) - p.on('end', resolve) - p.on('data', d => out.push(d)) - }) + const entry = path => + new Promise(resolve => { + const p = new Class(path, opt) + p.on('end', resolve) + p.on('data', d => out.push(d)) + }) await entry(path) if (path === '.') { @@ -1563,8 +1666,8 @@ t.test('hard links and no prefix', t => { }) t.test('sync', t => { - t.test('.', t => runTest(t, '.', WriteEntry.Sync)) - return t.test('./', t => runTest(t, './', WriteEntry.Sync)) + t.test('.', t => runTest(t, '.', WriteEntrySync)) + return t.test('./', t => runTest(t, './', WriteEntrySync)) }) t.end() @@ -1665,16 +1768,16 @@ t.test('hard links from tar entries and no prefix', t => { const data = Buffer.concat(out) expect.forEach((e, i) => { if (typeof e === 'string') { - t.equal(data.slice(i * 512, i * 512 + e.length).toString(), e) + t.equal(data.subarray(i * 512, i * 512 + e.length).toString(), e) } else if (e instanceof RegExp) { - t.match(data.slice(i * 512, (i + 1) * 512).toString(), e) + t.match(data.subarray(i * 512, (i + 1) * 512).toString(), e) } else { - t.match(new Header(data.slice(i * 512, (i + 1) * 512)), e) + t.match(new Header(data.subarray(i * 512, (i + 1) * 512)), e) } }) } - const runTest = async (t, path) => { + const runTest = async (t, _path) => { const linkCache = new Map() const statCache = new Map() const opt = { @@ -1685,7 +1788,7 @@ t.test('hard links from tar entries and no prefix', t => { const out = [] const parser = new Parser({ onentry: readEntry => { - const p = new WriteEntry.Tar(readEntry, opt) + const p = new WriteEntryTar(readEntry, opt) p.on('data', d => out.push(d)) }, }) From 734434c3e8e8e4c87cfb12e6c8df2252540a99c1 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 10 Apr 2024 08:51:07 -0700 Subject: [PATCH 62/96] changelog v7, flip default chmod behavior The `noChmod` option is deprecated, and replaced with the `chmod` option. The default is now to *not* explicitly set the mode of created filesystem entries. This is a deviation from `tar(1)` implementations, but prevents the need to call `process.umask()`, which is deprecated and not thread safe. To still set modes explicitly, while avoiding the need to call `process.umask()`, a `processUmask` numeric option may now be provided along with `chmod: true`. --- CHANGELOG.md | 37 +++++- README.md | 45 +++++--- package.json | 55 +++++++++ src/mkdir.ts | 1 - src/options.ts | 292 +++++++++++++++++++++++++++++++++++++++--------- src/unpack.ts | 16 +-- test/options.js | 3 + test/unpack.js | 38 ++++--- 8 files changed, 389 insertions(+), 98 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4b27a7a..c8c81472 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,26 +1,51 @@ # Changelog +## 7.0 + +- Rewrite in TypeScript, provide ESM and CommonJS hybrid + interface +- Add tree-shake friendly exports, like `import('tar/create')` + and `import('tar/read-entry')` to get individual functions or + classes. +- Add `chmod` option that defaults to false, and deprecate + `noChmod`. That is, reverse the default option regarding + explicitly setting file system modes to match tar entry + settings. +- Add `processUmask` option to avoid having to call + `process.umask()` when `chmod: true` (or `noChmod: false`) is + set. + ## 6.2 -* Add support for brotli compression +- Add support for brotli compression +- Add `maxDepth` option to prevent extraction into excessively + deep folders. + +## 6.1.15 + +- Normalize unicode internally using NFD + +## 6.1.14 + +- Update minipass dependency ## [6.1.13](https://github.com/npm/node-tar/compare/v6.1.12...v6.1.13) (2022-12-07) ### Dependencies -* [`cc4e0dd`](https://github.com/npm/node-tar/commit/cc4e0ddfe523a0bce383846a67442c637a65d486) [#343](https://github.com/npm/node-tar/pull/343) bump minipass from 3.3.6 to 4.0.0 +- [`cc4e0dd`](https://github.com/npm/node-tar/commit/cc4e0ddfe523a0bce383846a67442c637a65d486) [#343](https://github.com/npm/node-tar/pull/343) bump minipass from 3.3.6 to 4.0.0 ## [6.1.12](https://github.com/npm/node-tar/compare/v6.1.11...v6.1.12) (2022-10-31) ### Bug Fixes -* [`57493ee`](https://github.com/npm/node-tar/commit/57493ee66ece50d62114e02914282fc37be3a91a) [#332](https://github.com/npm/node-tar/pull/332) ensuring close event is emited after stream has ended (@webark) -* [`b003c64`](https://github.com/npm/node-tar/commit/b003c64f624332e24e19b30dc011069bb6708680) [#314](https://github.com/npm/node-tar/pull/314) replace deprecated String.prototype.substr() (#314) (@CommanderRoot, @lukekarrys) +- [`57493ee`](https://github.com/npm/node-tar/commit/57493ee66ece50d62114e02914282fc37be3a91a) [#332](https://github.com/npm/node-tar/pull/332) ensuring close event is emited after stream has ended (@webark) +- [`b003c64`](https://github.com/npm/node-tar/commit/b003c64f624332e24e19b30dc011069bb6708680) [#314](https://github.com/npm/node-tar/pull/314) replace deprecated String.prototype.substr() (#314) (@CommanderRoot, @lukekarrys) ### Documentation -* [`f129929`](https://github.com/npm/node-tar/commit/f12992932f171ea248b27fad95e7d489a56d31ed) [#313](https://github.com/npm/node-tar/pull/313) remove dead link to benchmarks (#313) (@yetzt) -* [`c1faa9f`](https://github.com/npm/node-tar/commit/c1faa9f44001dfb0bc7638b2850eb6058bd56a4a) add examples/explanation of using tar.t (@isaacs) +- [`f129929`](https://github.com/npm/node-tar/commit/f12992932f171ea248b27fad95e7d489a56d31ed) [#313](https://github.com/npm/node-tar/pull/313) remove dead link to benchmarks (#313) (@yetzt) +- [`c1faa9f`](https://github.com/npm/node-tar/commit/c1faa9f44001dfb0bc7638b2850eb6058bd56a4a) add examples/explanation of using tar.t (@isaacs) ## 6.0 diff --git a/README.md b/README.md index 296229c5..971638ab 100644 --- a/README.md +++ b/README.md @@ -156,12 +156,13 @@ to see how tar is handling the issue. The API mimics the `tar(1)` command line functionality, with aliases for more human-readable option and function names. The goal is that if you know how to use `tar(1)` in Unix, then you know how to use -`require('tar')` in JavaScript. +`import('tar')` in JavaScript. To replicate `tar czf my-tarball.tgz files and folders`, you'd do: ```js -tar.c( +import { create } from 'tar' +create( { gzip: <true|gzip options>, file: 'my-tarball.tgz' @@ -173,9 +174,12 @@ tar.c( To replicate `tar cz files and folders > my-tarball.tgz`, you'd do: ```js -tar.c( // or tar.create +// if you're familiar with the tar(1) cli flags, this can be nice +import * as tar from 'tar' +tar.c( { - gzip: <true|gzip options> + // 'z' is alias for 'gzip' option + z: <true|gzip options> }, ['some', 'files', 'and', 'folders'] ).pipe(fs.createWriteStream('my-tarball.tgz')) @@ -184,9 +188,10 @@ tar.c( // or tar.create To replicate `tar xf my-tarball.tgz` you'd do: ```js -tar.x( // or tar.extract( +tar.x( // or `tar.extract` { - file: 'my-tarball.tgz' + // or `file:` + f: 'my-tarball.tgz' } ).then(_=> { .. tarball has been dumped in cwd .. }) ``` @@ -424,11 +429,15 @@ The following options are supported: that passes the filter. - `onwarn` A function that will get called with `(code, message, data)` for any warnings encountered. (See "Warnings and Errors") -- `noChmod` Set to true to omit calling `fs.chmod()` to ensure that the - extracted file matches the entry mode. This also suppresses the call to - `process.umask()` to determine the default umask value, since tar will - extract with whatever mode is provided, and let the process `umask` apply - normally. +- `chmod` Set to true to call `fs.chmod()` to ensure that the + extracted file matches the entry mode. This may necessitate a + call to the deprecated and thread-unsafe `process.umask()` + method to determine the default umask value, unless a + `processUmask` options is also provided. Otherwise tar will + extract with whatever mode is provided, and let the process + `umask` apply normally. +- `processUmask` Set to an explicit numeric value to avoid + calling `process.umask()` when `chmod: true` is set. - `maxDepth` The maximum depth of subfolders to extract into. This defaults to 1024. Anything deeper than the limit will raise a warning and skip the entry. Set to `Infinity` to remove the @@ -751,11 +760,15 @@ Most unpack errors will cause a `warn` event to be emitted. If the that passes the filter. - `onwarn` A function that will get called with `(code, message, data)` for any warnings encountered. (See "Warnings and Errors") -- `noChmod` Set to true to omit calling `fs.chmod()` to ensure that the - extracted file matches the entry mode. This also suppresses the call to - `process.umask()` to determine the default umask value, since tar will - extract with whatever mode is provided, and let the process `umask` apply - normally. +- `chmod` Set to true to call `fs.chmod()` to ensure that the + extracted file matches the entry mode. This may necessitate a + call to the deprecated and thread-unsafe `process.umask()` + method to determine the default umask value, unless a + `processUmask` options is also provided. Otherwise tar will + extract with whatever mode is provided, and let the process + `umask` apply normally. +- `processUmask` Set to an explicit numeric value to avoid + calling `process.umask()` when `chmod: true` is set. - `maxDepth` The maximum depth of subfolders to extract into. This defaults to 1024. Anything deeper than the limit will raise a warning and skip the entry. Set to `Infinity` to remove the diff --git a/package.json b/package.json index 57eaf9a1..4090358b 100644 --- a/package.json +++ b/package.json @@ -66,11 +66,16 @@ "exports": { "./package.json": "./package.json", ".": "./src/index.ts", + "./c": "./src/create.ts", "./create": "./src/create.ts", "./replace": "./src/create.ts", + "./r": "./src/create.ts", "./list": "./src/list.ts", + "./t": "./src/list.ts", "./update": "./src/update.ts", + "./u": "./src/update.ts", "./extract": "./src/extract.ts", + "./x": "./src/extract.ts", "./pack": "./src/pack.ts", "./unpack": "./src/unpack.ts", "./parse": "./src/parse.ts", @@ -93,6 +98,16 @@ "default": "./dist/commonjs/index.js" } }, + "./c": { + "import": { + "types": "./dist/esm/create.d.ts", + "default": "./dist/esm/create.js" + }, + "require": { + "types": "./dist/commonjs/create.d.ts", + "default": "./dist/commonjs/create.js" + } + }, "./create": { "import": { "types": "./dist/esm/create.d.ts", @@ -113,6 +128,16 @@ "default": "./dist/commonjs/create.js" } }, + "./r": { + "import": { + "types": "./dist/esm/create.d.ts", + "default": "./dist/esm/create.js" + }, + "require": { + "types": "./dist/commonjs/create.d.ts", + "default": "./dist/commonjs/create.js" + } + }, "./list": { "import": { "types": "./dist/esm/list.d.ts", @@ -123,6 +148,16 @@ "default": "./dist/commonjs/list.js" } }, + "./t": { + "import": { + "types": "./dist/esm/list.d.ts", + "default": "./dist/esm/list.js" + }, + "require": { + "types": "./dist/commonjs/list.d.ts", + "default": "./dist/commonjs/list.js" + } + }, "./update": { "import": { "types": "./dist/esm/update.d.ts", @@ -133,6 +168,16 @@ "default": "./dist/commonjs/update.js" } }, + "./u": { + "import": { + "types": "./dist/esm/update.d.ts", + "default": "./dist/esm/update.js" + }, + "require": { + "types": "./dist/commonjs/update.d.ts", + "default": "./dist/commonjs/update.js" + } + }, "./extract": { "import": { "types": "./dist/esm/extract.d.ts", @@ -143,6 +188,16 @@ "default": "./dist/commonjs/extract.js" } }, + "./x": { + "import": { + "types": "./dist/esm/extract.d.ts", + "default": "./dist/esm/extract.js" + }, + "require": { + "types": "./dist/commonjs/extract.d.ts", + "default": "./dist/commonjs/extract.js" + } + }, "./pack": { "import": { "types": "./dist/esm/pack.d.ts", diff --git a/src/mkdir.ts b/src/mkdir.ts index cf98d1ac..f65c98ef 100644 --- a/src/mkdir.ts +++ b/src/mkdir.ts @@ -17,7 +17,6 @@ export type MkdirOptions = { cache: Map<string, boolean> cwd: string mode: number - noChmod: boolean } export type MkdirError = diff --git a/src/options.ts b/src/options.ts index a612f142..fe33ac46 100644 --- a/src/options.ts +++ b/src/options.ts @@ -38,6 +38,9 @@ const argmap = new Map<keyof TarOptionsWithAliases, keyof TarOptions>( * Aliases are provided in the {@link TarOptionsWithAliases} type. */ export interface TarOptions { + ////////////////////////// + // shared options + /** * Perform all I/O operations synchronously. If the stream is ended * immediately, then it will be processed entirely synchronously. @@ -92,7 +95,52 @@ export interface TarOptions { preservePaths?: boolean /** - * When extracting, unlink files before creating them. Without this option, + * When extracting, do not set the `mtime` value for extracted entries to + * match the `mtime` in the archive. + * + * When creating archives, do not store the `mtime` value in the entry. Note + * that this prevents properly using other mtime-based features (such as + * `tar.update` or the `newer` option) with the resulting archive. + */ + noMtime?: boolean + + /** + * Set to `true` or an object with settings for `zlib.BrotliCompress()` to + * create a brotli-compressed archive + * + * When extracting, this will cause the archive to be treated as a + * brotli-compressed file if set to `true` or a ZlibOptions object. + * + * If set `false`, then brotli options will not be used. + * + * If both this and the `gzip` option are left `undefined`, then tar will + * attempt to infer the brotli compression status, but can only do so based + * on the filename. If the filename ends in `.tbr` or `.tar.br`, and the + * first 512 bytes are not a valid tar header, then brotli decompression + * will be attempted. + */ + brotli?: boolean | ZlibOptions + + /** + * A function that is called with `(path, stat)` when creating an archive, or + * `(path, entry)` when extracting. Return true to process the file/entry, or + * false to exclude it. + */ + filter?: (path: string, entry: Stats | ReadEntry) => boolean + + /** + * A function that gets called for any warning encountered. + * + * Note: if `strict` is set, then the warning will throw, and this method + * will not be called. + */ + onwarn?: (code: string, message: string, data: WarnData) => any + + ////////////////////////// + // extraction options + + /** + * When extracting, unlink files before creating them. Without this option, * tar overwrites existing files, which preserves existing hardlinks. With * this option, existing hardlinks will be broken, as will any symlink that * would affect the location of an extracted file. @@ -103,6 +151,8 @@ export interface TarOptions { * When extracting, strip the specified number of path portions from the * entry path. For example, with `{strip: 2}`, the entry `a/b/c/d` would be * extracted to `{cwd}/c/d`. + * + * Any entry whose entire path is stripped will be excluded. */ strip?: number @@ -118,54 +168,26 @@ export interface TarOptions { keep?: boolean /** - * When extracting, do not set the `mtime` value for extracted entries to - * match the `mtime` in the archive. - * - * When creating archives, do not store the `mtime` value in the entry. Note - * that this prevents properly using other mtime-based features (such as - * `tar.update` or the `newer` option) with the resulting archive. - */ - noMtime?: boolean - - /** - * Set the `uid` and `gid` of extracted entries to the `uid` and `gid` fields - * in the archive. Defaults to true when run as root, and false otherwise. + * When extracting, set the `uid` and `gid` of extracted entries to the `uid` + * and `gid` fields in the archive. Defaults to true when run as root, and + * false otherwise. * * If false, then files and directories will be set with the owner and group - * of the user running the process. This is similar to `-p` in `tar(1)`, but + * of the user running the process. This is similar to `-p` in `tar(1)`, but * ACLs and other system-specific data is never unpacked in this * implementation, and modes are set by default already. */ preserveOwner?: boolean /** - * Pack the targets of symbolic links rather than the link itself. - */ - follow?: boolean - - /** - * Set to `true` or an object with settings for `zlib.BrotliCompress()` to - * create a brotli-compressed archive - */ - brotli?: boolean | ZlibOptions - - /** - * A function that is called with `(path, stat)` when creating an archive, or - * `(path, entry)` when unpacking. Return true to process the file/entry, or - * false to exclude it. - */ - filter?: (path: string, entry: Stats | ReadEntry) => boolean - - /** - * A function that gets called for any warning encountered. - * - * Note: if `strict` is set, then the warning will throw, and this method - * will not be called. + * The maximum depth of subfolders to extract into. This defaults to 1024. + * Anything deeper than the limit will raise a warning and skip the entry. + * Set to `Infinity` to remove the limitation. */ - onwarn?: (code: string, message: string, data: WarnData) => any + maxDepth?: number /** - * When unpacking, force all created files and directories, and all + * When extracting, force all created files and directories, and all * implicitly created directories, to be owned by the specified user id, * regardless of the `uid` field in the archive. * @@ -175,7 +197,7 @@ export interface TarOptions { uid?: number /** - * When unpacking, force all created files and directories, and all + * When extracting, force all created files and directories, and all * implicitly created directories, to be owned by the specified group id, * regardless of the `gid` field in the archive. * @@ -201,27 +223,55 @@ export interface TarOptions { transform?: (entry: ReadEntry) => any /** - * The maximum depth of subfolders to extract into. This defaults to 1024. - * Anything deeper than the limit will raise a warning and skip the entry. - * Set to `Infinity` to remove the limitation. + * Call `chmod()` to ensure that extracted files match the entry's mode + * field. Without this field set, all mode fields in archive entries are a + * best effort attempt only. + * + * Setting this necessitates a call to the deprecated `process.umask()` + * method to determine the default umask value, unless a `processUmask` + * config is provided as well. + * + * If not set, tar will attempt to create file system entries with whatever + * mode is provided, and let the implicit process `umask` apply normally, but + * if a file already exists to be written to, then its existing mode will not + * be modified. + * + * When setting `chmod: true`, it is highly recommend to set the + * {@link TarOptions#processUmask} option as well, to avoid the call to the + * deprecated (and thread-unsafe) `process.umask()` method. */ - maxDepth?: number + chmod?: boolean /** - * Do not call `chmod()` to ensure that extracted files match the entry's - * mode field. This also suppresses the call to `process.umask()` to - * determine the default umask value, since tar will extract with whatever - * mode is provided, and let the process `umask` apply normally. + * When setting the {@link TarOptions#noChmod} option to `false`, you may + * provide a value here to avoid having to call the deprecated and + * thread-unsafe `process.umask()` method. + * + * This has no effect with `noChmod` is not set to false explicitly, as + * mode values are not set explicitly anyway. If `noChmod` is set to `false`, + * and a value is not provided here, then `process.umask()` must be called, + * which will result in deprecation warnings. + * + * The most common values for this are `0o22` (resulting in directories + * created with mode `0o755` and files with `0o644` by default) and `0o2` + * (resulting in directores created with mode `0o775` and files `0o664`, so + * they are group-writable). */ - noChmod?: boolean + processUmask?: number + + ////////////////////////// + // archive creation options /** * When parsing/listing archives, `entry` streams are by default resumed * (set into "flowing" mode) immediately after the call to `onentry()`. - * Set to suppress this behavior. + * Set `noResume: true` to suppress this behavior. * * Note that when this is set, the stream will never complete until the * data is consumed somehow. + * + * Set automatically in extract operations, since the entry is piped to + * a file system entry right away. Only relevant when parsing. */ noResume?: boolean @@ -234,6 +284,11 @@ export interface TarOptions { */ onentry?: (entry: ReadEntry) => any + /** + * Pack the targets of symbolic links rather than the link itself. + */ + follow?: boolean + /** * When creating archives, omit any metadata that is system-specific: * `ctime`, `atime`, `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and @@ -256,9 +311,9 @@ export interface TarOptions { noDirRecurse?: boolean /** - * Suppress Pax extended headers. Note that this means long paths and - * linkpaths will be truncated, and large or negative numeric values may be - * interpreted incorrectly. + * Suppress Pax extended headers when creating archives. Note that this means + * long paths and linkpaths will be truncated, and large or negative numeric + * values may be interpreted incorrectly. */ noPax?: boolean @@ -266,6 +321,10 @@ export interface TarOptions { * Set to a `Date` object to force a specific `mtime` value for everything * written to an archive. * + * This is useful when creating archives that are intended to be + * deterministic based on their contents, irrespective of the file's last + * modification time. + * * Overridden by `noMtime`. */ mtime?: Date @@ -278,6 +337,9 @@ export interface TarOptions { /** * The mode to set on any created file archive, defaults to 0o666 * masked by the process umask, often resulting in 0o644. + * + * This does *not* affect the mode fields of individual entries, or the + * mode status of extracted entries on the filesystem. */ mode?: number @@ -286,6 +348,7 @@ export interface TarOptions { /** * A cache of mtime values, to avoid having to stat the same file repeatedly. + * * @internal */ mtimeCache?: Map<string, Date> @@ -305,7 +368,8 @@ export interface TarOptions { umask?: number /** - * default mode for directories + * Default mode for directories. Used for all implicitly created directories, + * and any directories in the archive that do not have a mode field. * * @internal */ @@ -366,7 +430,7 @@ export interface TarOptions { /** * Automatically set to true on Windows systems. * - * When unpacking, causes behavior where filenames containing `<|>?:` + * When extracting, causes behavior where filenames containing `<|>?:` * characters are converted to windows-compatible escape sequences in the * created filesystem entries. * @@ -411,25 +475,140 @@ export type TarOptionsSyncFile = TarOptionsSync & TarOptionsFile export type LinkCacheKey = `${number}:${number}` export interface TarOptionsWithAliases extends TarOptions { + /** + * The effective current working directory for this tar command + */ C?: TarOptions['cwd'] + /** + * The tar file to be read and/or written. When this is set, a stream + * is not returned. Asynchronous commands will return a promise indicating + * when the operation is completed, and synchronous commands will return + * immediately. + */ f?: TarOptions['file'] + /** + * When creating a tar archive, this can be used to compress it as well. + * Set to `true` to use the default gzip options, or customize them as + * needed. + * + * When reading, if this is unset, then the compression status will be + * inferred from the archive data. This is generally best, unless you are + * sure of the compression settings in use to create the archive, and want to + * fail if the archive doesn't match expectations. + */ z?: TarOptions['gzip'] + /** + * When creating archives, preserve absolute and `..` paths in the archive, + * rather than sanitizing them under the cwd. + * + * When extracting, allow absolute paths, paths containing `..`, and + * extracting through symbolic links. By default, the root `/` is stripped + * from absolute paths (eg, turning `/x/y/z` into `x/y/z`), paths containing + * `..` are not extracted, and any file whose location would be modified by a + * symbolic link is not extracted. + * + * **WARNING** This is almost always unsafe, and must NEVER be used on + * archives from untrusted sources, such as user input, and every entry must + * be validated to ensure it is safe to write. Even if the input is not + * malicious, mistakes can cause a lot of damage! + */ P?: TarOptions['preservePaths'] + /** + * When extracting, unlink files before creating them. Without this option, + * tar overwrites existing files, which preserves existing hardlinks. With + * this option, existing hardlinks will be broken, as will any symlink that + * would affect the location of an extracted file. + */ U?: TarOptions['unlink'] + /** + * When extracting, strip the specified number of path portions from the + * entry path. For example, with `{strip: 2}`, the entry `a/b/c/d` would be + * extracted to `{cwd}/c/d`. + */ 'strip-components'?: TarOptions['strip'] + /** + * When extracting, strip the specified number of path portions from the + * entry path. For example, with `{strip: 2}`, the entry `a/b/c/d` would be + * extracted to `{cwd}/c/d`. + */ stripComponents?: TarOptions['strip'] + /** + * When extracting, keep the existing file on disk if it's newer than the + * file in the archive. + */ 'keep-newer'?: TarOptions['newer'] + /** + * When extracting, keep the existing file on disk if it's newer than the + * file in the archive. + */ keepNewer?: TarOptions['newer'] + /** + * When extracting, keep the existing file on disk if it's newer than the + * file in the archive. + */ 'keep-newer-files'?: TarOptions['newer'] + /** + * When extracting, keep the existing file on disk if it's newer than the + * file in the archive. + */ keepNewerFiles?: TarOptions['newer'] + /** + * When extracting, do not overwrite existing files at all. + */ k?: TarOptions['keep'] + /** + * When extracting, do not overwrite existing files at all. + */ 'keep-existing'?: TarOptions['keep'] + /** + * When extracting, do not overwrite existing files at all. + */ keepExisting?: TarOptions['keep'] + /** + * When extracting, do not set the `mtime` value for extracted entries to + * match the `mtime` in the archive. + * + * When creating archives, do not store the `mtime` value in the entry. Note + * that this prevents properly using other mtime-based features (such as + * `tar.update` or the `newer` option) with the resulting archive. + */ m?: TarOptions['noMtime'] + /** + * When extracting, do not set the `mtime` value for extracted entries to + * match the `mtime` in the archive. + * + * When creating archives, do not store the `mtime` value in the entry. Note + * that this prevents properly using other mtime-based features (such as + * `tar.update` or the `newer` option) with the resulting archive. + */ 'no-mtime'?: TarOptions['noMtime'] + /** + * When extracting, set the `uid` and `gid` of extracted entries to the `uid` + * and `gid` fields in the archive. Defaults to true when run as root, and + * false otherwise. + * + * If false, then files and directories will be set with the owner and group + * of the user running the process. This is similar to `-p` in `tar(1)`, but + * ACLs and other system-specific data is never unpacked in this + * implementation, and modes are set by default already. + */ p?: TarOptions['preserveOwner'] + /** + * Pack the targets of symbolic links rather than the link itself. + */ L?: TarOptions['follow'] + /** + * Pack the targets of symbolic links rather than the link itself. + */ h?: TarOptions['follow'] + + /** + * Deprecated option. Set explicitly false to set `chmod: true`. Ignored + * if {@link TarOptions#chmod} is set to any boolean value. + * + * @deprecated + */ + noChmod?: boolean } export type TarOptionsWithAliasesSync = TarOptionsWithAliases & { @@ -469,5 +648,10 @@ export const dealias = ( const k = dealiasKey(key) result[k] = v } + // affordance for deprecated noChmod -> chmod + if (result.chmod === undefined && result.noChmod === false) { + result.chmod = true + } + delete result.noChmod return result as TarOptions } diff --git a/src/unpack.ts b/src/unpack.ts index 26e857cc..933975ff 100644 --- a/src/unpack.ts +++ b/src/unpack.ts @@ -172,7 +172,7 @@ export class Unpack extends Parser { umask: number dmode: number fmode: number - noChmod: boolean + chmod: boolean constructor(opt: TarOptions = {}) { opt.ondone = () => { @@ -185,7 +185,7 @@ export class Unpack extends Parser { this.transform = opt.transform this.dirCache = opt.dirCache || new Map() - this.noChmod = !!opt.noChmod + this.chmod = !!opt.chmod if (typeof opt.uid === 'number' || typeof opt.gid === 'number') { // need both or neither @@ -269,7 +269,11 @@ export class Unpack extends Parser { ) this.strip = Number(opt.strip) || 0 // if we're not chmodding, then we don't need the process umask - this.processUmask = opt.noChmod ? 0 : process.umask() + this.processUmask = !this.chmod + ? 0 + : typeof opt.processUmask === 'number' + ? opt.processUmask + : process.umask() this.umask = typeof opt.umask === 'number' ? opt.umask : this.processUmask @@ -469,7 +473,6 @@ export class Unpack extends Parser { cache: this.dirCache, cwd: this.cwd, mode: mode, - noChmod: this.noChmod, }, cb, ) @@ -777,7 +780,7 @@ export class Unpack extends Parser { if (st.isDirectory()) { if (entry.type === 'Directory') { const needChmod = - !this.noChmod && + this.chmod && entry.mode && (st.mode & 0o7777) !== entry.mode const afterChmod = (er?: Error | null | undefined) => @@ -931,7 +934,7 @@ export class UnpackSync extends Unpack { if (st.isDirectory()) { if (entry.type === 'Directory') { const needChmod = - !this.noChmod && + this.chmod && entry.mode && (st.mode & 0o7777) !== entry.mode const [er] = needChmod @@ -1088,7 +1091,6 @@ export class UnpackSync extends Unpack { cache: this.dirCache, cwd: this.cwd, mode: mode, - noChmod: this.noChmod, }) } catch (er) { return er diff --git a/test/options.js b/test/options.js index 5e10df5b..7aa01caf 100644 --- a/test/options.js +++ b/test/options.js @@ -51,6 +51,9 @@ t.same( }, ) +t.same(dealias({ noChmod: false }), { chmod: true }) +t.same(dealias({ noChmod: true }), {}) + t.equal(isSyncFile(dealias({ sync: true, f: 'x' })), true) t.equal(isSyncFile(dealias({ file: 'x' })), false) t.equal(isSyncFile(dealias({ sync: true })), false) diff --git a/test/unpack.js b/test/unpack.js index 51ba1220..2b0ea269 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -1,5 +1,3 @@ -process.umask(0o022) - import { Unpack, UnpackSync } from '../dist/esm/unpack.js' import fs from 'fs' @@ -36,6 +34,8 @@ const isLongFile = f => t.teardown(_ => rimraf(unpackdir)) +t.capture(process, 'umask', () => 0o22) + t.before(async () => { await rimraf(unpackdir) await mkdirp(unpackdir) @@ -640,6 +640,7 @@ t.test( onwarn: (c, w, d) => { warnings.push([c, w, d]) }, + chmod: true, }) u.on('close', _ => { t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) @@ -676,6 +677,8 @@ t.test( onwarn: (c, w, d) => { warnings.push([c, w, d]) }, + chmod: true, + processUmask: 0o22, }) u.end(data) t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) @@ -1395,6 +1398,8 @@ t.test('fail chmod', t => { new Unpack({ cwd: dir, onwarn: (_c, w, d) => warnings.push([w, d]), + chmod: true, + processUmask: 0o22, }) .on('close', _ => check(t, expect)) .end(data) @@ -1405,6 +1410,8 @@ t.test('fail chmod', t => { new UnpackSync({ cwd: dir, onwarn: (_c, w, d) => warnings.push([w, d]), + chmod: true, + processUmask: 0o22, }).end(data) check(t, expect) }) @@ -2112,8 +2119,6 @@ t.test('safely transmute chars on windows with absolutes', t => { }) t.test('use explicit chmod when required by umask', t => { - process.umask(0o022) - const basedir = path.resolve(unpackdir, 'umask-chmod') const data = makeTar([ @@ -2135,26 +2140,31 @@ t.test('use explicit chmod when required by umask', t => { t.test('async', t => { mkdirp.sync(basedir) - const unpack = new Unpack({ cwd: basedir }) + const unpack = new Unpack({ + cwd: basedir, + chmod: true, + processUmask: 0o22, + }) unpack.on('close', _ => check(t)) unpack.end(data) }) return t.test('sync', t => { mkdirp.sync(basedir) - const unpack = new UnpackSync({ cwd: basedir }) + const unpack = new UnpackSync({ + cwd: basedir, + chmod: true, + processUmask: 0o22, + }) unpack.end(data) check(t) }) }) -t.test('dont use explicit chmod if noChmod flag set', t => { - process.umask(0o022) - const { umask } = process - t.teardown(() => (process.umask = umask)) - process.umask = () => { +t.test('dont use explicit chmod if chmod flag not set', t => { + t.capture(process, 'umask', () => { throw new Error('should not call process.umask()') - } + }) const basedir = path.resolve(unpackdir, 'umask-no-chmod') @@ -2177,14 +2187,14 @@ t.test('dont use explicit chmod if noChmod flag set', t => { t.test('async', t => { mkdirp.sync(basedir) - const unpack = new Unpack({ cwd: basedir, noChmod: true }) + const unpack = new Unpack({ cwd: basedir }) unpack.on('close', _ => check(t)) unpack.end(data) }) return t.test('sync', t => { mkdirp.sync(basedir) - const unpack = new UnpackSync({ cwd: basedir, noChmod: true }) + const unpack = new UnpackSync({ cwd: basedir }) unpack.end(data) check(t) }) From 578f34f3522ce248bfa201b38d01c83b50d9922e Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 10 Apr 2024 08:59:31 -0700 Subject: [PATCH 63/96] tighten up changelog entries --- CHANGELOG.md | 52 ++++++++++++++++++---------------------------------- 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8c81472..85ae0acb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,48 +21,31 @@ - Add `maxDepth` option to prevent extraction into excessively deep folders. -## 6.1.15 +## 6.1 -- Normalize unicode internally using NFD - -## 6.1.14 - -- Update minipass dependency - -## [6.1.13](https://github.com/npm/node-tar/compare/v6.1.12...v6.1.13) (2022-12-07) - -### Dependencies - -- [`cc4e0dd`](https://github.com/npm/node-tar/commit/cc4e0ddfe523a0bce383846a67442c637a65d486) [#343](https://github.com/npm/node-tar/pull/343) bump minipass from 3.3.6 to 4.0.0 - -## [6.1.12](https://github.com/npm/node-tar/compare/v6.1.11...v6.1.12) (2022-10-31) - -### Bug Fixes - -- [`57493ee`](https://github.com/npm/node-tar/commit/57493ee66ece50d62114e02914282fc37be3a91a) [#332](https://github.com/npm/node-tar/pull/332) ensuring close event is emited after stream has ended (@webark) -- [`b003c64`](https://github.com/npm/node-tar/commit/b003c64f624332e24e19b30dc011069bb6708680) [#314](https://github.com/npm/node-tar/pull/314) replace deprecated String.prototype.substr() (#314) (@CommanderRoot, @lukekarrys) - -### Documentation - -- [`f129929`](https://github.com/npm/node-tar/commit/f12992932f171ea248b27fad95e7d489a56d31ed) [#313](https://github.com/npm/node-tar/pull/313) remove dead link to benchmarks (#313) (@yetzt) -- [`c1faa9f`](https://github.com/npm/node-tar/commit/c1faa9f44001dfb0bc7638b2850eb6058bd56a4a) add examples/explanation of using tar.t (@isaacs) +- remove dead link to benchmarks (#313) (@yetzt) +- add examples/explanation of using tar.t (@isaacs) +- ensure close event is emited after stream has ended (@webark) +- replace deprecated String.prototype.substr() (@CommanderRoot, + @lukekarrys) ## 6.0 - Drop support for node 6 and 8 -- fix symlinks and hardlinks on windows being packed with `\`-style path - targets +- fix symlinks and hardlinks on windows being packed with + `\`-style path targets ## 5.0 - Address unpack race conditions using path reservations - Change large-numbers errors from TypeError to Error - Add `TAR_*` error codes -- Raise `TAR_BAD_ARCHIVE` warning/error when there are no valid entries - found in an archive +- Raise `TAR_BAD_ARCHIVE` warning/error when there are no valid + entries found in an archive - do not treat ignored entries as an invalid archive - drop support for node v4 -- unpack: conditionally use a file mapping to write files on Windows +- unpack: conditionally use a file mapping to write files on + Windows - Set more portable 'mode' value in portable mode - Set `portable` gzip option in portable mode @@ -94,8 +77,8 @@ ## 3.1 -- Support `@file.tar` as an entry argument to copy entries from one tar - file to another. +- Support `@file.tar` as an entry argument to copy entries from + one tar file to another. - Add `noPax` option - `noResume` option for tar.t - win32: convert `>|<?:` chars to windows-friendly form @@ -104,12 +87,13 @@ ## 3.0 - Minipass-based implementation -- Entirely new API surface, `tar.c()`, `tar.x()` etc., much closer to - system tar semantics +- Entirely new API surface, `tar.c()`, `tar.x()` etc., much + closer to system tar semantics - Massive performance improvement - Require node 4.x and higher ## 0.x, 1.x, 2.x - 2011-2014 - fstream-based implementation -- slow and kinda bad, but better than npm shelling out to the system `tar` +- slow and kinda bad, but better than npm shelling out to the + system `tar` From dfb6b6cfc2fb5b26dc0d660bbe41c02c0a4c9cee Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 10 Apr 2024 09:15:52 -0700 Subject: [PATCH 64/96] ci: update versions --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e477a87..7a400a47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ jobs: build: strategy: matrix: - node-version: [16.x, 18.x, 20.x] + node-version: [18.x, 20.x, 21.x] platform: - os: ubuntu-latest shell: bash @@ -21,10 +21,10 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v1.1.0 + uses: actions/checkout@v4 - name: Use Nodejs ${{ matrix.node-version }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -32,4 +32,4 @@ jobs: run: npm install - name: Run Tests - run: npm test -- -c -t0 + run: npm test -- -c From ae9ce7ec2adb6300155cb6a46f8c9ea601330d81 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 10 Apr 2024 09:34:54 -0700 Subject: [PATCH 65/96] test: fix normalize-unicode coverage on linux --- .../test/normalize-unicode.js-win32.test.cjs | 30 +++++++ .../test/normalize-unicode.js.test.cjs | 30 ------- test/normalize-unicode.js | 82 ++++++++++--------- 3 files changed, 74 insertions(+), 68 deletions(-) create mode 100644 tap-snapshots/test/normalize-unicode.js-win32.test.cjs delete mode 100644 tap-snapshots/test/normalize-unicode.js.test.cjs diff --git a/tap-snapshots/test/normalize-unicode.js-win32.test.cjs b/tap-snapshots/test/normalize-unicode.js-win32.test.cjs new file mode 100644 index 00000000..85e353d8 --- /dev/null +++ b/tap-snapshots/test/normalize-unicode.js-win32.test.cjs @@ -0,0 +1,30 @@ +/* IMPORTANT + * This snapshot file is auto-generated, but designed for humans. + * It should be checked into source control and tracked carefully. + * Re-generate by setting TAP_SNAPSHOT=1 and running tests. + * Make sure to inspect the output below. Do not ignore changes! + */ +'use strict' +exports[`test/normalize-unicode.js win32 > TAP > normalize with strip slashes > "īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ" > normalized 1`] = ` +īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ +` + +exports[`test/normalize-unicode.js win32 > TAP > normalize with strip slashes > "\\\\a\\\\b\\\\c\\\\d\\\\" > normalized 1`] = ` +/a/b/c/d +` + +exports[`test/normalize-unicode.js win32 > TAP > normalize with strip slashes > "īš¨aaaaīš¨ddddīš¨" > normalized 1`] = ` +īš¨aaaaīš¨ddddīš¨ +` + +exports[`test/normalize-unicode.js win32 > TAP > normalize with strip slashes > "īŧŧbbbīŧŧeeeīŧŧ" > normalized 1`] = ` +īŧŧbbbīŧŧeeeīŧŧ +` + +exports[`test/normalize-unicode.js win32 > TAP > normalize with strip slashes > "1/4foo.txt" > normalized 1`] = ` +1/4foo.txt +` + +exports[`test/normalize-unicode.js win32 > TAP > normalize with strip slashes > "Âŧfoo.txt" > normalized 1`] = ` +Âŧfoo.txt +` diff --git a/tap-snapshots/test/normalize-unicode.js.test.cjs b/tap-snapshots/test/normalize-unicode.js.test.cjs deleted file mode 100644 index 6c7be82a..00000000 --- a/tap-snapshots/test/normalize-unicode.js.test.cjs +++ /dev/null @@ -1,30 +0,0 @@ -/* IMPORTANT - * This snapshot file is auto-generated, but designed for humans. - * It should be checked into source control and tracked carefully. - * Re-generate by setting TAP_SNAPSHOT=1 and running tests. - * Make sure to inspect the output below. Do not ignore changes! - */ -'use strict' -exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ" > normalized 1`] = ` -īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ -` - -exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "\\\\a\\\\b\\\\c\\\\d\\\\" > normalized 1`] = ` -/a/b/c/d -` - -exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "īš¨aaaaīš¨ddddīš¨" > normalized 1`] = ` -īš¨aaaaīš¨ddddīš¨ -` - -exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "īŧŧbbbīŧŧeeeīŧŧ" > normalized 1`] = ` -īŧŧbbbīŧŧeeeīŧŧ -` - -exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "1/4foo.txt" > normalized 1`] = ` -1/4foo.txt -` - -exports[`test/normalize-unicode.js > TAP > normalize with strip slashes > "Âŧfoo.txt" > normalized 1`] = ` -Âŧfoo.txt -` diff --git a/test/normalize-unicode.js b/test/normalize-unicode.js index 969ee6ca..ae3efd4d 100644 --- a/test/normalize-unicode.js +++ b/test/normalize-unicode.js @@ -1,16 +1,11 @@ import t from 'tap' +import { fileURLToPath } from 'url' +import { normalizeUnicode } from '../dist/esm/normalize-unicode.js' +import { stripTrailingSlashes } from '../dist/esm/strip-trailing-slashes.js' +import { normalizeWindowsPath } from '../dist/esm/normalize-windows-path.js' -process.env.TESTING_TAR_FAKE_PLATFORM = 'win32' - -const [ - { normalizeUnicode }, - { stripTrailingSlashes }, - { normalizeWindowsPath }, -] = await Promise.all([ - import('../dist/esm/normalize-unicode.js'), - import('../dist/esm/strip-trailing-slashes.js'), - import('../dist/esm/normalize-windows-path.js'), -]) +const __filename = fileURLToPath(import.meta.url) +const fakePlatform = process.env.TESTING_TAR_FAKE_PLATFORM // cafeˁ const cafe1 = Buffer.from([0x63, 0x61, 0x66, 0xc3, 0xa9]).toString() @@ -28,30 +23,41 @@ t.equal( t.equal(normalizeUnicode(cafe1), normalizeUnicode(cafe2), 'cached') t.equal(normalizeUnicode('foo'), 'foo', 'non-unicode string') -t.test('normalize with strip slashes', t => { - const paths = [ - '\\a\\b\\c\\d\\', - 'īš¨aaaaīš¨ddddīš¨', - 'īŧŧbbbīŧŧeeeīŧŧ', - 'īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ', - 'Âŧfoo.txt', - '1/4foo.txt', - ] - - t.plan(paths.length) - - for (const path of paths) { - t.test(JSON.stringify(path), t => { - const a = normalizeUnicode( - stripTrailingSlashes(normalizeWindowsPath(path)), - ) - const b = stripTrailingSlashes( - normalizeWindowsPath(normalizeUnicode(path)), - ) - t.matchSnapshot(a, 'normalized') - t.equal(a, b, 'order should not matter') - t.end() - }) - } - t.end() -}) +if (fakePlatform === 'win32') { + t.test('normalize with strip slashes', t => { + const paths = [ + '\\a\\b\\c\\d\\', + 'īš¨aaaaīš¨ddddīš¨', + 'īŧŧbbbīŧŧeeeīŧŧ', + 'īŧŧīŧŧīŧŧīŧŧīŧŧeeeīŧŧīŧŧīŧŧīŧŧīŧŧīŧŧ', + 'Âŧfoo.txt', + '1/4foo.txt', + ] + + t.plan(paths.length) + + for (const path of paths) { + t.test(JSON.stringify(path), t => { + const a = normalizeUnicode( + stripTrailingSlashes(normalizeWindowsPath(path)), + ) + const b = stripTrailingSlashes( + normalizeWindowsPath(normalizeUnicode(path)), + ) + t.matchSnapshot(a, 'normalized') + t.equal(a, b, 'order should not matter') + t.end() + }) + } + t.end() + }) +} + +if (fakePlatform !== 'win32') { + t.spawn(process.execPath, [__filename, 'win32'], { + env: { + ...process.env, + TESTING_TAR_FAKE_PLATFORM: 'win32', + } + }) +} From 23304160811cceb1a1949d3915d5a2a818726ec6 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 10 Apr 2024 09:37:22 -0700 Subject: [PATCH 66/96] test: code style, prefer () to _ for empty fns --- test/unpack.js | 188 ++++++++++++++++++++++++------------------------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/test/unpack.js b/test/unpack.js index 2b0ea269..9e92ba85 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -32,7 +32,7 @@ const isWindows = process.platform === 'win32' const isLongFile = f => f.match(/r.e.a.l.l.y.-.d.e.e.p.-.f.o.l.d.e.r.-.p.a.t.h/) -t.teardown(_ => rimraf(unpackdir)) +t.teardown(() => rimraf(unpackdir)) t.capture(process, 'umask', () => 0o22) @@ -43,7 +43,7 @@ t.before(async () => { t.test('basic file unpack tests', t => { const basedir = path.resolve(unpackdir, 'basic') - t.teardown(_ => rimraf(basedir)) + t.teardown(() => rimraf(basedir)) const cases = { 'emptypax.tar': { @@ -127,12 +127,12 @@ t.test('basic file unpack tests', t => { t.test('strict', t => { const unpack = new Unpack({ cwd: linkdir, strict: true }) fs.createReadStream(tf).pipe(unpack) - eos(unpack, _ => check(t)) + eos(unpack, () => check(t)) }) t.test('loose', t => { const unpack = new Unpack({ cwd: linkdir }) fs.createReadStream(tf).pipe(unpack) - eos(unpack, _ => check(t)) + eos(unpack, () => check(t)) }) }) @@ -212,11 +212,11 @@ t.test('links!', t => { t.test('async', t => { const unpack = new Unpack({ cwd: dir }) let finished = false - unpack.on('finish', _ => (finished = true)) - unpack.on('close', _ => + unpack.on('finish', () => (finished = true)) + unpack.on('close', () => t.ok(finished, 'emitted finish before close'), ) - unpack.on('close', _ => check(t)) + unpack.on('close', () => check(t)) unpack.end(data) }) @@ -235,11 +235,11 @@ t.test('links!', t => { t.test('async strip', t => { const unpack = new Unpack({ cwd: dir, strip: 1 }) let finished = false - unpack.on('finish', _ => (finished = true)) - unpack.on('close', _ => + unpack.on('finish', () => (finished = true)) + unpack.on('close', () => t.ok(finished, 'emitted finish before close'), ) - unpack.on('close', _ => checkForStrip(t)) + unpack.on('close', () => checkForStrip(t)) unpack.end(stripData) }) @@ -252,11 +252,11 @@ t.test('links!', t => { t.test('async strip 3', t => { const unpack = new Unpack({ cwd: dir, strip: 3 }) let finished = false - unpack.on('finish', _ => (finished = true)) - unpack.on('close', _ => + unpack.on('finish', () => (finished = true)) + unpack.on('close', () => t.ok(finished, 'emitted finish before close'), ) - unpack.on('close', _ => checkForStrip3(t)) + unpack.on('close', () => checkForStrip3(t)) unpack.end(stripData) }) }) @@ -267,7 +267,7 @@ t.test('links without cleanup (exercise clobbering code)', t => { t.plan(6) mkdirp.sync(dir) - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) t.beforeEach(() => { // clobber this junk @@ -296,11 +296,11 @@ t.test('links without cleanup (exercise clobbering code)', t => { t.test('async', t => { const unpack = new Unpack({ cwd: dir }) let prefinished = false - unpack.on('prefinish', _ => (prefinished = true)) - unpack.on('finish', _ => + unpack.on('prefinish', () => (prefinished = true)) + unpack.on('finish', () => t.ok(prefinished, 'emitted prefinish before finish'), ) - unpack.on('close', _ => check(t)) + unpack.on('close', () => check(t)) unpack.end(data) }) @@ -312,7 +312,7 @@ t.test('links without cleanup (exercise clobbering code)', t => { t.test('async again', t => { const unpack = new Unpack({ cwd: dir }) - eos(unpack, _ => check(t)) + eos(unpack, () => check(t)) unpack.end(data) }) @@ -324,7 +324,7 @@ t.test('links without cleanup (exercise clobbering code)', t => { t.test('async unlink', t => { const unpack = new Unpack({ cwd: dir, unlink: true }) - unpack.on('close', _ => check(t)) + unpack.on('close', () => check(t)) unpack.end(data) }) @@ -338,7 +338,7 @@ t.test('links without cleanup (exercise clobbering code)', t => { t.test('nested dir dupe', t => { const dir = path.resolve(unpackdir, 'nested-dir') mkdirp.sync(dir + '/d/e/e/p') - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) const expect = { 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt': 'short\n', 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': @@ -366,7 +366,7 @@ t.test('nested dir dupe', t => { // while we're at it, why not use gzip too? const zip = new z.Gzip() zip.pipe(unpack) - unpack.on('close', _ => check(t)) + unpack.on('close', () => check(t)) zip.end(data) }) @@ -378,7 +378,7 @@ t.test( t => { const dir = path.resolve(unpackdir, 'symlink-junk') - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) t.beforeEach(async () => { await rimraf(dir) await mkdirp(dir) @@ -437,7 +437,7 @@ t.test( cwd: dir, onwarn: (c, w, d) => warnings.push([c, w, d]), }) - u.on('close', _ => { + u.on('close', () => { t.equal( fs.lstatSync(dir + '/d/i').mode & 0o7777, isWindows ? 0o666 : 0o755, @@ -452,7 +452,7 @@ t.test( fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'got symlink', ) - t.throws(_ => fs.statSync(dir + '/d/i/r/symlink/x')) + t.throws(() => fs.statSync(dir + '/d/i/r/symlink/x')) } t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') if (!isWindows) { @@ -491,7 +491,7 @@ t.test( fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'got symlink', ) - t.throws(_ => fs.statSync(dir + '/d/i/r/symlink/x')) + t.throws(() => fs.statSync(dir + '/d/i/r/symlink/x')) } t.equal(warnings.length, 1) t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') @@ -514,7 +514,7 @@ t.test( onwarn: (c, w, d) => warnings.push([c, w, d]), preservePaths: true, }) - u.on('close', _ => { + u.on('close', () => { t.same(warnings, []) t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') @@ -565,7 +565,7 @@ t.test( onwarn: (c, w, d) => warnings.push([c, w, d]), unlink: true, }) - u.on('close', _ => { + u.on('close', () => { t.same(warnings, []) t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') @@ -596,7 +596,7 @@ t.test( onwarn: (c, w, d) => warnings.push([c, w, d]), unlink: true, }) - u.on('close', _ => { + u.on('close', () => { t.same(warnings, [['TAR_ENTRY_ERROR', 'poop', poop]]) reset() t.end() @@ -642,14 +642,14 @@ t.test( }, chmod: true, }) - u.on('close', _ => { + u.on('close', () => { t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') t.ok( fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'got symlink', ) - t.throws(_ => fs.statSync(dir + '/d/i/r/symlink/x')) + t.throws(() => fs.statSync(dir + '/d/i/r/symlink/x')) t.equal(warnings.length, 1) t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') t.equal( @@ -687,7 +687,7 @@ t.test( fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), 'got symlink', ) - t.throws(_ => fs.statSync(dir + '/d/i/r/symlink/x')) + t.throws(() => fs.statSync(dir + '/d/i/r/symlink/x')) t.equal(warnings.length, 1) t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') t.equal( @@ -709,7 +709,7 @@ t.test( t.test('unsupported entries', t => { const dir = path.resolve(unpackdir, 'unsupported-entries') mkdirp.sync(dir) - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) const unknown = new Header({ path: 'qux', size: 4 }) unknown.encode() unknown.block?.write('Z', 156) @@ -765,7 +765,7 @@ t.test('unsupported entries', t => { }, ], ] - u.on('close', _ => { + u.on('close', () => { t.equal(fs.readdirSync(dir).length, 0) t.match(warnings, expect) t.end() @@ -782,7 +782,7 @@ t.test('unsupported entries', t => { onwarn: (c, w, d) => warnings.push([c, w, d]), }) u.on('error', e => errors.push(e)) - u.on('close', _ => { + u.on('close', () => { t.equal(fs.readdirSync(dir).length, 0) t.same(warnings, []) t.match(errors, [ @@ -810,7 +810,7 @@ t.test('unsupported entries', t => { t.test('file in dir path', t => { const dir = path.resolve(unpackdir, 'file-junk') - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) t.beforeEach(async () => { await rimraf(dir) await mkdirp(dir) @@ -842,14 +842,14 @@ t.test('file in dir path', t => { t.test('fail because of file', t => { const check = t => { t.equal(fs.readFileSync(dir + '/d/i/r/file', 'utf8'), 'a') - t.throws(_ => fs.statSync(dir + '/d/i/r/file/a/b/c')) + t.throws(() => fs.statSync(dir + '/d/i/r/file/a/b/c')) t.end() } t.plan(2) t.test('async', t => { - new Unpack({ cwd: dir }).on('close', _ => check(t)).end(data) + new Unpack({ cwd: dir }).on('close', () => check(t)).end(data) }) t.test('sync', t => { @@ -869,7 +869,7 @@ t.test('file in dir path', t => { t.test('async', t => { new Unpack({ cwd: dir, unlink: true }) - .on('close', _ => check(t)) + .on('close', () => check(t)) .end(data) }) @@ -885,7 +885,7 @@ t.test('file in dir path', t => { t.test('set umask option', t => { const dir = path.resolve(unpackdir, 'umask') mkdirp.sync(dir) - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) const data = makeTar([ { @@ -901,7 +901,7 @@ t.test('set umask option', t => { umask: 0o027, cwd: dir, }) - .on('close', _ => { + .on('close', () => { t.equal( fs.statSync(dir + '/d/i/r').mode & 0o7777, isWindows ? 0o666 : 0o750, @@ -917,7 +917,7 @@ t.test('set umask option', t => { t.test('absolute paths', t => { const dir = path.join(unpackdir, 'absolute-paths') - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) t.beforeEach(async () => { await rimraf(dir) await mkdirp(dir) @@ -970,7 +970,7 @@ t.test('absolute paths', t => { cwd: dir, onwarn: (_c, w, d) => warnings.push([w, d]), }) - .on('close', _ => check(t)) + .on('close', () => check(t)) .end(data) }) @@ -1018,7 +1018,7 @@ t.test('absolute paths', t => { cwd: dir, onwarn: (_c, w, d) => warnings.push([w, d]), }) - .on('close', _ => check(t)) + .on('close', () => check(t)) .end(data) }) @@ -1040,7 +1040,7 @@ t.test('absolute paths', t => { t.test('.. paths', t => { const dir = path.join(unpackdir, 'dotted-paths') - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) t.beforeEach(async () => { await rimraf(dir) await mkdirp(dir) @@ -1072,7 +1072,7 @@ t.test('.. paths', t => { { path: dotted, code: 'TAR_ENTRY_ERROR' }, ], ]) - t.throws(_ => fs.lstatSync(resolved)) + t.throws(() => fs.lstatSync(resolved)) t.end() } @@ -1085,7 +1085,7 @@ t.test('.. paths', t => { cwd: dir, onwarn: (_c, w, d) => warnings.push([w, d]), }) - .on('close', _ => check(t)) + .on('close', () => check(t)) .end(data) }) @@ -1123,7 +1123,7 @@ t.test('.. paths', t => { cwd: dir, onwarn: (_c, w, d) => warnings.push([w, d]), }) - .on('close', _ => check(t)) + .on('close', () => check(t)) .end(data) }) @@ -1251,7 +1251,7 @@ t.test('fail all stats', t => { cwd: dir, onwarn: (_c, w, d) => warnings.push([w, d]), }) - .on('close', _ => check(t, expect)) + .on('close', () => check(t, expect)) .end(data) }) @@ -1289,7 +1289,7 @@ t.test('fail symlink', t => { poop.code = 'EPOOP' const unmutate = mutateFS.fail('symlink', poop) const dir = path.join(unpackdir, 'symlink-fail') - t.teardown(async _ => { + t.teardown(async () => { unmutate() await rimraf(dir) }) @@ -1334,7 +1334,7 @@ t.test('fail symlink', t => { cwd: dir, onwarn: (_c, w, d) => warnings.push([w, d]), }) - .on('close', _ => check(t, expect)) + .on('close', () => check(t, expect)) .end(data) }) @@ -1355,7 +1355,7 @@ t.test('fail chmod', t => { poop.code = 'EPOOP' const unmutate = mutateFS.fail('chmod', poop) const dir = path.join(unpackdir, 'chmod-fail') - t.teardown(async _ => { + t.teardown(async () => { unmutate() await rimraf(dir) }) @@ -1401,7 +1401,7 @@ t.test('fail chmod', t => { chmod: true, processUmask: 0o22, }) - .on('close', _ => check(t, expect)) + .on('close', () => check(t, expect)) .end(data) }) @@ -1424,7 +1424,7 @@ t.test('fail mkdir', t => { poop.code = 'EPOOP' let unmutate const dir = path.join(unpackdir, 'mkdir-fail') - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) const warnings = [] t.beforeEach(async () => { @@ -1478,7 +1478,7 @@ t.test('fail mkdir', t => { cwd: dir, onwarn: (_c, w, d) => warnings.push([w, d]), }) - .on('close', _ => check(t)) + .on('close', () => check(t)) .end(data) }) @@ -1490,7 +1490,7 @@ t.test('fail write', t => { poop.code = 'EPOOP' const unmutate = mutateFS.fail('write', poop) const dir = path.join(unpackdir, 'write-fail') - t.teardown(async _ => { + t.teardown(async () => { unmutate() await rimraf(dir) }) @@ -1528,7 +1528,7 @@ t.test('fail write', t => { cwd: dir, onwarn: (_c, w, d) => warnings.push([w, d]), }) - .on('close', _ => check(t)) + .on('close', () => check(t)) .end(data) }) @@ -1545,7 +1545,7 @@ t.test('fail write', t => { t.test('skip existing', t => { const dir = path.join(unpackdir, 'skip-newer') - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) const date = new Date('2011-03-27T22:16:31.000Z') t.beforeEach(async () => { @@ -1582,7 +1582,7 @@ t.test('skip existing', t => { cwd: dir, keep: true, }) - .on('close', _ => check(t)) + .on('close', () => check(t)) .end(data) }) @@ -1599,7 +1599,7 @@ t.test('skip existing', t => { t.test('skip newer', t => { const dir = path.join(unpackdir, 'skip-newer') - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) const date = new Date('2013-12-19T17:00:00.000Z') t.beforeEach(async () => { @@ -1636,7 +1636,7 @@ t.test('skip newer', t => { cwd: dir, newer: true, }) - .on('close', _ => check(t)) + .on('close', () => check(t)) .end(data) }) @@ -1653,7 +1653,7 @@ t.test('skip newer', t => { t.test('no mtime', t => { const dir = path.join(unpackdir, 'skip-newer') - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) t.beforeEach(async () => { await rimraf(dir) @@ -1702,7 +1702,7 @@ t.test('no mtime', t => { cwd: dir, noMtime: true, }) - .on('close', _ => check(t)) + .on('close', () => check(t)) .end(data) }) @@ -1720,7 +1720,7 @@ t.test('no mtime', t => { t.test('unpack big enough to pause/drain', t => { const dir = path.resolve(unpackdir, 'drain-clog') mkdirp.sync(dir) - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) const stream = fs.createReadStream(fixtures + '/parses.tar') const u = new Unpack({ cwd: dir, @@ -1732,7 +1732,7 @@ t.test('unpack big enough to pause/drain', t => { t.fail('should not get ignored entry: ' + entry.path), ) - u.on('close', _ => { + u.on('close', () => { t.pass('extraction finished') const actual = fs.readdirSync(dir) const expected = fs.readdirSync(parses) @@ -1749,17 +1749,17 @@ t.test('set owner', t => { const myGid = 1024 const getuid = process.getuid const getgid = process.getgid - process.getuid = _ => myUid - process.getgid = _ => myGid + process.getuid = () => myUid + process.getgid = () => myGid t.teardown( - _ => ((process.getuid = getuid), (process.getgid = getgid)), + () => ((process.getuid = getuid), (process.getgid = getgid)), ) // can't actually do this because it requires root, but we can // verify that chown gets called. t.test('as root, defaults to true', t => { const getuid = process.getuid - process.getuid = _ => 0 + process.getuid = () => 0 const u = new Unpack() t.equal(u.preserveOwner, true, 'preserveOwner enabled') process.getuid = getuid @@ -1768,7 +1768,7 @@ t.test('set owner', t => { t.test('as non-root, defaults to false', t => { const getuid = process.getuid - process.getuid = _ => 501 + process.getuid = () => 501 const u = new Unpack() t.equal(u.preserveOwner, false, 'preserveOwner disabled') process.getuid = getuid @@ -1855,7 +1855,7 @@ t.test('set owner', t => { t.test('sync', t => { mkdirp.sync(dir) - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) let warned = false const u = new UnpackSync({ cwd: dir, @@ -1873,7 +1873,7 @@ t.test('set owner', t => { t.test('async', t => { mkdirp.sync(dir) - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) let warned = false const u = new Unpack({ cwd: dir, @@ -1908,9 +1908,9 @@ t.test('set owner', t => { called++ cb() } - fs.chownSync = fs.lchownSync = fs.fchownSync = _ => called++ + fs.chownSync = fs.lchownSync = fs.fchownSync = () => called++ - t.teardown(_ => { + t.teardown(() => { fs.chown = chown fs.fchown = fchown fs.lchown = lchown @@ -1921,7 +1921,7 @@ t.test('set owner', t => { t.test('sync', t => { mkdirp.sync(dir) - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) called = 0 const u = new UnpackSync({ cwd: dir, preserveOwner: true }) u.end(data) @@ -1931,11 +1931,11 @@ t.test('set owner', t => { t.test('async', t => { mkdirp.sync(dir) - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) called = 0 const u = new Unpack({ cwd: dir, preserveOwner: true }) u.end(data) - u.on('close', _ => { + u.on('close', () => { t.ok(called >= 5, 'called chowns') t.end() }) @@ -1950,7 +1950,7 @@ t.test('set owner', t => { const un = mutateFS.fail('chown', poop) const unf = mutateFS.fail('fchown', poop) const unl = mutateFS.fail('lchown', poop) - t.teardown(async _ => { + t.teardown(async () => { un() unf() unl() @@ -1985,7 +1985,7 @@ t.test('set owner', t => { t.test('async', t => { const u = new Unpack({ cwd: dir, preserveOwner: false }) u.end(data) - u.on('close', _ => check(t)) + u.on('close', () => check(t)) }) t.end() @@ -2033,7 +2033,7 @@ t.test('unpack when dir is not writable', t => { t.test('async', t => { const u = new Unpack({ cwd: dir, strict: true }) u.end(data) - u.on('close', _ => check(t)) + u.on('close', () => check(t)) }) t.end() @@ -2071,7 +2071,7 @@ t.test('transmute chars on windows', t => { win32: true, }) u.end(data) - u.on('close', _ => check(t)) + u.on('close', () => check(t)) }) t.test('sync', t => { @@ -2145,7 +2145,7 @@ t.test('use explicit chmod when required by umask', t => { chmod: true, processUmask: 0o22, }) - unpack.on('close', _ => check(t)) + unpack.on('close', () => check(t)) unpack.end(data) }) @@ -2188,7 +2188,7 @@ t.test('dont use explicit chmod if chmod flag not set', t => { t.test('async', t => { mkdirp.sync(basedir) const unpack = new Unpack({ cwd: basedir }) - unpack.on('close', _ => check(t)) + unpack.on('close', () => check(t)) unpack.end(data) }) @@ -2213,7 +2213,7 @@ t.test('chown implicit dirs and also the entries', t => { const getuid = process.getuid const getgid = process.getgid - t.teardown(_ => { + t.teardown(() => { fs.chown = chown fs.chownSync = chownSync fs.lchown = lchown @@ -2278,15 +2278,15 @@ t.test('chown implicit dirs and also the entries', t => { t.test('throws when setting uid/gid improperly', t => { t.throws( - _ => new Unpack({ uid: 420 }), + () => new Unpack({ uid: 420 }), TypeError('cannot set owner without number uid and gid'), ) t.throws( - _ => new Unpack({ gid: 666 }), + () => new Unpack({ gid: 666 }), TypeError('cannot set owner without number uid and gid'), ) t.throws( - _ => new Unpack({ uid: 1, gid: 2, preserveOwner: true }), + () => new Unpack({ uid: 1, gid: 2, preserveOwner: true }), TypeError( 'cannot preserve owner in archive and also set owner explicitly', ), @@ -2304,7 +2304,7 @@ t.test('chown implicit dirs and also the entries', t => { uid: 420, gid: 666, }) - unpack.on('close', _ => check(t)) + unpack.on('close', () => check(t)) unpack.end(data) }) .then( @@ -2342,7 +2342,7 @@ t.test('chown implicit dirs and also the entries', t => { t.test('bad cwd setting', t => { const basedir = path.resolve(unpackdir, 'bad-cwd') mkdirp.sync(basedir) - t.teardown(_ => rimraf(basedir)) + t.teardown(() => rimraf(basedir)) const cases = [ // the cwd itself @@ -2383,7 +2383,7 @@ t.test('bad cwd setting', t => { const cwd = basedir + '/file' const opt = { cwd: cwd } - t.throws(_ => new UnpackSync(opt).end(data), { + t.throws(() => new UnpackSync(opt).end(data), { name: 'CwdError', message: "ENOTDIR: Cannot cd into '" + normPath(cwd) + "'", path: normPath(cwd), @@ -2408,7 +2408,7 @@ t.test('bad cwd setting', t => { const cwd = basedir + '/asdf/asdf/asdf' const opt = { cwd: cwd } - t.throws(_ => new UnpackSync(opt).end(data), { + t.throws(() => new UnpackSync(opt).end(data), { name: 'CwdError', message: "ENOENT: Cannot cd into '" + normPath(cwd) + "'", path: normPath(cwd), @@ -2436,7 +2436,7 @@ t.test('bad cwd setting', t => { t.test('transform', t => { const basedir = path.resolve(unpackdir, 'transform') - t.teardown(_ => rimraf(basedir)) + t.teardown(() => rimraf(basedir)) const cases = { 'emptypax.tar': { @@ -2514,12 +2514,12 @@ t.test('transform', t => { transform: txFn, }) fs.createReadStream(tf).pipe(unpack) - eos(unpack, _ => check(t)) + eos(unpack, () => check(t)) }) t.test('loose', t => { const unpack = new Unpack({ cwd: dir, transform: txFn }) fs.createReadStream(tf).pipe(unpack) - eos(unpack, _ => check(t)) + eos(unpack, () => check(t)) }) }) @@ -2547,7 +2547,7 @@ t.test('transform', t => { t.test('transform error', t => { const dir = path.resolve(unpackdir, 'transform-error') mkdirp.sync(dir) - t.teardown(_ => rimraf(dir)) + t.teardown(() => rimraf(dir)) const tarfile = path.resolve(tars, 'body-byte-counts.tar') const tardata = fs.readFileSync(tarfile) From b3afdbb26496fe42110b3708b8f75c4ca4c853b7 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 10 Apr 2024 10:23:23 -0700 Subject: [PATCH 67/96] unpack test: use modern tap features This replaces a lot of manual mkdir/rimraf with t.testdir() --- test/unpack.js | 590 +++++++++++++++++++++---------------------------- 1 file changed, 254 insertions(+), 336 deletions(-) diff --git a/test/unpack.js b/test/unpack.js index 9e92ba85..f7c4f88a 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -15,7 +15,6 @@ const __dirname = path.dirname(__filename) const fixtures = path.resolve(__dirname, 'fixtures') const tars = path.resolve(fixtures, 'tars') const parses = path.resolve(fixtures, 'parse') -const unpackdir = path.resolve(fixtures, 'unpack') import eos from 'end-of-stream' import { mkdirp } from 'mkdirp' @@ -32,19 +31,9 @@ const isWindows = process.platform === 'win32' const isLongFile = f => f.match(/r.e.a.l.l.y.-.d.e.e.p.-.f.o.l.d.e.r.-.p.a.t.h/) -t.teardown(() => rimraf(unpackdir)) - t.capture(process, 'umask', () => 0o22) -t.before(async () => { - await rimraf(unpackdir) - await mkdirp(unpackdir) -}) - t.test('basic file unpack tests', t => { - const basedir = path.resolve(unpackdir, 'basic') - t.teardown(() => rimraf(basedir)) - const cases = { 'emptypax.tar': { '🌟.txt': 'đŸŒŸâœ§âœŠâ­ī¸ŽâœĒâœĢâœŦ✭✎⚝✯✰âœĩâœļ✷✸✹❂⭑⭒★☆✡â˜Ēâœ´ī¸ŽâœĻâœĄī¸đŸ”¯âœ´ī¸đŸŒ \n', @@ -99,13 +88,11 @@ t.test('basic file unpack tests', t => { tarfiles.forEach(tarfile => { t.test(tarfile, t => { const tf = path.resolve(tars, tarfile) - const dir = path.resolve(basedir, tarfile) - const linkdir = path.resolve(basedir, tarfile + '.link') + const dir = t.testdir({}) + const linkdir = dir + '.link' t.beforeEach(async () => { - await rimraf(dir) await rimraf(linkdir) - await mkdirp(dir) - fs.symlinkSync(dir, linkdir, 'junction') + fs.symlinkSync(dir, linkdir) }) const check = t => { @@ -163,7 +150,7 @@ t.test('cwd default to process cwd', t => { }) t.test('links!', t => { - const dir = path.resolve(unpackdir, 'links') + const dir = t.testdir({}) const data = fs.readFileSync(tars + '/links.tar') const stripData = fs.readFileSync(tars + '/links-strip.tar') @@ -262,12 +249,10 @@ t.test('links!', t => { }) t.test('links without cleanup (exercise clobbering code)', t => { - const dir = path.resolve(unpackdir, 'links') + const dir = t.testdir({}) const data = fs.readFileSync(tars + '/links.tar') t.plan(6) - mkdirp.sync(dir) - t.teardown(() => rimraf(dir)) t.beforeEach(() => { // clobber this junk @@ -336,9 +321,8 @@ t.test('links without cleanup (exercise clobbering code)', t => { }) t.test('nested dir dupe', t => { - const dir = path.resolve(unpackdir, 'nested-dir') + const dir = t.testdir({}) mkdirp.sync(dir + '/d/e/e/p') - t.teardown(() => rimraf(dir)) const expect = { 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/a.txt': 'short\n', 'd/e/e/p/-/f/o/l/d/e/r/-/p/a/t/h/cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc': @@ -376,14 +360,6 @@ t.test( skip: isWindows && 'symlinks not fully supported', }, t => { - const dir = path.resolve(unpackdir, 'symlink-junk') - - t.teardown(() => rimraf(dir)) - t.beforeEach(async () => { - await rimraf(dir) - await mkdirp(dir) - }) - const data = makeTar([ { path: 'd/i', @@ -433,26 +409,27 @@ t.test( t.test('no clobbering', t => { const warnings = [] + const cwd = t.testdir({}) const u = new Unpack({ - cwd: dir, + cwd, onwarn: (c, w, d) => warnings.push([c, w, d]), }) u.on('close', () => { t.equal( - fs.lstatSync(dir + '/d/i').mode & 0o7777, + fs.lstatSync(cwd + '/d/i').mode & 0o7777, isWindows ? 0o666 : 0o755, ) t.equal( - fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, + fs.lstatSync(cwd + '/d/i/r/dir').mode & 0o7777, isWindows ? 0o666 : 0o751, ) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + t.ok(fs.lstatSync(cwd + '/d/i/r/file').isFile(), 'got file') if (!isWindows) { t.ok( - fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + fs.lstatSync(cwd + '/d/i/r/symlink').isSymbolicLink(), 'got symlink', ) - t.throws(() => fs.statSync(dir + '/d/i/r/symlink/x')) + t.throws(() => fs.statSync(cwd + '/d/i/r/symlink/x')) } t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') if (!isWindows) { @@ -464,8 +441,8 @@ t.test( name: 'SymlinkError', code: 'TAR_SYMLINK_ERROR', tarCode: 'TAR_ENTRY_ERROR', - path: dir + '/d/i/r/symlink/', - symlink: dir + '/d/i/r/symlink', + path: cwd + '/d/i/r/symlink/', + symlink: cwd + '/d/i/r/symlink', }) } t.equal(warnings.length, 1) @@ -476,22 +453,23 @@ t.test( t.test('no clobbering, sync', t => { const warnings = [] + const cwd = t.testdir({}) const u = new UnpackSync({ - cwd: dir, + cwd, onwarn: (c, w, d) => warnings.push([c, w, d]), }) u.end(data) t.equal( - fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, + fs.lstatSync(cwd + '/d/i/r/dir').mode & 0o7777, isWindows ? 0o666 : 0o751, ) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + t.ok(fs.lstatSync(cwd + '/d/i/r/file').isFile(), 'got file') if (!isWindows) { t.ok( - fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + fs.lstatSync(cwd + '/d/i/r/symlink').isSymbolicLink(), 'got symlink', ) - t.throws(() => fs.statSync(dir + '/d/i/r/symlink/x')) + t.throws(() => fs.statSync(cwd + '/d/i/r/symlink/x')) } t.equal(warnings.length, 1) t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') @@ -501,33 +479,34 @@ t.test( ) t.match(warnings[0][2], { name: 'SymlinkError', - path: dir + '/d/i/r/symlink/', - symlink: dir + '/d/i/r/symlink', + path: cwd + '/d/i/r/symlink/', + symlink: cwd + '/d/i/r/symlink', }) t.end() }) t.test('extract through symlink', t => { const warnings = [] + const cwd = t.testdir({}) const u = new Unpack({ - cwd: dir, + cwd, onwarn: (c, w, d) => warnings.push([c, w, d]), preservePaths: true, }) u.on('close', () => { t.same(warnings, []) - t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + t.equal(fs.lstatSync(cwd + '/d/i/r/dir').mode & 0o7777, 0o751) + t.ok(fs.lstatSync(cwd + '/d/i/r/file').isFile(), 'got file') t.ok( - fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + fs.lstatSync(cwd + '/d/i/r/symlink').isSymbolicLink(), 'got symlink', ) t.ok( - fs.lstatSync(dir + '/d/i/r/dir/x').isFile(), + fs.lstatSync(cwd + '/d/i/r/dir/x').isFile(), 'x thru link', ) t.ok( - fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), + fs.lstatSync(cwd + '/d/i/r/symlink/x').isFile(), 'x thru link', ) t.end() @@ -537,22 +516,23 @@ t.test( t.test('extract through symlink sync', t => { const warnings = [] + const cwd = t.testdir({}) const u = new UnpackSync({ - cwd: dir, + cwd, onwarn: (c, w, d) => warnings.push([c, w, d]), preservePaths: true, }) u.end(data) t.same(warnings, []) - t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + t.equal(fs.lstatSync(cwd + '/d/i/r/dir').mode & 0o7777, 0o751) + t.ok(fs.lstatSync(cwd + '/d/i/r/file').isFile(), 'got file') t.ok( - fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + fs.lstatSync(cwd + '/d/i/r/symlink').isSymbolicLink(), 'got symlink', ) - t.ok(fs.lstatSync(dir + '/d/i/r/dir/x').isFile(), 'x thru link') + t.ok(fs.lstatSync(cwd + '/d/i/r/dir/x').isFile(), 'x thru link') t.ok( - fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), + fs.lstatSync(cwd + '/d/i/r/symlink/x').isFile(), 'x thru link', ) t.end() @@ -560,25 +540,26 @@ t.test( t.test('clobber through symlink', t => { const warnings = [] + const cwd = t.testdir({}) const u = new Unpack({ - cwd: dir, + cwd, onwarn: (c, w, d) => warnings.push([c, w, d]), unlink: true, }) u.on('close', () => { t.same(warnings, []) - t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + t.equal(fs.lstatSync(cwd + '/d/i/r/dir').mode & 0o7777, 0o751) + t.ok(fs.lstatSync(cwd + '/d/i/r/file').isFile(), 'got file') t.notOk( - fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + fs.lstatSync(cwd + '/d/i/r/symlink').isSymbolicLink(), 'no link', ) t.ok( - fs.lstatSync(dir + '/d/i/r/symlink').isDirectory(), + fs.lstatSync(cwd + '/d/i/r/symlink').isDirectory(), 'sym is dir', ) t.ok( - fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), + fs.lstatSync(cwd + '/d/i/r/symlink/x').isFile(), 'x thru link', ) t.end() @@ -590,9 +571,10 @@ t.test( const poop = new Error('poop') // for some reason, resetting fs.unlink in the teardown was breaking const reset = mutateFS.fail('unlink', poop) + const cwd = t.testdir({}) const warnings = [] const u = new Unpack({ - cwd: dir, + cwd, onwarn: (c, w, d) => warnings.push([c, w, d]), unlink: true, }) @@ -606,50 +588,59 @@ t.test( t.test('clobber through symlink sync', t => { const warnings = [] + const cwd = t.testdir({}) const u = new UnpackSync({ - cwd: dir, + cwd, onwarn: (c, w, d) => warnings.push([c, w, d]), unlink: true, }) u.end(data) - t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + t.equal(fs.lstatSync(cwd + '/d/i/r/dir').mode & 0o7777, 0o751) + t.ok(fs.lstatSync(cwd + '/d/i/r/file').isFile(), 'got file') t.notOk( - fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + fs.lstatSync(cwd + '/d/i/r/symlink').isSymbolicLink(), 'no link', ) t.ok( - fs.lstatSync(dir + '/d/i/r/symlink').isDirectory(), + fs.lstatSync(cwd + '/d/i/r/symlink').isDirectory(), 'sym is dir', ) t.ok( - fs.lstatSync(dir + '/d/i/r/symlink/x').isFile(), + fs.lstatSync(cwd + '/d/i/r/symlink/x').isFile(), 'x thru link', ) t.end() }) t.test('clobber dirs', t => { - mkdirp.sync(dir + '/d/i/r/dir') - mkdirp.sync(dir + '/d/i/r/file') - mkdirp.sync(dir + '/d/i/r/link') - mkdirp.sync(dir + '/d/i/r/symlink') + const cwd = t.testdir({ + d: { + i: { + r: { + dir: {}, + file: {}, + link: {}, + symlink: {}, + }, + }, + }, + }) const warnings = [] const u = new Unpack({ - cwd: dir, + cwd, onwarn: (c, w, d) => { warnings.push([c, w, d]) }, chmod: true, }) u.on('close', () => { - t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + t.equal(fs.lstatSync(cwd + '/d/i/r/dir').mode & 0o7777, 0o751) + t.ok(fs.lstatSync(cwd + '/d/i/r/file').isFile(), 'got file') t.ok( - fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + fs.lstatSync(cwd + '/d/i/r/symlink').isSymbolicLink(), 'got symlink', ) - t.throws(() => fs.statSync(dir + '/d/i/r/symlink/x')) + t.throws(() => fs.statSync(cwd + '/d/i/r/symlink/x')) t.equal(warnings.length, 1) t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') t.equal( @@ -658,8 +649,8 @@ t.test( ) t.match(warnings[0][2], { name: 'SymlinkError', - path: dir + '/d/i/r/symlink/', - symlink: dir + '/d/i/r/symlink', + path: cwd + '/d/i/r/symlink/', + symlink: cwd + '/d/i/r/symlink', }) t.end() }) @@ -667,13 +658,21 @@ t.test( }) t.test('clobber dirs sync', t => { - mkdirp.sync(dir + '/d/i/r/dir') - mkdirp.sync(dir + '/d/i/r/file') - mkdirp.sync(dir + '/d/i/r/link') - mkdirp.sync(dir + '/d/i/r/symlink') + const cwd = t.testdir({ + d: { + i: { + r: { + dir: {}, + file: {}, + link: {}, + symlink: {}, + }, + }, + }, + }) const warnings = [] const u = new UnpackSync({ - cwd: dir, + cwd, onwarn: (c, w, d) => { warnings.push([c, w, d]) }, @@ -681,13 +680,13 @@ t.test( processUmask: 0o22, }) u.end(data) - t.equal(fs.lstatSync(dir + '/d/i/r/dir').mode & 0o7777, 0o751) - t.ok(fs.lstatSync(dir + '/d/i/r/file').isFile(), 'got file') + t.equal(fs.lstatSync(cwd + '/d/i/r/dir').mode & 0o7777, 0o751) + t.ok(fs.lstatSync(cwd + '/d/i/r/file').isFile(), 'got file') t.ok( - fs.lstatSync(dir + '/d/i/r/symlink').isSymbolicLink(), + fs.lstatSync(cwd + '/d/i/r/symlink').isSymbolicLink(), 'got symlink', ) - t.throws(() => fs.statSync(dir + '/d/i/r/symlink/x')) + t.throws(() => fs.statSync(cwd + '/d/i/r/symlink/x')) t.equal(warnings.length, 1) t.equal(warnings[0][0], 'TAR_ENTRY_ERROR') t.equal( @@ -696,8 +695,8 @@ t.test( ) t.match(warnings[0][2], { name: 'SymlinkError', - path: dir + '/d/i/r/symlink/', - symlink: dir + '/d/i/r/symlink', + path: cwd + '/d/i/r/symlink/', + symlink: cwd + '/d/i/r/symlink', }) t.end() }) @@ -707,9 +706,6 @@ t.test( ) t.test('unsupported entries', t => { - const dir = path.resolve(unpackdir, 'unsupported-entries') - mkdirp.sync(dir) - t.teardown(() => rimraf(dir)) const unknown = new Header({ path: 'qux', size: 4 }) unknown.encode() unknown.block?.write('Z', 156) @@ -736,9 +732,10 @@ t.test('unsupported entries', t => { ]) t.test('basic, warns', t => { + const cwd = t.testdir({}) const warnings = [] const u = new Unpack({ - cwd: dir, + cwd, onwarn: (c, w, d) => warnings.push([c, w, d]), }) const c = 'TAR_ENTRY_UNSUPPORTED' @@ -766,7 +763,7 @@ t.test('unsupported entries', t => { ], ] u.on('close', () => { - t.equal(fs.readdirSync(dir).length, 0) + t.equal(fs.readdirSync(cwd).length, 0) t.match(warnings, expect) t.end() }) @@ -774,16 +771,17 @@ t.test('unsupported entries', t => { }) t.test('strict, throws', t => { + const cwd = t.testdir({}) const warnings = [] const errors = [] const u = new Unpack({ - cwd: dir, + cwd, strict: true, onwarn: (c, w, d) => warnings.push([c, w, d]), }) u.on('error', e => errors.push(e)) u.on('close', () => { - t.equal(fs.readdirSync(dir).length, 0) + t.equal(fs.readdirSync(cwd).length, 0) t.same(warnings, []) t.match(errors, [ { @@ -808,14 +806,6 @@ t.test('unsupported entries', t => { }) t.test('file in dir path', t => { - const dir = path.resolve(unpackdir, 'file-junk') - - t.teardown(() => rimraf(dir)) - t.beforeEach(async () => { - await rimraf(dir) - await mkdirp(dir) - }) - const data = makeTar([ { path: 'd/i/r/file', @@ -841,40 +831,46 @@ t.test('file in dir path', t => { t.test('fail because of file', t => { const check = t => { - t.equal(fs.readFileSync(dir + '/d/i/r/file', 'utf8'), 'a') - t.throws(() => fs.statSync(dir + '/d/i/r/file/a/b/c')) + const cwd = t.testdirName + t.equal(fs.readFileSync(cwd + '/d/i/r/file', 'utf8'), 'a') + t.throws(() => fs.statSync(cwd + '/d/i/r/file/a/b/c')) t.end() } t.plan(2) t.test('async', t => { - new Unpack({ cwd: dir }).on('close', () => check(t)).end(data) + const cwd = t.testdir({}) + new Unpack({ cwd }).on('close', () => check(t)).end(data) }) t.test('sync', t => { - new UnpackSync({ cwd: dir }).end(data) + const cwd = t.testdir({}) + new UnpackSync({ cwd }).end(data) check(t) }) }) t.test('clobber on through', t => { const check = t => { - t.ok(fs.statSync(dir + '/d/i/r/file').isDirectory()) - t.equal(fs.readFileSync(dir + '/d/i/r/file/a/b/c', 'utf8'), 'b') + const cwd = t.testdirName + t.ok(fs.statSync(cwd + '/d/i/r/file').isDirectory()) + t.equal(fs.readFileSync(cwd + '/d/i/r/file/a/b/c', 'utf8'), 'b') t.end() } t.plan(2) t.test('async', t => { - new Unpack({ cwd: dir, unlink: true }) + const cwd = t.testdir({}) + new Unpack({ cwd, unlink: true }) .on('close', () => check(t)) .end(data) }) t.test('sync', t => { - new UnpackSync({ cwd: dir, unlink: true }).end(data) + const cwd = t.testdir({}) + new UnpackSync({ cwd, unlink: true }).end(data) check(t) }) }) @@ -883,9 +879,7 @@ t.test('file in dir path', t => { }) t.test('set umask option', t => { - const dir = path.resolve(unpackdir, 'umask') - mkdirp.sync(dir) - t.teardown(() => rimraf(dir)) + const cwd = t.testdir({}) const data = makeTar([ { @@ -899,15 +893,15 @@ t.test('set umask option', t => { new Unpack({ umask: 0o027, - cwd: dir, + cwd, }) .on('close', () => { t.equal( - fs.statSync(dir + '/d/i/r').mode & 0o7777, + fs.statSync(cwd + '/d/i/r').mode & 0o7777, isWindows ? 0o666 : 0o750, ) t.equal( - fs.statSync(dir + '/d/i/r/dir').mode & 0o7777, + fs.statSync(cwd + '/d/i/r/dir').mode & 0o7777, isWindows ? 0o666 : 0o751, ) t.end() @@ -916,7 +910,7 @@ t.test('set umask option', t => { }) t.test('absolute paths', t => { - const dir = path.join(unpackdir, 'absolute-paths') + const dir = t.testdir({}) t.teardown(() => rimraf(dir)) t.beforeEach(async () => { await rimraf(dir) @@ -1039,8 +1033,7 @@ t.test('absolute paths', t => { }) t.test('.. paths', t => { - const dir = path.join(unpackdir, 'dotted-paths') - t.teardown(() => rimraf(dir)) + const dir = t.testdir({}) t.beforeEach(async () => { await rimraf(dir) await mkdirp(dir) @@ -1147,7 +1140,7 @@ t.test('.. paths', t => { t.test('fail all stats', t => { const poop = new Error('poop') poop.code = 'EPOOP' - const dir = normPath(path.join(unpackdir, 'stat-fail')) + const dir = normPath(t.testdir({})) const { stat, fstat, lstat, statSync, fstatSync, lstatSync } = fs const unmutate = () => Object.assign(fs, { @@ -1287,12 +1280,8 @@ t.test('fail all stats', t => { t.test('fail symlink', t => { const poop = new Error('poop') poop.code = 'EPOOP' - const unmutate = mutateFS.fail('symlink', poop) - const dir = path.join(unpackdir, 'symlink-fail') - t.teardown(async () => { - unmutate() - await rimraf(dir) - }) + const dir = t.testdir({}) + t.teardown(mutateFS.fail('symlink', poop)) const warnings = [] t.beforeEach(async () => { @@ -1353,12 +1342,8 @@ t.test('fail symlink', t => { t.test('fail chmod', t => { const poop = new Error('poop') poop.code = 'EPOOP' - const unmutate = mutateFS.fail('chmod', poop) - const dir = path.join(unpackdir, 'chmod-fail') - t.teardown(async () => { - unmutate() - await rimraf(dir) - }) + const dir = t.testdir() + t.teardown(mutateFS.fail('chmod', poop)) const warnings = [] t.beforeEach(async () => { @@ -1423,8 +1408,7 @@ t.test('fail mkdir', t => { const poop = new Error('poop') poop.code = 'EPOOP' let unmutate - const dir = path.join(unpackdir, 'mkdir-fail') - t.teardown(() => rimraf(dir)) + const dir = t.testdir({}) const warnings = [] t.beforeEach(async () => { @@ -1488,12 +1472,8 @@ t.test('fail mkdir', t => { t.test('fail write', t => { const poop = new Error('poop') poop.code = 'EPOOP' - const unmutate = mutateFS.fail('write', poop) - const dir = path.join(unpackdir, 'write-fail') - t.teardown(async () => { - unmutate() - await rimraf(dir) - }) + const dir = t.testdir({}) + t.teardown(mutateFS.fail('write', poop)) const warnings = [] t.beforeEach(async () => { @@ -1544,14 +1524,11 @@ t.test('fail write', t => { }) t.test('skip existing', t => { - const dir = path.join(unpackdir, 'skip-newer') - t.teardown(() => rimraf(dir)) - const date = new Date('2011-03-27T22:16:31.000Z') - t.beforeEach(async () => { - await rimraf(dir) - await mkdirp(dir) - fs.writeFileSync(dir + '/x', 'y') + t.beforeEach(async t => { + const dir = t.testdir({ + x: 'y', + }) fs.utimesSync(dir + '/x', date, date) }) @@ -1569,6 +1546,7 @@ t.test('skip existing', t => { ]) const check = t => { + const dir = t.testdirName const st = fs.lstatSync(dir + '/x') t.equal(st.atime.toISOString(), date.toISOString()) t.equal(st.mtime.toISOString(), date.toISOString()) @@ -1578,6 +1556,7 @@ t.test('skip existing', t => { } t.test('async', t => { + const dir = t.testdirName new Unpack({ cwd: dir, keep: true, @@ -1587,6 +1566,7 @@ t.test('skip existing', t => { }) t.test('sync', t => { + const dir = t.testdirName new UnpackSync({ cwd: dir, keep: true, @@ -1598,14 +1578,9 @@ t.test('skip existing', t => { }) t.test('skip newer', t => { - const dir = path.join(unpackdir, 'skip-newer') - t.teardown(() => rimraf(dir)) - const date = new Date('2013-12-19T17:00:00.000Z') - t.beforeEach(async () => { - await rimraf(dir) - await mkdirp(dir) - fs.writeFileSync(dir + '/x', 'y') + t.beforeEach(async t => { + const dir = t.testdir({ x: 'y' }) fs.utimesSync(dir + '/x', date, date) }) @@ -1623,6 +1598,7 @@ t.test('skip newer', t => { ]) const check = t => { + const dir = t.testdirName const st = fs.lstatSync(dir + '/x') t.equal(st.atime.toISOString(), date.toISOString()) t.equal(st.mtime.toISOString(), date.toISOString()) @@ -1633,7 +1609,7 @@ t.test('skip newer', t => { t.test('async', t => { new Unpack({ - cwd: dir, + cwd: t.testdirName, newer: true, }) .on('close', () => check(t)) @@ -1642,7 +1618,7 @@ t.test('skip newer', t => { t.test('sync', t => { new UnpackSync({ - cwd: dir, + cwd: t.testdirName, newer: true, }).end(data) check(t) @@ -1652,14 +1628,6 @@ t.test('skip newer', t => { }) t.test('no mtime', t => { - const dir = path.join(unpackdir, 'skip-newer') - t.teardown(() => rimraf(dir)) - - t.beforeEach(async () => { - await rimraf(dir) - await mkdirp(dir) - }) - const date = new Date('2011-03-27T22:16:31.000Z') const data = makeTar([ { @@ -1685,6 +1653,7 @@ t.test('no mtime', t => { ]) const check = t => { + const dir = t.testdirName // this may fail if it's run on March 27, 2011 const stx = fs.lstatSync(dir + '/x') t.not(stx.atime.toISOString(), date.toISOString()) @@ -1698,6 +1667,7 @@ t.test('no mtime', t => { } t.test('async', t => { + const dir = t.testdir({}) new Unpack({ cwd: dir, noMtime: true, @@ -1707,6 +1677,7 @@ t.test('no mtime', t => { }) t.test('sync', t => { + const dir = t.testdir({}) new UnpackSync({ cwd: dir, noMtime: true, @@ -1718,9 +1689,7 @@ t.test('no mtime', t => { }) t.test('unpack big enough to pause/drain', t => { - const dir = path.resolve(unpackdir, 'drain-clog') - mkdirp.sync(dir) - t.teardown(() => rimraf(dir)) + const dir = t.testdir({}) const stream = fs.createReadStream(fixtures + '/parses.tar') const u = new Unpack({ cwd: dir, @@ -1747,31 +1716,22 @@ t.test('set owner', t => { // fake it on platforms that don't have getuid const myUid = 501 const myGid = 1024 - const getuid = process.getuid - const getgid = process.getgid - process.getuid = () => myUid - process.getgid = () => myGid - t.teardown( - () => ((process.getuid = getuid), (process.getgid = getgid)), - ) + t.capture(process, 'getuid', () => myUid) + t.capture(process, 'getgid', () => myGid) // can't actually do this because it requires root, but we can // verify that chown gets called. t.test('as root, defaults to true', t => { - const getuid = process.getuid - process.getuid = () => 0 + t.capture(process, 'getuid', () => 0) const u = new Unpack() t.equal(u.preserveOwner, true, 'preserveOwner enabled') - process.getuid = getuid t.end() }) t.test('as non-root, defaults to false', t => { - const getuid = process.getuid - process.getuid = () => 501 + t.capture(process, 'getuid', () => 501) const u = new Unpack() t.equal(u.preserveOwner, false, 'preserveOwner disabled') - process.getuid = getuid t.end() }) @@ -1840,7 +1800,6 @@ t.test('set owner', t => { ]) t.test('chown failure results in unpack failure', t => { - const dir = path.resolve(unpackdir, 'chown') const poop = new Error('expected chown failure') const un = mutateFS.fail('chown', poop) const unl = mutateFS.fail('lchown', poop) @@ -1850,15 +1809,13 @@ t.test('set owner', t => { un() unf() unl() - await rimraf(dir) }) t.test('sync', t => { - mkdirp.sync(dir) - t.teardown(() => rimraf(dir)) + const cwd = t.testdir({}) let warned = false const u = new UnpackSync({ - cwd: dir, + cwd, preserveOwner: true, onwarn: (_c, _m, er) => { if (!warned) { @@ -1872,11 +1829,10 @@ t.test('set owner', t => { }) t.test('async', t => { - mkdirp.sync(dir) - t.teardown(() => rimraf(dir)) + const cwd = t.testdir({}) let warned = false const u = new Unpack({ - cwd: dir, + cwd, preserveOwner: true, onwarn: (_c, _m, er) => { if (!warned) { @@ -1893,7 +1849,6 @@ t.test('set owner', t => { }) t.test('chown when true', t => { - const dir = path.resolve(unpackdir, 'chown') const chown = fs.chown const lchown = fs.lchown const fchown = fs.fchown @@ -1920,20 +1875,18 @@ t.test('set owner', t => { }) t.test('sync', t => { - mkdirp.sync(dir) - t.teardown(() => rimraf(dir)) + const cwd = t.testdir({}) called = 0 - const u = new UnpackSync({ cwd: dir, preserveOwner: true }) + const u = new UnpackSync({ cwd, preserveOwner: true }) u.end(data) t.ok(called >= 5, 'called chowns') t.end() }) t.test('async', t => { - mkdirp.sync(dir) - t.teardown(() => rimraf(dir)) + const cwd = t.testdir({}) called = 0 - const u = new Unpack({ cwd: dir, preserveOwner: true }) + const u = new Unpack({ cwd, preserveOwner: true }) u.end(data) u.on('close', () => { t.ok(called >= 5, 'called chowns') @@ -1945,7 +1898,6 @@ t.test('set owner', t => { }) t.test('no chown when false', t => { - const dir = path.resolve(unpackdir, 'nochown') const poop = new Error('poop') const un = mutateFS.fail('chown', poop) const unf = mutateFS.fail('fchown', poop) @@ -1954,13 +1906,10 @@ t.test('set owner', t => { un() unf() unl() - await rimraf(dir) }) - t.beforeEach(() => mkdirp(dir)) - t.afterEach(() => rimraf(dir)) - const check = t => { + const dir = t.testdirName const dirStat = fs.statSync(dir + '/foo') t.not(dirStat.uid, 2456124561) t.not(dirStat.gid, 813708013) @@ -1977,12 +1926,14 @@ t.test('set owner', t => { } t.test('sync', t => { + const dir = t.testdir({}) const u = new UnpackSync({ cwd: dir, preserveOwner: false }) u.end(data) check(t) }) t.test('async', t => { + const dir = t.testdir({}) const u = new Unpack({ cwd: dir, preserveOwner: false }) u.end(data) u.on('close', () => check(t)) @@ -2011,11 +1962,8 @@ t.test('unpack when dir is not writable', t => { '', ]) - const dir = path.resolve(unpackdir, 'nowrite-dir') - t.beforeEach(() => mkdirp(dir)) - t.afterEach(() => rimraf(dir)) - const check = t => { + const dir = t.testdirName t.equal( fs.statSync(dir + '/a').mode & 0o7777, isWindows ? 0o666 : 0o744, @@ -2025,12 +1973,14 @@ t.test('unpack when dir is not writable', t => { } t.test('sync', t => { + const dir = t.testdir({}) const u = new UnpackSync({ cwd: dir, strict: true }) u.end(data) check(t) }) t.test('async', t => { + const dir = t.testdir({}) const u = new Unpack({ cwd: dir, strict: true }) u.end(data) u.on('close', () => check(t)) @@ -2051,21 +2001,19 @@ t.test('transmute chars on windows', t => { '', ]) - const dir = path.resolve(unpackdir, 'winchars') - t.beforeEach(() => mkdirp(dir)) - t.afterEach(() => rimraf(dir)) - const hex = 'ef80bcef81bcef80beef80bfef80ba2e747874' const uglyName = Buffer.from(hex, 'hex').toString() - const ugly = path.resolve(dir, uglyName) const check = t => { + const dir = t.testdirName + const ugly = path.resolve(dir, uglyName) t.same(fs.readdirSync(dir), [uglyName]) t.equal(fs.readFileSync(ugly, 'utf8'), '<|>?:') t.end() } t.test('async', t => { + const dir = t.testdir({}) const u = new Unpack({ cwd: dir, win32: true, @@ -2075,6 +2023,7 @@ t.test('transmute chars on windows', t => { }) t.test('sync', t => { + const dir = t.testdir({}) const u = new UnpackSync({ cwd: dir, win32: true, @@ -2119,8 +2068,6 @@ t.test('safely transmute chars on windows with absolutes', t => { }) t.test('use explicit chmod when required by umask', t => { - const basedir = path.resolve(unpackdir, 'umask-chmod') - const data = makeTar([ { path: 'x/y/z', @@ -2132,16 +2079,16 @@ t.test('use explicit chmod when required by umask', t => { ]) const check = async t => { - const st = fs.statSync(basedir + '/x/y/z') + const cwd = t.testdirName + const st = fs.statSync(cwd + '/x/y/z') t.equal(st.mode & 0o777, isWindows ? 0o666 : 0o775) - await rimraf(basedir) t.end() } t.test('async', t => { - mkdirp.sync(basedir) + const cwd = t.testdir({}) const unpack = new Unpack({ - cwd: basedir, + cwd, chmod: true, processUmask: 0o22, }) @@ -2150,9 +2097,9 @@ t.test('use explicit chmod when required by umask', t => { }) return t.test('sync', t => { - mkdirp.sync(basedir) + const cwd = t.testdir({}) const unpack = new UnpackSync({ - cwd: basedir, + cwd, chmod: true, processUmask: 0o22, }) @@ -2166,8 +2113,6 @@ t.test('dont use explicit chmod if chmod flag not set', t => { throw new Error('should not call process.umask()') }) - const basedir = path.resolve(unpackdir, 'umask-no-chmod') - const data = makeTar([ { path: 'x/y/z', @@ -2179,29 +2124,29 @@ t.test('dont use explicit chmod if chmod flag not set', t => { ]) const check = async t => { - const st = fs.statSync(basedir + '/x/y/z') + const cwd = t.testdirName + const st = fs.statSync(cwd + '/x/y/z') t.equal(st.mode & 0o777, isWindows ? 0o666 : 0o755) - await rimraf(basedir) t.end() } t.test('async', t => { - mkdirp.sync(basedir) - const unpack = new Unpack({ cwd: basedir }) + const cwd = t.testdir({}) + const unpack = new Unpack({ cwd }) unpack.on('close', () => check(t)) unpack.end(data) }) return t.test('sync', t => { - mkdirp.sync(basedir) - const unpack = new UnpackSync({ cwd: basedir }) + const cwd = t.testdir({}) + const unpack = new UnpackSync({ cwd }) unpack.end(data) check(t) }) }) t.test('chown implicit dirs and also the entries', t => { - const basedir = path.resolve(unpackdir, 'chownr') + const basedir = t.testdir({}) // club these so that the test can run as non-root const chown = fs.chown @@ -2340,9 +2285,7 @@ t.test('chown implicit dirs and also the entries', t => { }) t.test('bad cwd setting', t => { - const basedir = path.resolve(unpackdir, 'bad-cwd') - mkdirp.sync(basedir) - t.teardown(() => rimraf(basedir)) + const basedir = t.testdir({}) const cases = [ // the cwd itself @@ -2435,9 +2378,6 @@ t.test('bad cwd setting', t => { }) t.test('transform', t => { - const basedir = path.resolve(unpackdir, 'transform') - t.teardown(() => rimraf(basedir)) - const cases = { 'emptypax.tar': { '🌟.txt': 'đŸŒŸâœ§âœŠâ­ī¸ŽâœĒâœĢâœŦ✭✎⚝✯✰âœĩâœļ✷✸✹❂⭑⭒★☆✡â˜Ēâœ´ī¸ŽâœĻâœĄī¸đŸ”¯âœ´ī¸đŸŒ \n', @@ -2488,13 +2428,9 @@ t.test('transform', t => { tarfiles.forEach(tarfile => { t.test(tarfile, t => { const tf = path.resolve(tars, tarfile) - const dir = path.resolve(basedir, tarfile) - t.beforeEach(async () => { - await rimraf(dir) - await mkdirp(dir) - }) const check = t => { + const dir = t.testdirName const expect = cases[tarfile] Object.keys(expect).forEach(file => { const f = path.resolve(dir, file) @@ -2508,6 +2444,7 @@ t.test('transform', t => { t.test('async unpack', t => { t.plan(2) t.test('strict', t => { + const dir = t.testdir({}) const unpack = new Unpack({ cwd: dir, strict: true, @@ -2517,6 +2454,7 @@ t.test('transform', t => { eos(unpack, () => check(t)) }) t.test('loose', t => { + const dir = t.testdir({}) const unpack = new Unpack({ cwd: dir, transform: txFn }) fs.createReadStream(tf).pipe(unpack) eos(unpack, () => check(t)) @@ -2526,6 +2464,7 @@ t.test('transform', t => { t.test('sync unpack', t => { t.plan(2) t.test('strict', t => { + const dir = t.testdir({}) const unpack = new UnpackSync({ cwd: dir, strict: true, @@ -2535,6 +2474,7 @@ t.test('transform', t => { check(t) }) t.test('loose', t => { + const dir = t.testdir({}) const unpack = new UnpackSync({ cwd: dir, transform: txFn }) unpack.end(fs.readFileSync(tf)) check(t) @@ -2545,10 +2485,6 @@ t.test('transform', t => { }) t.test('transform error', t => { - const dir = path.resolve(unpackdir, 'transform-error') - mkdirp.sync(dir) - t.teardown(() => rimraf(dir)) - const tarfile = path.resolve(tars, 'body-byte-counts.tar') const tardata = fs.readFileSync(tarfile) const poop = new Error('poop') @@ -2562,6 +2498,7 @@ t.test('transform error', t => { t.test('sync unpack', t => { t.test('strict', t => { + const dir = t.testdir({}) const unpack = new UnpackSync({ cwd: dir, strict: true, @@ -2578,6 +2515,7 @@ t.test('transform error', t => { t.end() }) t.test('loose', t => { + const dir = t.testdir({}) const unpack = new UnpackSync({ cwd: dir, transform: txFn }) const expect = 3 let actual = 0 @@ -2592,6 +2530,7 @@ t.test('transform error', t => { t.end() }) t.test('async unpack', t => { + const dir = t.testdir({}) // the last error is about the folder being deleted, just ignore that one t.test('strict', t => { const unpack = new Unpack({ @@ -2608,6 +2547,7 @@ t.test('transform error', t => { unpack.end(tardata) }) t.test('loose', t => { + const dir = t.testdir({}) const unpack = new Unpack({ cwd: dir, transform: txFn }) t.plan(3) t.teardown(() => unpack.removeAllListeners('warn')) @@ -2622,23 +2562,16 @@ t.test('transform error', t => { t.test('futimes/fchown failures', t => { const archive = path.resolve(tars, 'utf8.tar') - const dir = path.resolve(unpackdir, 'futimes-fchown-fails') const tardata = fs.readFileSync(archive) const poop = new Error('poop') const second = new Error('second error') - t.beforeEach(async () => { - await rimraf(dir) - await mkdirp(dir) - }) - - t.teardown(() => rimraf(dir)) - const methods = ['utimes', 'chown'] methods.forEach(method => { const fc = method === 'chown' t.test(method + ' fallback', t => { + const dir = t.testdir({}) t.teardown(mutateFS.fail('f' + method, poop)) // forceChown will fail on systems where the user is not root // and/or the uid/gid in the archive aren't valid. We're just @@ -2694,6 +2627,7 @@ t.test('futimes/fchown failures', t => { t.test('async unpack', t => { t.plan(2) t.test('strict', t => { + const dir = t.testdir({}) const unpack = new Unpack({ cwd: dir, strict: true, @@ -2704,6 +2638,7 @@ t.test('futimes/fchown failures', t => { unpack.end(tardata) }) t.test('loose', t => { + const dir = t.testdir({}) const unpack = new Unpack({ cwd: dir, forceChown: fc }) t.plan(3) unpack.on('warn', (_code, _m, er) => t.equal(er, poop)) @@ -2713,6 +2648,7 @@ t.test('futimes/fchown failures', t => { t.test('sync unpack', t => { t.plan(2) t.test('strict', t => { + const dir = t.testdir({}) const unpack = new UnpackSync({ cwd: dir, strict: true, @@ -2723,6 +2659,7 @@ t.test('futimes/fchown failures', t => { unpack.end(tardata) }) t.test('loose', t => { + const dir = t.testdir({}) const unpack = new UnpackSync({ cwd: dir, forceChown: fc }) t.plan(3) unpack.on('warn', (_c, _m, er) => t.equal(er, poop)) @@ -2736,10 +2673,6 @@ t.test('futimes/fchown failures', t => { }) t.test('onentry option is preserved', t => { - const basedir = path.resolve(unpackdir, 'onentry-method') - mkdirp.sync(basedir) - t.teardown(() => rimraf(basedir)) - let oecalls = 0 const onentry = _entry => oecalls++ const data = makeTar([ @@ -2772,15 +2705,14 @@ t.test('onentry option is preserved', t => { } t.test('sync', t => { - const dir = path.join(basedir, 'sync') - mkdirp.sync(dir) + const dir = t.testdir({}) const unpack = new UnpackSync({ cwd: dir, onentry }) unpack.end(data) check(t) }) t.test('async', t => { - const dir = path.join(basedir, 'async') + const dir = t.testdir({}) mkdirp.sync(dir) const unpack = new Unpack({ cwd: dir, onentry }) unpack.on('finish', () => check(t)) @@ -2791,10 +2723,6 @@ t.test('onentry option is preserved', t => { }) t.test('do not reuse hardlinks, only nlink=1 files', t => { - const basedir = path.resolve(unpackdir, 'hardlink-reuse') - mkdirp.sync(basedir) - t.teardown(() => rimraf(basedir)) - const now = new Date('2018-04-30T18:30:39.025Z') const data = makeTar([ @@ -2831,25 +2759,24 @@ t.test('do not reuse hardlinks, only nlink=1 files', t => { } const check = t => { + const dir = t.testdirName for (const f in checks) { - t.equal( - fs.readFileSync(basedir + '/' + f, 'utf8'), - checks[f], - f, - ) - t.equal(fs.statSync(basedir + '/' + f).nlink, 1, f) + t.equal(fs.readFileSync(dir + '/' + f, 'utf8'), checks[f], f) + t.equal(fs.statSync(dir + '/' + f).nlink, 1, f) } t.end() } t.test('async', t => { - const u = new Unpack({ cwd: basedir }) + const dir = t.testdir({}) + const u = new Unpack({ cwd: dir }) u.on('close', () => check(t)) u.end(data) }) t.test('sync', t => { - const u = new UnpackSync({ cwd: basedir }) + const dir = t.testdir({}) + const u = new UnpackSync({ cwd: dir }) u.end(data) check(t) }) @@ -2860,19 +2787,18 @@ t.test('do not reuse hardlinks, only nlink=1 files', t => { t.test('trying to unpack a non-zlib gzip file should fail', t => { const data = Buffer.from('hello this is not gzip data') const dataGzip = Buffer.concat([Buffer.from([0x1f, 0x8b]), data]) - const basedir = path.resolve(unpackdir, 'bad-archive') + t.test('abort if gzip has an error', t => { - t.plan(2) const expect = { message: /^zlib/, errno: Number, code: /^Z/, recoverable: false, - cwd: normPath(basedir), + cwd: normPath(t.testdirName), tarCode: 'TAR_ABORT', } const opts = { - cwd: basedir, + cwd: t.testdir({}), gzip: true, } new Unpack(opts) @@ -2887,6 +2813,7 @@ t.test('trying to unpack a non-zlib gzip file should fail', t => { 'sync throws', { skip }, ) + t.end() }) t.test('bad archive if no gzip', t => { @@ -2895,9 +2822,9 @@ t.test('trying to unpack a non-zlib gzip file should fail', t => { tarCode: 'TAR_BAD_ARCHIVE', recoverable: false, } - const opts = { cwd: basedir } + const opts = { cwd: t.testdir({}) } new Unpack(opts) - .on('error', er => t.match(er, expect, 'async emits')) + .once('error', er => t.match(er, expect, 'async emits')) .end(data) t.throws( () => new UnpackSync(opts).end(data), @@ -2911,17 +2838,9 @@ t.test('trying to unpack a non-zlib gzip file should fail', t => { t.test('handle errors on fs.close', t => { const poop = new Error('poop') - const { close, closeSync } = fs // have to actually close them, or else windows gets mad - fs.close = (fd, cb) => close(fd, () => cb(poop)) - fs.closeSync = fd => { - closeSync(fd) - throw poop - } - t.teardown(() => Object.assign(fs, { close, closeSync })) - const dir = path.resolve(unpackdir, 'close-fail') - mkdirp.sync(dir + '/sync') - mkdirp.sync(dir + '/async') + t.teardown(mutateFS.fail('close', poop)) + const data = makeTar([ { path: 'file', @@ -2937,18 +2856,24 @@ t.test('handle errors on fs.close', t => { ]) t.plan(2) - new Unpack({ cwd: dir + '/async', strict: true }) - .on('error', er => t.equal(er, poop, 'async')) - .end(data) - t.throws( - () => - new UnpackSync({ - cwd: normPath(dir + '/sync'), - strict: true, - }).end(data), - poop, - 'sync', - ) + t.test('async', t => { + new Unpack({ cwd: t.testdir({}), strict: true }) + .on('error', er => t.equal(er, poop, 'async')) + .on('end', () => t.end()) + .end(data) + }) + t.test('sync', t => { + t.throws( + () => + new UnpackSync({ + cwd: normPath(t.testdir({})), + strict: true, + }).end(data), + poop, + 'sync', + ) + t.end() + }) }) t.test( @@ -2957,9 +2882,6 @@ t.test( skip: isWindows && 'symlinks not fully supported', }, t => { - const dir = path.resolve(unpackdir, 'dir-cache-error') - mkdirp.sync(dir + '/sync/y') - mkdirp.sync(dir + '/async/y') const data = makeTar([ { path: 'x', @@ -2996,14 +2918,14 @@ t.test( t.end() } t.test('async', t => { - const path = dir + '/async' + const path = t.testdir({ y: {} }) new Unpack({ cwd: path }) .on('warn', (code, msg) => (WARNINGS[path] = [code, msg])) .on('end', () => check(t, path)) .end(data) }) t.test('sync', t => { - const path = dir + '/sync' + const path = t.testdir({ y: {} }) new UnpackSync({ cwd: path }) .on('warn', (code, msg) => (WARNINGS[path] = [code, msg])) .end(data) @@ -3013,9 +2935,6 @@ t.test( ) t.test('using strip option when top level file exists', t => { - const dir = path.resolve(unpackdir, 'strip-with-top-file') - mkdirp.sync(dir + '/sync/y') - mkdirp.sync(dir + '/async/y') const data = makeTar([ { path: 'top', @@ -3054,13 +2973,13 @@ t.test('using strip option when top level file exists', t => { t.end() } t.test('async', t => { - const path = dir + '/async' + const path = t.testdir({ y: {} }) new Unpack({ cwd: path, strip: 1 }) .on('end', () => check(t, path)) .end(data) }) t.test('sync', t => { - const path = dir + '/sync' + const path = t.testdir({ y: {} }) new UnpackSync({ cwd: path, strip: 1 }).end(data) check(t, path) }) @@ -3110,11 +3029,7 @@ t.test('handle EPERMs when creating symlinks', t => { '', ]) - const dir = path.resolve(unpackdir, 'eperm-symlinks') - mkdirp.sync(`${dir}/sync`) - mkdirp.sync(`${dir}/async`) - - const check = path => { + const check = (t, path) => { t.match( WARNINGS, [ @@ -3134,21 +3049,29 @@ t.test('handle EPERMs when creating symlinks', t => { } const WARNINGS = [] - const u = new Unpack({ - cwd: `${dir}/async`, - onwarn: (code, msg, _er) => WARNINGS.push([code, msg]), + t.test('async', t => { + const dir = t.testdir({}) + const u = new Unpack({ + cwd: dir, + onwarn: (code, msg, _er) => WARNINGS.push([code, msg]), + }) + u.on('end', () => { + check(t, dir) + t.end() + }) + u.end(data) }) - u.on('end', () => { - check(`${dir}/async`) + t.test('sync', t => { + const dir = t.testdir({}) const u = new UnpackSync({ - cwd: `${dir}/sync`, + cwd: dir, onwarn: (code, msg, _er) => WARNINGS.push([code, msg]), }) u.end(data) - check(`${dir}/sync`) + check(t, dir) t.end() }) - u.end(data) + t.end() }) t.test('close fd when error writing', t => { @@ -3186,8 +3109,8 @@ t.test('close fd when error writing', t => { }), ) const WARNINGS = [] - const dir = path.resolve(unpackdir, 'close-on-write-error') - mkdirp.sync(dir) + + const dir = t.testdir({}) const unpack = new Unpack({ cwd: dir, onwarn: (code, msg) => WARNINGS.push([code, msg]), @@ -3225,15 +3148,14 @@ t.test('close fd when error setting mtime', t => { const CLOSES = [] const OPENS = {} const { open } = fs - t.teardown(() => (fs.open = open)) - fs.open = (...args) => { + t.capture(fs, 'open', (...args) => { const cb = args.pop() args.push((er, fd) => { OPENS[args[0]] = fd cb(er, fd) }) return open.call(fs, ...args) - } + }) t.teardown( mutateFS.mutateArgs('close', ([fd]) => { CLOSES.push(fd) @@ -3241,8 +3163,7 @@ t.test('close fd when error setting mtime', t => { }), ) const WARNINGS = [] - const dir = path.resolve(unpackdir, 'close-on-futimes-error') - mkdirp.sync(dir) + const dir = t.testdir({}) const unpack = new Unpack({ cwd: dir, onwarn: (code, msg) => WARNINGS.push([code, msg]), @@ -3272,11 +3193,8 @@ t.test('do not hang on large files that fail to open()', t => { '', ]) t.teardown(mutateFS.fail('open', new Error('nope'))) - const dir = path.resolve( - unpackdir, - 'no-hang-for-large-file-failures', - ) - mkdirp.sync(dir) + const dir = t.testdir({}) + const WARNINGS = [] const unpack = new Unpack({ cwd: dir, From 314ec7e64245f86663c8ca20fad05ebb5a390d80 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 10 Apr 2024 10:26:05 -0700 Subject: [PATCH 68/96] list: close file even if no error thrown Fix: #404 --- src/list.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/list.ts b/src/list.ts index 7ba43143..9173edaa 100644 --- a/src/list.ts +++ b/src/list.ts @@ -130,7 +130,6 @@ const filesFilter = (opt: TarOptions, files: string[]) => { const listFileSync = (opt: TarOptionsSyncFile) => { const p = list_(opt) const file = opt.file - let threw = true let fd try { const stat = fs.statSync(file) @@ -148,9 +147,8 @@ const listFileSync = (opt: TarOptionsSyncFile) => { } p.end() } - threw = false } finally { - if (threw && fd) { + if (typeof fd === 'number') { try { fs.closeSync(fd) /* c8 ignore next */ From 2d89a4edc3dd76aef0bde3a9913cdb4f9c9d3b77 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 10 Apr 2024 10:59:50 -0700 Subject: [PATCH 69/96] Properly handle long linkpath in PaxHeader tar-stream creates some interesting tarballs, but they are technically allowed, and should be handled properly. Fix: #312 Also, this cleans up a flaky race condition in the unpack test. --- src/parse.ts | 1 + test/extract.js | 14 ++++++++++++++ test/fixtures/long-linkname.tar | Bin 0 -> 2560 bytes test/unpack.js | 8 ++++++-- 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/long-linkname.tar diff --git a/src/parse.ts b/src/parse.ts index d0b0781e..0147f786 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -199,6 +199,7 @@ export class Parser extends EE implements Warner { }) } else if ( !/^(Symbolic)?Link$/.test(type) && + !/^(Global)?ExtendedHeader$/.test(type) && header.linkpath ) { this.warn('TAR_ENTRY_INVALID', 'linkpath forbidden', { diff --git a/test/extract.js b/test/extract.js index 8fe8eff1..ce2afeb7 100644 --- a/test/extract.js +++ b/test/extract.js @@ -415,3 +415,17 @@ t.test('brotli', async t => { t.end() }) }) + +t.test('verify long linkname is not a problem', async t => { + // See: https://github.com/isaacs/node-tar/issues/312 + const file = path.resolve(__dirname, 'fixtures/long-linkname.tar') + t.test('sync', t => { + x({ sync: true, strict: true, file, C: t.testdir({}) }) + t.ok(fs.lstatSync(t.testdirName + '/test').isSymbolicLink()) + t.end() + }) + t.test('async', async t => { + await x({ file, C: t.testdir({}), strict: true }) + t.ok(fs.lstatSync(t.testdirName + '/test').isSymbolicLink()) + }) +}) diff --git a/test/fixtures/long-linkname.tar b/test/fixtures/long-linkname.tar new file mode 100644 index 0000000000000000000000000000000000000000..34c0ea57d17b34911ef760553c67b7428d611138 GIT binary patch literal 2560 zcmWGYtnf%pOi3+bpdBzUFfcPQQD6YlK!8pg7#NuvD;S!X8JL=yn3<WHC>R(TnHw1@ zFjNH4!EvR<C5c5qr%~#Cbk9+09-Z_X8Y>hemSotLq!yQO8Jb!s<YeY$gGCYt0Vqo? zs?5pHOV3NpP359fh>R?2=#j;MSp#qW2Neov`QOX{nE#FF;kXf=|3_A8ANB2M2#kgR HatHtb<eqDt literal 0 HcmV?d00001 diff --git a/test/unpack.js b/test/unpack.js index f7c4f88a..2f167a30 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -1821,11 +1821,12 @@ t.test('set owner', t => { if (!warned) { warned = true t.equal(er, poop) - t.end() } }, }) u.end(data) + t.equal(warned, true) + t.end() }) t.test('async', t => { @@ -1838,10 +1839,13 @@ t.test('set owner', t => { if (!warned) { warned = true t.equal(er, poop) - t.end() } }, }) + u.on('finish', () => { + t.equal(warned, true) + t.end() + }) u.end(data) }) From 9a260c2dbaf9090c34872944393dfd854940c7c6 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 10 Apr 2024 11:08:26 -0700 Subject: [PATCH 70/96] test verifying #398 is fixed --- tap-snapshots/test/unpack.js.test.cjs | 18 ++++++++++++++ test/unpack.js | 34 ++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tap-snapshots/test/unpack.js.test.cjs diff --git a/tap-snapshots/test/unpack.js.test.cjs b/tap-snapshots/test/unpack.js.test.cjs new file mode 100644 index 00000000..2446eb2e --- /dev/null +++ b/tap-snapshots/test/unpack.js.test.cjs @@ -0,0 +1,18 @@ +/* IMPORTANT + * This snapshot file is auto-generated, but designed for humans. + * It should be checked into source control and tracked carefully. + * Re-generate by setting TAP_SNAPSHOT=1 and running tests. + * Make sure to inspect the output below. Do not ignore changes! + */ +'use strict' +exports[`test/unpack.js > TAP > ignore self-referential hardlinks > async > must match snapshot 1`] = ` +Array [ + "ENOENT: no such file or directory, link '{CWD}/.tap/fixtures/test-unpack.js-ignore-self-referential-hardlinks-async/autolink' -> '{CWD}/.tap/fixtures/test-unpack.js-ignore-self-referential-hardlinks-async/autolink'", +] +` + +exports[`test/unpack.js > TAP > ignore self-referential hardlinks > sync > must match snapshot 1`] = ` +Array [ + "ENOENT: no such file or directory, link '{CWD}/.tap/fixtures/test-unpack.js-ignore-self-referential-hardlinks-sync/autolink' -> '{CWD}/.tap/fixtures/test-unpack.js-ignore-self-referential-hardlinks-sync/autolink'", +] +` diff --git a/test/unpack.js b/test/unpack.js index 2f167a30..bcffa0c9 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -1,6 +1,6 @@ import { Unpack, UnpackSync } from '../dist/esm/unpack.js' -import fs from 'fs' +import fs, { readdirSync } from 'fs' import { Minipass } from 'minipass' import * as z from 'minizlib' import path from 'path' @@ -3531,3 +3531,35 @@ t.test('excessively deep subfolder nesting', async t => { check(t, 64) }) }) + +t.test('ignore self-referential hardlinks', async t => { + const data = makeTar([ + { + path: 'autolink', + linkpath: './autolink', + type: 'Link', + }, + ]) + const check = (t, warnings) => { + t.matchSnapshot(warnings) + t.strictSame(readdirSync(t.testdirName), [], 'nothing extracted') + t.end() + } + t.test('async', t => { + const cwd = t.testdir({}) + const warnings = [] + const u = new Unpack({ cwd, onwarn: (_, m) => warnings.push(m) }) + u.on('end', () => check(t, warnings)) + u.end(data) + }) + t.test('sync', t => { + const cwd = t.testdir({}) + const warnings = [] + const u = new UnpackSync({ + cwd, + onwarn: (_, m) => warnings.push(m), + }) + u.end(data) + check(t, warnings) + }) +}) From 957da7506cc594f24f54b884305718927194fb73 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 10 Apr 2024 12:06:43 -0700 Subject: [PATCH 71/96] remove old lib folder --- lib/create.js | 111 ---- lib/extract.js | 113 ----- lib/get-write-flag.js | 20 - lib/header.js | 304 ----------- lib/high-level-opt.js | 29 -- lib/large-numbers.js | 104 ---- lib/list.js | 139 ----- lib/mkdir.js | 229 --------- lib/mode-fix.js | 27 - lib/normalize-unicode.js | 12 - lib/normalize-windows-path.js | 8 - lib/pack.js | 432 ---------------- lib/parse.js | 552 -------------------- lib/path-reservations.js | 163 ------ lib/pax.js | 150 ------ lib/read-entry.js | 107 ---- lib/replace.js | 246 --------- lib/strip-absolute-path.js | 24 - lib/strip-trailing-slashes.js | 13 - lib/types.js | 44 -- lib/unpack.js | 923 ---------------------------------- lib/update.js | 40 -- lib/warn-mixin.js | 24 - lib/winchars.js | 23 - lib/write-entry.js | 546 -------------------- 25 files changed, 4383 deletions(-) delete mode 100644 lib/create.js delete mode 100644 lib/extract.js delete mode 100644 lib/get-write-flag.js delete mode 100644 lib/header.js delete mode 100644 lib/high-level-opt.js delete mode 100644 lib/large-numbers.js delete mode 100644 lib/list.js delete mode 100644 lib/mkdir.js delete mode 100644 lib/mode-fix.js delete mode 100644 lib/normalize-unicode.js delete mode 100644 lib/normalize-windows-path.js delete mode 100644 lib/pack.js delete mode 100644 lib/parse.js delete mode 100644 lib/path-reservations.js delete mode 100644 lib/pax.js delete mode 100644 lib/read-entry.js delete mode 100644 lib/replace.js delete mode 100644 lib/strip-absolute-path.js delete mode 100644 lib/strip-trailing-slashes.js delete mode 100644 lib/types.js delete mode 100644 lib/unpack.js delete mode 100644 lib/update.js delete mode 100644 lib/warn-mixin.js delete mode 100644 lib/winchars.js delete mode 100644 lib/write-entry.js diff --git a/lib/create.js b/lib/create.js deleted file mode 100644 index 9c860d4e..00000000 --- a/lib/create.js +++ /dev/null @@ -1,111 +0,0 @@ -'use strict' - -// tar -c -const hlo = require('./high-level-opt.js') - -const Pack = require('./pack.js') -const fsm = require('fs-minipass') -const t = require('./list.js') -const path = require('path') - -module.exports = (opt_, files, cb) => { - if (typeof files === 'function') { - cb = files - } - - if (Array.isArray(opt_)) { - files = opt_, opt_ = {} - } - - if (!files || !Array.isArray(files) || !files.length) { - throw new TypeError('no files or directories specified') - } - - files = Array.from(files) - - const opt = hlo(opt_) - - if (opt.sync && typeof cb === 'function') { - throw new TypeError('callback not supported for sync tar functions') - } - - if (!opt.file && typeof cb === 'function') { - throw new TypeError('callback only supported with file option') - } - - return opt.file && opt.sync ? createFileSync(opt, files) - : opt.file ? createFile(opt, files, cb) - : opt.sync ? createSync(opt, files) - : create(opt, files) -} - -const createFileSync = (opt, files) => { - const p = new Pack.Sync(opt) - const stream = new fsm.WriteStreamSync(opt.file, { - mode: opt.mode || 0o666, - }) - p.pipe(stream) - addFilesSync(p, files) -} - -const createFile = (opt, files, cb) => { - const p = new Pack(opt) - const stream = new fsm.WriteStream(opt.file, { - mode: opt.mode || 0o666, - }) - p.pipe(stream) - - const promise = new Promise((res, rej) => { - stream.on('error', rej) - stream.on('close', res) - p.on('error', rej) - }) - - addFilesAsync(p, files) - - return cb ? promise.then(cb, cb) : promise -} - -const addFilesSync = (p, files) => { - files.forEach(file => { - if (file.charAt(0) === '@') { - t({ - file: path.resolve(p.cwd, file.slice(1)), - sync: true, - noResume: true, - onentry: entry => p.add(entry), - }) - } else { - p.add(file) - } - }) - p.end() -} - -const addFilesAsync = (p, files) => { - while (files.length) { - const file = files.shift() - if (file.charAt(0) === '@') { - return t({ - file: path.resolve(p.cwd, file.slice(1)), - noResume: true, - onentry: entry => p.add(entry), - }).then(_ => addFilesAsync(p, files)) - } else { - p.add(file) - } - } - p.end() -} - -const createSync = (opt, files) => { - const p = new Pack.Sync(opt) - addFilesSync(p, files) - return p -} - -const create = (opt, files) => { - const p = new Pack(opt) - addFilesAsync(p, files) - return p -} diff --git a/lib/extract.js b/lib/extract.js deleted file mode 100644 index 54767982..00000000 --- a/lib/extract.js +++ /dev/null @@ -1,113 +0,0 @@ -'use strict' - -// tar -x -const hlo = require('./high-level-opt.js') -const Unpack = require('./unpack.js') -const fs = require('fs') -const fsm = require('fs-minipass') -const path = require('path') -const stripSlash = require('./strip-trailing-slashes.js') - -module.exports = (opt_, files, cb) => { - if (typeof opt_ === 'function') { - cb = opt_, files = null, opt_ = {} - } else if (Array.isArray(opt_)) { - files = opt_, opt_ = {} - } - - if (typeof files === 'function') { - cb = files, files = null - } - - if (!files) { - files = [] - } else { - files = Array.from(files) - } - - const opt = hlo(opt_) - - if (opt.sync && typeof cb === 'function') { - throw new TypeError('callback not supported for sync tar functions') - } - - if (!opt.file && typeof cb === 'function') { - throw new TypeError('callback only supported with file option') - } - - if (files.length) { - filesFilter(opt, files) - } - - return opt.file && opt.sync ? extractFileSync(opt) - : opt.file ? extractFile(opt, cb) - : opt.sync ? extractSync(opt) - : extract(opt) -} - -// construct a filter that limits the file entries listed -// include child entries if a dir is included -const filesFilter = (opt, files) => { - const map = new Map(files.map(f => [stripSlash(f), true])) - const filter = opt.filter - - const mapHas = (file, r) => { - const root = r || path.parse(file).root || '.' - const ret = file === root ? false - : map.has(file) ? map.get(file) - : mapHas(path.dirname(file), root) - - map.set(file, ret) - return ret - } - - opt.filter = filter - ? (file, entry) => filter(file, entry) && mapHas(stripSlash(file)) - : file => mapHas(stripSlash(file)) -} - -const extractFileSync = opt => { - const u = new Unpack.Sync(opt) - - const file = opt.file - const stat = fs.statSync(file) - // This trades a zero-byte read() syscall for a stat - // However, it will usually result in less memory allocation - const readSize = opt.maxReadSize || 16 * 1024 * 1024 - const stream = new fsm.ReadStreamSync(file, { - readSize: readSize, - size: stat.size, - }) - stream.pipe(u) -} - -const extractFile = (opt, cb) => { - const u = new Unpack(opt) - const readSize = opt.maxReadSize || 16 * 1024 * 1024 - - const file = opt.file - const p = new Promise((resolve, reject) => { - u.on('error', reject) - u.on('close', resolve) - - // This trades a zero-byte read() syscall for a stat - // However, it will usually result in less memory allocation - fs.stat(file, (er, stat) => { - if (er) { - reject(er) - } else { - const stream = new fsm.ReadStream(file, { - readSize: readSize, - size: stat.size, - }) - stream.on('error', reject) - stream.pipe(u) - } - }) - }) - return cb ? p.then(cb, cb) : p -} - -const extractSync = opt => new Unpack.Sync(opt) - -const extract = opt => new Unpack(opt) diff --git a/lib/get-write-flag.js b/lib/get-write-flag.js deleted file mode 100644 index e8695999..00000000 --- a/lib/get-write-flag.js +++ /dev/null @@ -1,20 +0,0 @@ -// Get the appropriate flag to use for creating files -// We use fmap on Windows platforms for files less than -// 512kb. This is a fairly low limit, but avoids making -// things slower in some cases. Since most of what this -// library is used for is extracting tarballs of many -// relatively small files in npm packages and the like, -// it can be a big boost on Windows platforms. -// Only supported in Node v12.9.0 and above. -const platform = process.env.__FAKE_PLATFORM__ || process.platform -const isWindows = platform === 'win32' -const fs = global.__FAKE_TESTING_FS__ || require('fs') - -/* istanbul ignore next */ -const { O_CREAT, O_TRUNC, O_WRONLY, UV_FS_O_FILEMAP = 0 } = fs.constants - -const fMapEnabled = isWindows && !!UV_FS_O_FILEMAP -const fMapLimit = 512 * 1024 -const fMapFlag = UV_FS_O_FILEMAP | O_TRUNC | O_CREAT | O_WRONLY -module.exports = !fMapEnabled ? () => 'w' - : size => size < fMapLimit ? fMapFlag : 'w' diff --git a/lib/header.js b/lib/header.js deleted file mode 100644 index 411d5e45..00000000 --- a/lib/header.js +++ /dev/null @@ -1,304 +0,0 @@ -'use strict' -// parse a 512-byte header block to a data object, or vice-versa -// encode returns `true` if a pax extended header is needed, because -// the data could not be faithfully encoded in a simple header. -// (Also, check header.needPax to see if it needs a pax header.) - -const types = require('./types.js') -const pathModule = require('path').posix -const large = require('./large-numbers.js') - -const SLURP = Symbol('slurp') -const TYPE = Symbol('type') - -class Header { - constructor (data, off, ex, gex) { - this.cksumValid = false - this.needPax = false - this.nullBlock = false - - this.block = null - this.path = null - this.mode = null - this.uid = null - this.gid = null - this.size = null - this.mtime = null - this.cksum = null - this[TYPE] = '0' - this.linkpath = null - this.uname = null - this.gname = null - this.devmaj = 0 - this.devmin = 0 - this.atime = null - this.ctime = null - - if (Buffer.isBuffer(data)) { - this.decode(data, off || 0, ex, gex) - } else if (data) { - this.set(data) - } - } - - decode (buf, off, ex, gex) { - if (!off) { - off = 0 - } - - if (!buf || !(buf.length >= off + 512)) { - throw new Error('need 512 bytes for header') - } - - this.path = decString(buf, off, 100) - this.mode = decNumber(buf, off + 100, 8) - this.uid = decNumber(buf, off + 108, 8) - this.gid = decNumber(buf, off + 116, 8) - this.size = decNumber(buf, off + 124, 12) - this.mtime = decDate(buf, off + 136, 12) - this.cksum = decNumber(buf, off + 148, 12) - - // if we have extended or global extended headers, apply them now - // See https://github.com/npm/node-tar/pull/187 - this[SLURP](ex) - this[SLURP](gex, true) - - // old tar versions marked dirs as a file with a trailing / - this[TYPE] = decString(buf, off + 156, 1) - if (this[TYPE] === '') { - this[TYPE] = '0' - } - if (this[TYPE] === '0' && this.path.slice(-1) === '/') { - this[TYPE] = '5' - } - - // tar implementations sometimes incorrectly put the stat(dir).size - // as the size in the tarball, even though Directory entries are - // not able to have any body at all. In the very rare chance that - // it actually DOES have a body, we weren't going to do anything with - // it anyway, and it'll just be a warning about an invalid header. - if (this[TYPE] === '5') { - this.size = 0 - } - - this.linkpath = decString(buf, off + 157, 100) - if (buf.slice(off + 257, off + 265).toString() === 'ustar\u000000') { - this.uname = decString(buf, off + 265, 32) - this.gname = decString(buf, off + 297, 32) - this.devmaj = decNumber(buf, off + 329, 8) - this.devmin = decNumber(buf, off + 337, 8) - if (buf[off + 475] !== 0) { - // definitely a prefix, definitely >130 chars. - const prefix = decString(buf, off + 345, 155) - this.path = prefix + '/' + this.path - } else { - const prefix = decString(buf, off + 345, 130) - if (prefix) { - this.path = prefix + '/' + this.path - } - this.atime = decDate(buf, off + 476, 12) - this.ctime = decDate(buf, off + 488, 12) - } - } - - let sum = 8 * 0x20 - for (let i = off; i < off + 148; i++) { - sum += buf[i] - } - - for (let i = off + 156; i < off + 512; i++) { - sum += buf[i] - } - - this.cksumValid = sum === this.cksum - if (this.cksum === null && sum === 8 * 0x20) { - this.nullBlock = true - } - } - - [SLURP] (ex, global) { - for (const k in ex) { - // we slurp in everything except for the path attribute in - // a global extended header, because that's weird. - if (ex[k] !== null && ex[k] !== undefined && - !(global && k === 'path')) { - this[k] = ex[k] - } - } - } - - encode (buf, off) { - if (!buf) { - buf = this.block = Buffer.alloc(512) - off = 0 - } - - if (!off) { - off = 0 - } - - if (!(buf.length >= off + 512)) { - throw new Error('need 512 bytes for header') - } - - const prefixSize = this.ctime || this.atime ? 130 : 155 - const split = splitPrefix(this.path || '', prefixSize) - const path = split[0] - const prefix = split[1] - this.needPax = split[2] - - this.needPax = encString(buf, off, 100, path) || this.needPax - this.needPax = encNumber(buf, off + 100, 8, this.mode) || this.needPax - this.needPax = encNumber(buf, off + 108, 8, this.uid) || this.needPax - this.needPax = encNumber(buf, off + 116, 8, this.gid) || this.needPax - this.needPax = encNumber(buf, off + 124, 12, this.size) || this.needPax - this.needPax = encDate(buf, off + 136, 12, this.mtime) || this.needPax - buf[off + 156] = this[TYPE].charCodeAt(0) - this.needPax = encString(buf, off + 157, 100, this.linkpath) || this.needPax - buf.write('ustar\u000000', off + 257, 8) - this.needPax = encString(buf, off + 265, 32, this.uname) || this.needPax - this.needPax = encString(buf, off + 297, 32, this.gname) || this.needPax - this.needPax = encNumber(buf, off + 329, 8, this.devmaj) || this.needPax - this.needPax = encNumber(buf, off + 337, 8, this.devmin) || this.needPax - this.needPax = encString(buf, off + 345, prefixSize, prefix) || this.needPax - if (buf[off + 475] !== 0) { - this.needPax = encString(buf, off + 345, 155, prefix) || this.needPax - } else { - this.needPax = encString(buf, off + 345, 130, prefix) || this.needPax - this.needPax = encDate(buf, off + 476, 12, this.atime) || this.needPax - this.needPax = encDate(buf, off + 488, 12, this.ctime) || this.needPax - } - - let sum = 8 * 0x20 - for (let i = off; i < off + 148; i++) { - sum += buf[i] - } - - for (let i = off + 156; i < off + 512; i++) { - sum += buf[i] - } - - this.cksum = sum - encNumber(buf, off + 148, 8, this.cksum) - this.cksumValid = true - - return this.needPax - } - - set (data) { - for (const i in data) { - if (data[i] !== null && data[i] !== undefined) { - this[i] = data[i] - } - } - } - - get type () { - return types.name.get(this[TYPE]) || this[TYPE] - } - - get typeKey () { - return this[TYPE] - } - - set type (type) { - if (types.code.has(type)) { - this[TYPE] = types.code.get(type) - } else { - this[TYPE] = type - } - } -} - -const splitPrefix = (p, prefixSize) => { - const pathSize = 100 - let pp = p - let prefix = '' - let ret - const root = pathModule.parse(p).root || '.' - - if (Buffer.byteLength(pp) < pathSize) { - ret = [pp, prefix, false] - } else { - // first set prefix to the dir, and path to the base - prefix = pathModule.dirname(pp) - pp = pathModule.basename(pp) - - do { - if (Buffer.byteLength(pp) <= pathSize && - Buffer.byteLength(prefix) <= prefixSize) { - // both fit! - ret = [pp, prefix, false] - } else if (Buffer.byteLength(pp) > pathSize && - Buffer.byteLength(prefix) <= prefixSize) { - // prefix fits in prefix, but path doesn't fit in path - ret = [pp.slice(0, pathSize - 1), prefix, true] - } else { - // make path take a bit from prefix - pp = pathModule.join(pathModule.basename(prefix), pp) - prefix = pathModule.dirname(prefix) - } - } while (prefix !== root && !ret) - - // at this point, found no resolution, just truncate - if (!ret) { - ret = [p.slice(0, pathSize - 1), '', true] - } - } - return ret -} - -const decString = (buf, off, size) => - buf.slice(off, off + size).toString('utf8').replace(/\0.*/, '') - -const decDate = (buf, off, size) => - numToDate(decNumber(buf, off, size)) - -const numToDate = num => num === null ? null : new Date(num * 1000) - -const decNumber = (buf, off, size) => - buf[off] & 0x80 ? large.parse(buf.slice(off, off + size)) - : decSmallNumber(buf, off, size) - -const nanNull = value => isNaN(value) ? null : value - -const decSmallNumber = (buf, off, size) => - nanNull(parseInt( - buf.slice(off, off + size) - .toString('utf8').replace(/\0.*$/, '').trim(), 8)) - -// the maximum encodable as a null-terminated octal, by field size -const MAXNUM = { - 12: 0o77777777777, - 8: 0o7777777, -} - -const encNumber = (buf, off, size, number) => - number === null ? false : - number > MAXNUM[size] || number < 0 - ? (large.encode(number, buf.slice(off, off + size)), true) - : (encSmallNumber(buf, off, size, number), false) - -const encSmallNumber = (buf, off, size, number) => - buf.write(octalString(number, size), off, size, 'ascii') - -const octalString = (number, size) => - padOctal(Math.floor(number).toString(8), size) - -const padOctal = (string, size) => - (string.length === size - 1 ? string - : new Array(size - string.length - 1).join('0') + string + ' ') + '\0' - -const encDate = (buf, off, size, date) => - date === null ? false : - encNumber(buf, off, size, date.getTime() / 1000) - -// enough to fill the longest string we've got -const NULLS = new Array(156).join('\0') -// pad with nulls, return true if it's longer or non-ascii -const encString = (buf, off, size, string) => - string === null ? false : - (buf.write(string + NULLS, off, size, 'utf8'), - string.length !== Buffer.byteLength(string) || string.length > size) - -module.exports = Header diff --git a/lib/high-level-opt.js b/lib/high-level-opt.js deleted file mode 100644 index 40e44180..00000000 --- a/lib/high-level-opt.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict' - -// turn tar(1) style args like `C` into the more verbose things like `cwd` - -const argmap = new Map([ - ['C', 'cwd'], - ['f', 'file'], - ['z', 'gzip'], - ['P', 'preservePaths'], - ['U', 'unlink'], - ['strip-components', 'strip'], - ['stripComponents', 'strip'], - ['keep-newer', 'newer'], - ['keepNewer', 'newer'], - ['keep-newer-files', 'newer'], - ['keepNewerFiles', 'newer'], - ['k', 'keep'], - ['keep-existing', 'keep'], - ['keepExisting', 'keep'], - ['m', 'noMtime'], - ['no-mtime', 'noMtime'], - ['p', 'preserveOwner'], - ['L', 'follow'], - ['h', 'follow'], -]) - -module.exports = opt => opt ? Object.keys(opt).map(k => [ - argmap.has(k) ? argmap.get(k) : k, opt[k], -]).reduce((set, kv) => (set[kv[0]] = kv[1], set), Object.create(null)) : {} diff --git a/lib/large-numbers.js b/lib/large-numbers.js deleted file mode 100644 index b11e72d9..00000000 --- a/lib/large-numbers.js +++ /dev/null @@ -1,104 +0,0 @@ -'use strict' -// Tar can encode large and negative numbers using a leading byte of -// 0xff for negative, and 0x80 for positive. - -const encode = (num, buf) => { - if (!Number.isSafeInteger(num)) { - // The number is so large that javascript cannot represent it with integer - // precision. - throw Error('cannot encode number outside of javascript safe integer range') - } else if (num < 0) { - encodeNegative(num, buf) - } else { - encodePositive(num, buf) - } - return buf -} - -const encodePositive = (num, buf) => { - buf[0] = 0x80 - - for (var i = buf.length; i > 1; i--) { - buf[i - 1] = num & 0xff - num = Math.floor(num / 0x100) - } -} - -const encodeNegative = (num, buf) => { - buf[0] = 0xff - var flipped = false - num = num * -1 - for (var i = buf.length; i > 1; i--) { - var byte = num & 0xff - num = Math.floor(num / 0x100) - if (flipped) { - buf[i - 1] = onesComp(byte) - } else if (byte === 0) { - buf[i - 1] = 0 - } else { - flipped = true - buf[i - 1] = twosComp(byte) - } - } -} - -const parse = (buf) => { - const pre = buf[0] - const value = pre === 0x80 ? pos(buf.slice(1, buf.length)) - : pre === 0xff ? twos(buf) - : null - if (value === null) { - throw Error('invalid base256 encoding') - } - - if (!Number.isSafeInteger(value)) { - // The number is so large that javascript cannot represent it with integer - // precision. - throw Error('parsed number outside of javascript safe integer range') - } - - return value -} - -const twos = (buf) => { - var len = buf.length - var sum = 0 - var flipped = false - for (var i = len - 1; i > -1; i--) { - var byte = buf[i] - var f - if (flipped) { - f = onesComp(byte) - } else if (byte === 0) { - f = byte - } else { - flipped = true - f = twosComp(byte) - } - if (f !== 0) { - sum -= f * Math.pow(256, len - i - 1) - } - } - return sum -} - -const pos = (buf) => { - var len = buf.length - var sum = 0 - for (var i = len - 1; i > -1; i--) { - var byte = buf[i] - if (byte !== 0) { - sum += byte * Math.pow(256, len - i - 1) - } - } - return sum -} - -const onesComp = byte => (0xff ^ byte) & 0xff - -const twosComp = byte => ((0xff ^ byte) + 1) & 0xff - -module.exports = { - encode, - parse, -} diff --git a/lib/list.js b/lib/list.js deleted file mode 100644 index f2358c25..00000000 --- a/lib/list.js +++ /dev/null @@ -1,139 +0,0 @@ -'use strict' - -// XXX: This shares a lot in common with extract.js -// maybe some DRY opportunity here? - -// tar -t -const hlo = require('./high-level-opt.js') -const Parser = require('./parse.js') -const fs = require('fs') -const fsm = require('fs-minipass') -const path = require('path') -const stripSlash = require('./strip-trailing-slashes.js') - -module.exports = (opt_, files, cb) => { - if (typeof opt_ === 'function') { - cb = opt_, files = null, opt_ = {} - } else if (Array.isArray(opt_)) { - files = opt_, opt_ = {} - } - - if (typeof files === 'function') { - cb = files, files = null - } - - if (!files) { - files = [] - } else { - files = Array.from(files) - } - - const opt = hlo(opt_) - - if (opt.sync && typeof cb === 'function') { - throw new TypeError('callback not supported for sync tar functions') - } - - if (!opt.file && typeof cb === 'function') { - throw new TypeError('callback only supported with file option') - } - - if (files.length) { - filesFilter(opt, files) - } - - if (!opt.noResume) { - onentryFunction(opt) - } - - return opt.file && opt.sync ? listFileSync(opt) - : opt.file ? listFile(opt, cb) - : list(opt) -} - -const onentryFunction = opt => { - const onentry = opt.onentry - opt.onentry = onentry ? e => { - onentry(e) - e.resume() - } : e => e.resume() -} - -// construct a filter that limits the file entries listed -// include child entries if a dir is included -const filesFilter = (opt, files) => { - const map = new Map(files.map(f => [stripSlash(f), true])) - const filter = opt.filter - - const mapHas = (file, r) => { - const root = r || path.parse(file).root || '.' - const ret = file === root ? false - : map.has(file) ? map.get(file) - : mapHas(path.dirname(file), root) - - map.set(file, ret) - return ret - } - - opt.filter = filter - ? (file, entry) => filter(file, entry) && mapHas(stripSlash(file)) - : file => mapHas(stripSlash(file)) -} - -const listFileSync = opt => { - const p = list(opt) - const file = opt.file - let threw = true - let fd - try { - const stat = fs.statSync(file) - const readSize = opt.maxReadSize || 16 * 1024 * 1024 - if (stat.size < readSize) { - p.end(fs.readFileSync(file)) - } else { - let pos = 0 - const buf = Buffer.allocUnsafe(readSize) - fd = fs.openSync(file, 'r') - while (pos < stat.size) { - const bytesRead = fs.readSync(fd, buf, 0, readSize, pos) - pos += bytesRead - p.write(buf.slice(0, bytesRead)) - } - p.end() - } - threw = false - } finally { - if (threw && fd) { - try { - fs.closeSync(fd) - } catch (er) {} - } - } -} - -const listFile = (opt, cb) => { - const parse = new Parser(opt) - const readSize = opt.maxReadSize || 16 * 1024 * 1024 - - const file = opt.file - const p = new Promise((resolve, reject) => { - parse.on('error', reject) - parse.on('end', resolve) - - fs.stat(file, (er, stat) => { - if (er) { - reject(er) - } else { - const stream = new fsm.ReadStream(file, { - readSize: readSize, - size: stat.size, - }) - stream.on('error', reject) - stream.pipe(parse) - } - }) - }) - return cb ? p.then(cb, cb) : p -} - -const list = opt => new Parser(opt) diff --git a/lib/mkdir.js b/lib/mkdir.js deleted file mode 100644 index 8ee8de78..00000000 --- a/lib/mkdir.js +++ /dev/null @@ -1,229 +0,0 @@ -'use strict' -// wrapper around mkdirp for tar's needs. - -// TODO: This should probably be a class, not functionally -// passing around state in a gazillion args. - -const mkdirp = require('mkdirp') -const fs = require('fs') -const path = require('path') -const chownr = require('chownr') -const normPath = require('./normalize-windows-path.js') - -class SymlinkError extends Error { - constructor (symlink, path) { - super('Cannot extract through symbolic link') - this.path = path - this.symlink = symlink - } - - get name () { - return 'SylinkError' - } -} - -class CwdError extends Error { - constructor (path, code) { - super(code + ': Cannot cd into \'' + path + '\'') - this.path = path - this.code = code - } - - get name () { - return 'CwdError' - } -} - -const cGet = (cache, key) => cache.get(normPath(key)) -const cSet = (cache, key, val) => cache.set(normPath(key), val) - -const checkCwd = (dir, cb) => { - fs.stat(dir, (er, st) => { - if (er || !st.isDirectory()) { - er = new CwdError(dir, er && er.code || 'ENOTDIR') - } - cb(er) - }) -} - -module.exports = (dir, opt, cb) => { - dir = normPath(dir) - - // if there's any overlap between mask and mode, - // then we'll need an explicit chmod - const umask = opt.umask - const mode = opt.mode | 0o0700 - const needChmod = (mode & umask) !== 0 - - const uid = opt.uid - const gid = opt.gid - const doChown = typeof uid === 'number' && - typeof gid === 'number' && - (uid !== opt.processUid || gid !== opt.processGid) - - const preserve = opt.preserve - const unlink = opt.unlink - const cache = opt.cache - const cwd = normPath(opt.cwd) - - const done = (er, created) => { - if (er) { - cb(er) - } else { - cSet(cache, dir, true) - if (created && doChown) { - chownr(created, uid, gid, er => done(er)) - } else if (needChmod) { - fs.chmod(dir, mode, cb) - } else { - cb() - } - } - } - - if (cache && cGet(cache, dir) === true) { - return done() - } - - if (dir === cwd) { - return checkCwd(dir, done) - } - - if (preserve) { - return mkdirp(dir, { mode }).then(made => done(null, made), done) - } - - const sub = normPath(path.relative(cwd, dir)) - const parts = sub.split('/') - mkdir_(cwd, parts, mode, cache, unlink, cwd, null, done) -} - -const mkdir_ = (base, parts, mode, cache, unlink, cwd, created, cb) => { - if (!parts.length) { - return cb(null, created) - } - const p = parts.shift() - const part = normPath(path.resolve(base + '/' + p)) - if (cGet(cache, part)) { - return mkdir_(part, parts, mode, cache, unlink, cwd, created, cb) - } - fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb)) -} - -const onmkdir = (part, parts, mode, cache, unlink, cwd, created, cb) => er => { - if (er) { - fs.lstat(part, (statEr, st) => { - if (statEr) { - statEr.path = statEr.path && normPath(statEr.path) - cb(statEr) - } else if (st.isDirectory()) { - mkdir_(part, parts, mode, cache, unlink, cwd, created, cb) - } else if (unlink) { - fs.unlink(part, er => { - if (er) { - return cb(er) - } - fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb)) - }) - } else if (st.isSymbolicLink()) { - return cb(new SymlinkError(part, part + '/' + parts.join('/'))) - } else { - cb(er) - } - }) - } else { - created = created || part - mkdir_(part, parts, mode, cache, unlink, cwd, created, cb) - } -} - -const checkCwdSync = dir => { - let ok = false - let code = 'ENOTDIR' - try { - ok = fs.statSync(dir).isDirectory() - } catch (er) { - code = er.code - } finally { - if (!ok) { - throw new CwdError(dir, code) - } - } -} - -module.exports.sync = (dir, opt) => { - dir = normPath(dir) - // if there's any overlap between mask and mode, - // then we'll need an explicit chmod - const umask = opt.umask - const mode = opt.mode | 0o0700 - const needChmod = (mode & umask) !== 0 - - const uid = opt.uid - const gid = opt.gid - const doChown = typeof uid === 'number' && - typeof gid === 'number' && - (uid !== opt.processUid || gid !== opt.processGid) - - const preserve = opt.preserve - const unlink = opt.unlink - const cache = opt.cache - const cwd = normPath(opt.cwd) - - const done = (created) => { - cSet(cache, dir, true) - if (created && doChown) { - chownr.sync(created, uid, gid) - } - if (needChmod) { - fs.chmodSync(dir, mode) - } - } - - if (cache && cGet(cache, dir) === true) { - return done() - } - - if (dir === cwd) { - checkCwdSync(cwd) - return done() - } - - if (preserve) { - return done(mkdirp.sync(dir, mode)) - } - - const sub = normPath(path.relative(cwd, dir)) - const parts = sub.split('/') - let created = null - for (let p = parts.shift(), part = cwd; - p && (part += '/' + p); - p = parts.shift()) { - part = normPath(path.resolve(part)) - if (cGet(cache, part)) { - continue - } - - try { - fs.mkdirSync(part, mode) - created = created || part - cSet(cache, part, true) - } catch (er) { - const st = fs.lstatSync(part) - if (st.isDirectory()) { - cSet(cache, part, true) - continue - } else if (unlink) { - fs.unlinkSync(part) - fs.mkdirSync(part, mode) - created = created || part - cSet(cache, part, true) - continue - } else if (st.isSymbolicLink()) { - return new SymlinkError(part, part + '/' + parts.join('/')) - } - } - } - - return done(created) -} diff --git a/lib/mode-fix.js b/lib/mode-fix.js deleted file mode 100644 index 42f1d6e6..00000000 --- a/lib/mode-fix.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict' -module.exports = (mode, isDir, portable) => { - mode &= 0o7777 - - // in portable mode, use the minimum reasonable umask - // if this system creates files with 0o664 by default - // (as some linux distros do), then we'll write the - // archive with 0o644 instead. Also, don't ever create - // a file that is not readable/writable by the owner. - if (portable) { - mode = (mode | 0o600) & ~0o22 - } - - // if dirs are readable, then they should be listable - if (isDir) { - if (mode & 0o400) { - mode |= 0o100 - } - if (mode & 0o40) { - mode |= 0o10 - } - if (mode & 0o4) { - mode |= 0o1 - } - } - return mode -} diff --git a/lib/normalize-unicode.js b/lib/normalize-unicode.js deleted file mode 100644 index 79e285ab..00000000 --- a/lib/normalize-unicode.js +++ /dev/null @@ -1,12 +0,0 @@ -// warning: extremely hot code path. -// This has been meticulously optimized for use -// within npm install on large package trees. -// Do not edit without careful benchmarking. -const normalizeCache = Object.create(null) -const { hasOwnProperty } = Object.prototype -module.exports = s => { - if (!hasOwnProperty.call(normalizeCache, s)) { - normalizeCache[s] = s.normalize('NFD') - } - return normalizeCache[s] -} diff --git a/lib/normalize-windows-path.js b/lib/normalize-windows-path.js deleted file mode 100644 index eb13ba01..00000000 --- a/lib/normalize-windows-path.js +++ /dev/null @@ -1,8 +0,0 @@ -// on windows, either \ or / are valid directory separators. -// on unix, \ is a valid character in filenames. -// so, on windows, and only on windows, we replace all \ chars with /, -// so that we can use / as our one and only directory separator char. - -const platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform -module.exports = platform !== 'win32' ? p => p - : p => p && p.replace(/\\/g, '/') diff --git a/lib/pack.js b/lib/pack.js deleted file mode 100644 index d533a068..00000000 --- a/lib/pack.js +++ /dev/null @@ -1,432 +0,0 @@ -'use strict' - -// A readable tar stream creator -// Technically, this is a transform stream that you write paths into, -// and tar format comes out of. -// The `add()` method is like `write()` but returns this, -// and end() return `this` as well, so you can -// do `new Pack(opt).add('files').add('dir').end().pipe(output) -// You could also do something like: -// streamOfPaths().pipe(new Pack()).pipe(new fs.WriteStream('out.tar')) - -class PackJob { - constructor (path, absolute) { - this.path = path || './' - this.absolute = absolute - this.entry = null - this.stat = null - this.readdir = null - this.pending = false - this.ignore = false - this.piped = false - } -} - -const { Minipass } = require('minipass') -const zlib = require('minizlib') -const ReadEntry = require('./read-entry.js') -const WriteEntry = require('./write-entry.js') -const WriteEntrySync = WriteEntry.Sync -const WriteEntryTar = WriteEntry.Tar -const Yallist = require('yallist') -const EOF = Buffer.alloc(1024) -const ONSTAT = Symbol('onStat') -const ENDED = Symbol('ended') -const QUEUE = Symbol('queue') -const CURRENT = Symbol('current') -const PROCESS = Symbol('process') -const PROCESSING = Symbol('processing') -const PROCESSJOB = Symbol('processJob') -const JOBS = Symbol('jobs') -const JOBDONE = Symbol('jobDone') -const ADDFSENTRY = Symbol('addFSEntry') -const ADDTARENTRY = Symbol('addTarEntry') -const STAT = Symbol('stat') -const READDIR = Symbol('readdir') -const ONREADDIR = Symbol('onreaddir') -const PIPE = Symbol('pipe') -const ENTRY = Symbol('entry') -const ENTRYOPT = Symbol('entryOpt') -const WRITEENTRYCLASS = Symbol('writeEntryClass') -const WRITE = Symbol('write') -const ONDRAIN = Symbol('ondrain') - -const fs = require('fs') -const path = require('path') -const warner = require('./warn-mixin.js') -const normPath = require('./normalize-windows-path.js') - -const Pack = warner(class Pack extends Minipass { - constructor (opt) { - super(opt) - opt = opt || Object.create(null) - this.opt = opt - this.file = opt.file || '' - this.cwd = opt.cwd || process.cwd() - this.maxReadSize = opt.maxReadSize - this.preservePaths = !!opt.preservePaths - this.strict = !!opt.strict - this.noPax = !!opt.noPax - this.prefix = normPath(opt.prefix || '') - this.linkCache = opt.linkCache || new Map() - this.statCache = opt.statCache || new Map() - this.readdirCache = opt.readdirCache || new Map() - - this[WRITEENTRYCLASS] = WriteEntry - if (typeof opt.onwarn === 'function') { - this.on('warn', opt.onwarn) - } - - this.portable = !!opt.portable - this.zip = null - - if (opt.gzip || opt.brotli) { - if (opt.gzip && opt.brotli) { - throw new TypeError('gzip and brotli are mutually exclusive') - } - if (opt.gzip) { - if (typeof opt.gzip !== 'object') { - opt.gzip = {} - } - if (this.portable) { - opt.gzip.portable = true - } - this.zip = new zlib.Gzip(opt.gzip) - } - if (opt.brotli) { - if (typeof opt.brotli !== 'object') { - opt.brotli = {} - } - this.zip = new zlib.BrotliCompress(opt.brotli) - } - this.zip.on('data', chunk => super.write(chunk)) - this.zip.on('end', _ => super.end()) - this.zip.on('drain', _ => this[ONDRAIN]()) - this.on('resume', _ => this.zip.resume()) - } else { - this.on('drain', this[ONDRAIN]) - } - - this.noDirRecurse = !!opt.noDirRecurse - this.follow = !!opt.follow - this.noMtime = !!opt.noMtime - this.mtime = opt.mtime || null - - this.filter = typeof opt.filter === 'function' ? opt.filter : _ => true - - this[QUEUE] = new Yallist() - this[JOBS] = 0 - this.jobs = +opt.jobs || 4 - this[PROCESSING] = false - this[ENDED] = false - } - - [WRITE] (chunk) { - return super.write(chunk) - } - - add (path) { - this.write(path) - return this - } - - end (path) { - if (path) { - this.write(path) - } - this[ENDED] = true - this[PROCESS]() - return this - } - - write (path) { - if (this[ENDED]) { - throw new Error('write after end') - } - - if (path instanceof ReadEntry) { - this[ADDTARENTRY](path) - } else { - this[ADDFSENTRY](path) - } - return this.flowing - } - - [ADDTARENTRY] (p) { - const absolute = normPath(path.resolve(this.cwd, p.path)) - // in this case, we don't have to wait for the stat - if (!this.filter(p.path, p)) { - p.resume() - } else { - const job = new PackJob(p.path, absolute, false) - job.entry = new WriteEntryTar(p, this[ENTRYOPT](job)) - job.entry.on('end', _ => this[JOBDONE](job)) - this[JOBS] += 1 - this[QUEUE].push(job) - } - - this[PROCESS]() - } - - [ADDFSENTRY] (p) { - const absolute = normPath(path.resolve(this.cwd, p)) - this[QUEUE].push(new PackJob(p, absolute)) - this[PROCESS]() - } - - [STAT] (job) { - job.pending = true - this[JOBS] += 1 - const stat = this.follow ? 'stat' : 'lstat' - fs[stat](job.absolute, (er, stat) => { - job.pending = false - this[JOBS] -= 1 - if (er) { - this.emit('error', er) - } else { - this[ONSTAT](job, stat) - } - }) - } - - [ONSTAT] (job, stat) { - this.statCache.set(job.absolute, stat) - job.stat = stat - - // now we have the stat, we can filter it. - if (!this.filter(job.path, stat)) { - job.ignore = true - } - - this[PROCESS]() - } - - [READDIR] (job) { - job.pending = true - this[JOBS] += 1 - fs.readdir(job.absolute, (er, entries) => { - job.pending = false - this[JOBS] -= 1 - if (er) { - return this.emit('error', er) - } - this[ONREADDIR](job, entries) - }) - } - - [ONREADDIR] (job, entries) { - this.readdirCache.set(job.absolute, entries) - job.readdir = entries - this[PROCESS]() - } - - [PROCESS] () { - if (this[PROCESSING]) { - return - } - - this[PROCESSING] = true - for (let w = this[QUEUE].head; - w !== null && this[JOBS] < this.jobs; - w = w.next) { - this[PROCESSJOB](w.value) - if (w.value.ignore) { - const p = w.next - this[QUEUE].removeNode(w) - w.next = p - } - } - - this[PROCESSING] = false - - if (this[ENDED] && !this[QUEUE].length && this[JOBS] === 0) { - if (this.zip) { - this.zip.end(EOF) - } else { - super.write(EOF) - super.end() - } - } - } - - get [CURRENT] () { - return this[QUEUE] && this[QUEUE].head && this[QUEUE].head.value - } - - [JOBDONE] (job) { - this[QUEUE].shift() - this[JOBS] -= 1 - this[PROCESS]() - } - - [PROCESSJOB] (job) { - if (job.pending) { - return - } - - if (job.entry) { - if (job === this[CURRENT] && !job.piped) { - this[PIPE](job) - } - return - } - - if (!job.stat) { - if (this.statCache.has(job.absolute)) { - this[ONSTAT](job, this.statCache.get(job.absolute)) - } else { - this[STAT](job) - } - } - if (!job.stat) { - return - } - - // filtered out! - if (job.ignore) { - return - } - - if (!this.noDirRecurse && job.stat.isDirectory() && !job.readdir) { - if (this.readdirCache.has(job.absolute)) { - this[ONREADDIR](job, this.readdirCache.get(job.absolute)) - } else { - this[READDIR](job) - } - if (!job.readdir) { - return - } - } - - // we know it doesn't have an entry, because that got checked above - job.entry = this[ENTRY](job) - if (!job.entry) { - job.ignore = true - return - } - - if (job === this[CURRENT] && !job.piped) { - this[PIPE](job) - } - } - - [ENTRYOPT] (job) { - return { - onwarn: (code, msg, data) => this.warn(code, msg, data), - noPax: this.noPax, - cwd: this.cwd, - absolute: job.absolute, - preservePaths: this.preservePaths, - maxReadSize: this.maxReadSize, - strict: this.strict, - portable: this.portable, - linkCache: this.linkCache, - statCache: this.statCache, - noMtime: this.noMtime, - mtime: this.mtime, - prefix: this.prefix, - } - } - - [ENTRY] (job) { - this[JOBS] += 1 - try { - return new this[WRITEENTRYCLASS](job.path, this[ENTRYOPT](job)) - .on('end', () => this[JOBDONE](job)) - .on('error', er => this.emit('error', er)) - } catch (er) { - this.emit('error', er) - } - } - - [ONDRAIN] () { - if (this[CURRENT] && this[CURRENT].entry) { - this[CURRENT].entry.resume() - } - } - - // like .pipe() but using super, because our write() is special - [PIPE] (job) { - job.piped = true - - if (job.readdir) { - job.readdir.forEach(entry => { - const p = job.path - const base = p === './' ? '' : p.replace(/\/*$/, '/') - this[ADDFSENTRY](base + entry) - }) - } - - const source = job.entry - const zip = this.zip - - if (zip) { - source.on('data', chunk => { - if (!zip.write(chunk)) { - source.pause() - } - }) - } else { - source.on('data', chunk => { - if (!super.write(chunk)) { - source.pause() - } - }) - } - } - - pause () { - if (this.zip) { - this.zip.pause() - } - return super.pause() - } -}) - -class PackSync extends Pack { - constructor (opt) { - super(opt) - this[WRITEENTRYCLASS] = WriteEntrySync - } - - // pause/resume are no-ops in sync streams. - pause () {} - resume () {} - - [STAT] (job) { - const stat = this.follow ? 'statSync' : 'lstatSync' - this[ONSTAT](job, fs[stat](job.absolute)) - } - - [READDIR] (job, stat) { - this[ONREADDIR](job, fs.readdirSync(job.absolute)) - } - - // gotta get it all in this tick - [PIPE] (job) { - const source = job.entry - const zip = this.zip - - if (job.readdir) { - job.readdir.forEach(entry => { - const p = job.path - const base = p === './' ? '' : p.replace(/\/*$/, '/') - this[ADDFSENTRY](base + entry) - }) - } - - if (zip) { - source.on('data', chunk => { - zip.write(chunk) - }) - } else { - source.on('data', chunk => { - super[WRITE](chunk) - }) - } - } -} - -Pack.Sync = PackSync - -module.exports = Pack diff --git a/lib/parse.js b/lib/parse.js deleted file mode 100644 index 94e53042..00000000 --- a/lib/parse.js +++ /dev/null @@ -1,552 +0,0 @@ -'use strict' - -// this[BUFFER] is the remainder of a chunk if we're waiting for -// the full 512 bytes of a header to come in. We will Buffer.concat() -// it to the next write(), which is a mem copy, but a small one. -// -// this[QUEUE] is a Yallist of entries that haven't been emitted -// yet this can only get filled up if the user keeps write()ing after -// a write() returns false, or does a write() with more than one entry -// -// We don't buffer chunks, we always parse them and either create an -// entry, or push it into the active entry. The ReadEntry class knows -// to throw data away if .ignore=true -// -// Shift entry off the buffer when it emits 'end', and emit 'entry' for -// the next one in the list. -// -// At any time, we're pushing body chunks into the entry at WRITEENTRY, -// and waiting for 'end' on the entry at READENTRY -// -// ignored entries get .resume() called on them straight away - -const warner = require('./warn-mixin.js') -const Header = require('./header.js') -const EE = require('events') -const Yallist = require('yallist') -const maxMetaEntrySize = 1024 * 1024 -const Entry = require('./read-entry.js') -const Pax = require('./pax.js') -const zlib = require('minizlib') -const { nextTick } = require('process') - -const gzipHeader = Buffer.from([0x1f, 0x8b]) -const STATE = Symbol('state') -const WRITEENTRY = Symbol('writeEntry') -const READENTRY = Symbol('readEntry') -const NEXTENTRY = Symbol('nextEntry') -const PROCESSENTRY = Symbol('processEntry') -const EX = Symbol('extendedHeader') -const GEX = Symbol('globalExtendedHeader') -const META = Symbol('meta') -const EMITMETA = Symbol('emitMeta') -const BUFFER = Symbol('buffer') -const QUEUE = Symbol('queue') -const ENDED = Symbol('ended') -const EMITTEDEND = Symbol('emittedEnd') -const EMIT = Symbol('emit') -const UNZIP = Symbol('unzip') -const CONSUMECHUNK = Symbol('consumeChunk') -const CONSUMECHUNKSUB = Symbol('consumeChunkSub') -const CONSUMEBODY = Symbol('consumeBody') -const CONSUMEMETA = Symbol('consumeMeta') -const CONSUMEHEADER = Symbol('consumeHeader') -const CONSUMING = Symbol('consuming') -const BUFFERCONCAT = Symbol('bufferConcat') -const MAYBEEND = Symbol('maybeEnd') -const WRITING = Symbol('writing') -const ABORTED = Symbol('aborted') -const DONE = Symbol('onDone') -const SAW_VALID_ENTRY = Symbol('sawValidEntry') -const SAW_NULL_BLOCK = Symbol('sawNullBlock') -const SAW_EOF = Symbol('sawEOF') -const CLOSESTREAM = Symbol('closeStream') - -const noop = _ => true - -module.exports = warner(class Parser extends EE { - constructor (opt) { - opt = opt || {} - super(opt) - - this.file = opt.file || '' - - // set to boolean false when an entry starts. 1024 bytes of \0 - // is technically a valid tarball, albeit a boring one. - this[SAW_VALID_ENTRY] = null - - // these BADARCHIVE errors can't be detected early. listen on DONE. - this.on(DONE, _ => { - if (this[STATE] === 'begin' || this[SAW_VALID_ENTRY] === false) { - // either less than 1 block of data, or all entries were invalid. - // Either way, probably not even a tarball. - this.warn('TAR_BAD_ARCHIVE', 'Unrecognized archive format') - } - }) - - if (opt.ondone) { - this.on(DONE, opt.ondone) - } else { - this.on(DONE, _ => { - this.emit('prefinish') - this.emit('finish') - this.emit('end') - }) - } - - this.strict = !!opt.strict - this.maxMetaEntrySize = opt.maxMetaEntrySize || maxMetaEntrySize - this.filter = typeof opt.filter === 'function' ? opt.filter : noop - // Unlike gzip, brotli doesn't have any magic bytes to identify it - // Users need to explicitly tell us they're extracting a brotli file - // Or we infer from the file extension - const isTBR = (opt.file && ( - opt.file.endsWith('.tar.br') || opt.file.endsWith('.tbr'))) - // if it's a tbr file it MIGHT be brotli, but we don't know until - // we look at it and verify it's not a valid tar file. - this.brotli = !opt.gzip && opt.brotli !== undefined ? opt.brotli - : isTBR ? undefined - : false - - // have to set this so that streams are ok piping into it - this.writable = true - this.readable = false - - this[QUEUE] = new Yallist() - this[BUFFER] = null - this[READENTRY] = null - this[WRITEENTRY] = null - this[STATE] = 'begin' - this[META] = '' - this[EX] = null - this[GEX] = null - this[ENDED] = false - this[UNZIP] = null - this[ABORTED] = false - this[SAW_NULL_BLOCK] = false - this[SAW_EOF] = false - - this.on('end', () => this[CLOSESTREAM]()) - - if (typeof opt.onwarn === 'function') { - this.on('warn', opt.onwarn) - } - if (typeof opt.onentry === 'function') { - this.on('entry', opt.onentry) - } - } - - [CONSUMEHEADER] (chunk, position) { - if (this[SAW_VALID_ENTRY] === null) { - this[SAW_VALID_ENTRY] = false - } - let header - try { - header = new Header(chunk, position, this[EX], this[GEX]) - } catch (er) { - return this.warn('TAR_ENTRY_INVALID', er) - } - - if (header.nullBlock) { - if (this[SAW_NULL_BLOCK]) { - this[SAW_EOF] = true - // ending an archive with no entries. pointless, but legal. - if (this[STATE] === 'begin') { - this[STATE] = 'header' - } - this[EMIT]('eof') - } else { - this[SAW_NULL_BLOCK] = true - this[EMIT]('nullBlock') - } - } else { - this[SAW_NULL_BLOCK] = false - if (!header.cksumValid) { - this.warn('TAR_ENTRY_INVALID', 'checksum failure', { header }) - } else if (!header.path) { - this.warn('TAR_ENTRY_INVALID', 'path is required', { header }) - } else { - const type = header.type - if (/^(Symbolic)?Link$/.test(type) && !header.linkpath) { - this.warn('TAR_ENTRY_INVALID', 'linkpath required', { header }) - } else if (!/^(Symbolic)?Link$/.test(type) && header.linkpath) { - this.warn('TAR_ENTRY_INVALID', 'linkpath forbidden', { header }) - } else { - const entry = this[WRITEENTRY] = new Entry(header, this[EX], this[GEX]) - - // we do this for meta & ignored entries as well, because they - // are still valid tar, or else we wouldn't know to ignore them - if (!this[SAW_VALID_ENTRY]) { - if (entry.remain) { - // this might be the one! - const onend = () => { - if (!entry.invalid) { - this[SAW_VALID_ENTRY] = true - } - } - entry.on('end', onend) - } else { - this[SAW_VALID_ENTRY] = true - } - } - - if (entry.meta) { - if (entry.size > this.maxMetaEntrySize) { - entry.ignore = true - this[EMIT]('ignoredEntry', entry) - this[STATE] = 'ignore' - entry.resume() - } else if (entry.size > 0) { - this[META] = '' - entry.on('data', c => this[META] += c) - this[STATE] = 'meta' - } - } else { - this[EX] = null - entry.ignore = entry.ignore || !this.filter(entry.path, entry) - - if (entry.ignore) { - // probably valid, just not something we care about - this[EMIT]('ignoredEntry', entry) - this[STATE] = entry.remain ? 'ignore' : 'header' - entry.resume() - } else { - if (entry.remain) { - this[STATE] = 'body' - } else { - this[STATE] = 'header' - entry.end() - } - - if (!this[READENTRY]) { - this[QUEUE].push(entry) - this[NEXTENTRY]() - } else { - this[QUEUE].push(entry) - } - } - } - } - } - } - } - - [CLOSESTREAM] () { - nextTick(() => this.emit('close')) - } - - [PROCESSENTRY] (entry) { - let go = true - - if (!entry) { - this[READENTRY] = null - go = false - } else if (Array.isArray(entry)) { - this.emit.apply(this, entry) - } else { - this[READENTRY] = entry - this.emit('entry', entry) - if (!entry.emittedEnd) { - entry.on('end', _ => this[NEXTENTRY]()) - go = false - } - } - - return go - } - - [NEXTENTRY] () { - do {} while (this[PROCESSENTRY](this[QUEUE].shift())) - - if (!this[QUEUE].length) { - // At this point, there's nothing in the queue, but we may have an - // entry which is being consumed (readEntry). - // If we don't, then we definitely can handle more data. - // If we do, and either it's flowing, or it has never had any data - // written to it, then it needs more. - // The only other possibility is that it has returned false from a - // write() call, so we wait for the next drain to continue. - const re = this[READENTRY] - const drainNow = !re || re.flowing || re.size === re.remain - if (drainNow) { - if (!this[WRITING]) { - this.emit('drain') - } - } else { - re.once('drain', _ => this.emit('drain')) - } - } - } - - [CONSUMEBODY] (chunk, position) { - // write up to but no more than writeEntry.blockRemain - const entry = this[WRITEENTRY] - const br = entry.blockRemain - const c = (br >= chunk.length && position === 0) ? chunk - : chunk.slice(position, position + br) - - entry.write(c) - - if (!entry.blockRemain) { - this[STATE] = 'header' - this[WRITEENTRY] = null - entry.end() - } - - return c.length - } - - [CONSUMEMETA] (chunk, position) { - const entry = this[WRITEENTRY] - const ret = this[CONSUMEBODY](chunk, position) - - // if we finished, then the entry is reset - if (!this[WRITEENTRY]) { - this[EMITMETA](entry) - } - - return ret - } - - [EMIT] (ev, data, extra) { - if (!this[QUEUE].length && !this[READENTRY]) { - this.emit(ev, data, extra) - } else { - this[QUEUE].push([ev, data, extra]) - } - } - - [EMITMETA] (entry) { - this[EMIT]('meta', this[META]) - switch (entry.type) { - case 'ExtendedHeader': - case 'OldExtendedHeader': - this[EX] = Pax.parse(this[META], this[EX], false) - break - - case 'GlobalExtendedHeader': - this[GEX] = Pax.parse(this[META], this[GEX], true) - break - - case 'NextFileHasLongPath': - case 'OldGnuLongPath': - this[EX] = this[EX] || Object.create(null) - this[EX].path = this[META].replace(/\0.*/, '') - break - - case 'NextFileHasLongLinkpath': - this[EX] = this[EX] || Object.create(null) - this[EX].linkpath = this[META].replace(/\0.*/, '') - break - - /* istanbul ignore next */ - default: throw new Error('unknown meta: ' + entry.type) - } - } - - abort (error) { - this[ABORTED] = true - this.emit('abort', error) - // always throws, even in non-strict mode - this.warn('TAR_ABORT', error, { recoverable: false }) - } - - write (chunk) { - if (this[ABORTED]) { - return - } - - // first write, might be gzipped - const needSniff = this[UNZIP] === null || - this.brotli === undefined && this[UNZIP] === false - if (needSniff && chunk) { - if (this[BUFFER]) { - chunk = Buffer.concat([this[BUFFER], chunk]) - this[BUFFER] = null - } - if (chunk.length < gzipHeader.length) { - this[BUFFER] = chunk - return true - } - - // look for gzip header - for (let i = 0; this[UNZIP] === null && i < gzipHeader.length; i++) { - if (chunk[i] !== gzipHeader[i]) { - this[UNZIP] = false - } - } - - const maybeBrotli = this.brotli === undefined - if (this[UNZIP] === false && maybeBrotli) { - // read the first header to see if it's a valid tar file. If so, - // we can safely assume that it's not actually brotli, despite the - // .tbr or .tar.br file extension. - // if we ended before getting a full chunk, yes, def brotli - if (chunk.length < 512) { - if (this[ENDED]) { - this.brotli = true - } else { - this[BUFFER] = chunk - return true - } - } else { - // if it's tar, it's pretty reliably not brotli, chances of - // that happening are astronomical. - try { - new Header(chunk.slice(0, 512)) - this.brotli = false - } catch (_) { - this.brotli = true - } - } - } - - if (this[UNZIP] === null || (this[UNZIP] === false && this.brotli)) { - const ended = this[ENDED] - this[ENDED] = false - this[UNZIP] = this[UNZIP] === null - ? new zlib.Unzip() - : new zlib.BrotliDecompress() - this[UNZIP].on('data', chunk => this[CONSUMECHUNK](chunk)) - this[UNZIP].on('error', er => this.abort(er)) - this[UNZIP].on('end', _ => { - this[ENDED] = true - this[CONSUMECHUNK]() - }) - this[WRITING] = true - const ret = this[UNZIP][ended ? 'end' : 'write'](chunk) - this[WRITING] = false - return ret - } - } - - this[WRITING] = true - if (this[UNZIP]) { - this[UNZIP].write(chunk) - } else { - this[CONSUMECHUNK](chunk) - } - this[WRITING] = false - - // return false if there's a queue, or if the current entry isn't flowing - const ret = - this[QUEUE].length ? false : - this[READENTRY] ? this[READENTRY].flowing : - true - - // if we have no queue, then that means a clogged READENTRY - if (!ret && !this[QUEUE].length) { - this[READENTRY].once('drain', _ => this.emit('drain')) - } - - return ret - } - - [BUFFERCONCAT] (c) { - if (c && !this[ABORTED]) { - this[BUFFER] = this[BUFFER] ? Buffer.concat([this[BUFFER], c]) : c - } - } - - [MAYBEEND] () { - if (this[ENDED] && - !this[EMITTEDEND] && - !this[ABORTED] && - !this[CONSUMING]) { - this[EMITTEDEND] = true - const entry = this[WRITEENTRY] - if (entry && entry.blockRemain) { - // truncated, likely a damaged file - const have = this[BUFFER] ? this[BUFFER].length : 0 - this.warn('TAR_BAD_ARCHIVE', `Truncated input (needed ${ - entry.blockRemain} more bytes, only ${have} available)`, { entry }) - if (this[BUFFER]) { - entry.write(this[BUFFER]) - } - entry.end() - } - this[EMIT](DONE) - } - } - - [CONSUMECHUNK] (chunk) { - if (this[CONSUMING]) { - this[BUFFERCONCAT](chunk) - } else if (!chunk && !this[BUFFER]) { - this[MAYBEEND]() - } else { - this[CONSUMING] = true - if (this[BUFFER]) { - this[BUFFERCONCAT](chunk) - const c = this[BUFFER] - this[BUFFER] = null - this[CONSUMECHUNKSUB](c) - } else { - this[CONSUMECHUNKSUB](chunk) - } - - while (this[BUFFER] && - this[BUFFER].length >= 512 && - !this[ABORTED] && - !this[SAW_EOF]) { - const c = this[BUFFER] - this[BUFFER] = null - this[CONSUMECHUNKSUB](c) - } - this[CONSUMING] = false - } - - if (!this[BUFFER] || this[ENDED]) { - this[MAYBEEND]() - } - } - - [CONSUMECHUNKSUB] (chunk) { - // we know that we are in CONSUMING mode, so anything written goes into - // the buffer. Advance the position and put any remainder in the buffer. - let position = 0 - const length = chunk.length - while (position + 512 <= length && !this[ABORTED] && !this[SAW_EOF]) { - switch (this[STATE]) { - case 'begin': - case 'header': - this[CONSUMEHEADER](chunk, position) - position += 512 - break - - case 'ignore': - case 'body': - position += this[CONSUMEBODY](chunk, position) - break - - case 'meta': - position += this[CONSUMEMETA](chunk, position) - break - - /* istanbul ignore next */ - default: - throw new Error('invalid state: ' + this[STATE]) - } - } - - if (position < length) { - if (this[BUFFER]) { - this[BUFFER] = Buffer.concat([chunk.slice(position), this[BUFFER]]) - } else { - this[BUFFER] = chunk.slice(position) - } - } - } - - end (chunk) { - if (!this[ABORTED]) { - if (this[UNZIP]) { - this[UNZIP].end(chunk) - } else { - this[ENDED] = true - if (this.brotli === undefined) chunk = chunk || Buffer.alloc(0) - this.write(chunk) - } - } - } -}) diff --git a/lib/path-reservations.js b/lib/path-reservations.js deleted file mode 100644 index 62890060..00000000 --- a/lib/path-reservations.js +++ /dev/null @@ -1,163 +0,0 @@ -// A path exclusive reservation system -// reserve([list, of, paths], fn) -// When the fn is first in line for all its paths, it -// is called with a cb that clears the reservation. -// -// Used by async unpack to avoid clobbering paths in use, -// while still allowing maximal safe parallelization. - -const assert = require('assert') -const normalize = require('./normalize-unicode.js') -const stripSlashes = require('./strip-trailing-slashes.js') -const { join } = require('path') - -const platform = - process.env.TESTING_TAR_FAKE_PLATFORM || process.platform -const isWindows = platform === 'win32' - -module.exports = () => { - // path => [function or Set] - // A Set object means a directory reservation - // A fn is a direct reservation on that path - const queues = new Map() - - // fn => {paths:[path,...], dirs:[path, ...]} - const reservations = new Map() - - // return a set of parent dirs for a given path - // '/a/b/c/d' -> ['/', '/a', '/a/b', '/a/b/c', '/a/b/c/d'] - const getDirs = path => { - const dirs = path - .split('/') - .slice(0, -1) - .reduce((set, path) => { - if (set.length) { - path = join(set[set.length - 1], path) - } - set.push(path || '/') - return set - }, []) - return dirs - } - - // functions currently running - const running = new Set() - - // return the queues for each path the function cares about - // fn => {paths, dirs} - const getQueues = fn => { - const res = reservations.get(fn) - /* istanbul ignore if - unpossible */ - if (!res) { - throw new Error('function does not have any path reservations') - } - return { - paths: res.paths.map(path => queues.get(path)), - dirs: [...res.dirs].map(path => queues.get(path)), - } - } - - // check if fn is first in line for all its paths, and is - // included in the first set for all its dir queues - const check = fn => { - const { paths, dirs } = getQueues(fn) - return ( - paths.every(q => q && q[0] === fn) && - dirs.every(q => q && q[0] instanceof Set && q[0].has(fn)) - ) - } - - // run the function if it's first in line and not already running - const run = fn => { - if (running.has(fn) || !check(fn)) { - return false - } - running.add(fn) - fn(() => clear(fn)) - return true - } - - const clear = fn => { - if (!running.has(fn)) { - return false - } - - const { paths, dirs } = reservations.get(fn) - const next = new Set() - - paths.forEach(path => { - const q = queues.get(path) - assert.equal(q[0], fn) - if (q.length === 1) { - queues.delete(path) - } else { - q.shift() - if (typeof q[0] === 'function') { - next.add(q[0]) - } else { - q[0].forEach(fn => next.add(fn)) - } - } - }) - - dirs.forEach(dir => { - const q = queues.get(dir) - assert(q[0] instanceof Set) - if (q[0].size === 1 && q.length === 1) { - queues.delete(dir) - } else if (q[0].size === 1) { - q.shift() - - next.add(q[0]) - } else { - q[0].delete(fn) - } - }) - running.delete(fn) - - next.forEach(fn => run(fn)) - return true - } - - const reserve = (paths, fn) => { - // collide on matches across case and unicode normalization - // On windows, thanks to the magic of 8.3 shortnames, it is fundamentally - // impossible to determine whether two paths refer to the same thing on - // disk, without asking the kernel for a shortname. - // So, we just pretend that every path matches every other path here, - // effectively removing all parallelization on windows. - paths = isWindows - ? ['win32 parallelization disabled'] - : paths.map(p => { - // don't need normPath, because we skip this entirely for windows - return stripSlashes(join(normalize(p))).toLowerCase() - }) - - const dirs = new Set( - paths.map(path => getDirs(path)).reduce((a, b) => a.concat(b)), - ) - reservations.set(fn, { dirs, paths }) - paths.forEach(path => { - const q = queues.get(path) - if (!q) { - queues.set(path, [fn]) - } else { - q.push(fn) - } - }) - dirs.forEach(dir => { - const q = queues.get(dir) - if (!q) { - queues.set(dir, [new Set([fn])]) - } else if (q[q.length - 1] instanceof Set) { - q[q.length - 1].add(fn) - } else { - q.push(new Set([fn])) - } - }) - - return run(fn) - } - - return { check, reserve } -} diff --git a/lib/pax.js b/lib/pax.js deleted file mode 100644 index 4a7ca853..00000000 --- a/lib/pax.js +++ /dev/null @@ -1,150 +0,0 @@ -'use strict' -const Header = require('./header.js') -const path = require('path') - -class Pax { - constructor (obj, global) { - this.atime = obj.atime || null - this.charset = obj.charset || null - this.comment = obj.comment || null - this.ctime = obj.ctime || null - this.gid = obj.gid || null - this.gname = obj.gname || null - this.linkpath = obj.linkpath || null - this.mtime = obj.mtime || null - this.path = obj.path || null - this.size = obj.size || null - this.uid = obj.uid || null - this.uname = obj.uname || null - this.dev = obj.dev || null - this.ino = obj.ino || null - this.nlink = obj.nlink || null - this.global = global || false - } - - encode () { - const body = this.encodeBody() - if (body === '') { - return null - } - - const bodyLen = Buffer.byteLength(body) - // round up to 512 bytes - // add 512 for header - const bufLen = 512 * Math.ceil(1 + bodyLen / 512) - const buf = Buffer.allocUnsafe(bufLen) - - // 0-fill the header section, it might not hit every field - for (let i = 0; i < 512; i++) { - buf[i] = 0 - } - - new Header({ - // XXX split the path - // then the path should be PaxHeader + basename, but less than 99, - // prepend with the dirname - path: ('PaxHeader/' + path.basename(this.path)).slice(0, 99), - mode: this.mode || 0o644, - uid: this.uid || null, - gid: this.gid || null, - size: bodyLen, - mtime: this.mtime || null, - type: this.global ? 'GlobalExtendedHeader' : 'ExtendedHeader', - linkpath: '', - uname: this.uname || '', - gname: this.gname || '', - devmaj: 0, - devmin: 0, - atime: this.atime || null, - ctime: this.ctime || null, - }).encode(buf) - - buf.write(body, 512, bodyLen, 'utf8') - - // null pad after the body - for (let i = bodyLen + 512; i < buf.length; i++) { - buf[i] = 0 - } - - return buf - } - - encodeBody () { - return ( - this.encodeField('path') + - this.encodeField('ctime') + - this.encodeField('atime') + - this.encodeField('dev') + - this.encodeField('ino') + - this.encodeField('nlink') + - this.encodeField('charset') + - this.encodeField('comment') + - this.encodeField('gid') + - this.encodeField('gname') + - this.encodeField('linkpath') + - this.encodeField('mtime') + - this.encodeField('size') + - this.encodeField('uid') + - this.encodeField('uname') - ) - } - - encodeField (field) { - if (this[field] === null || this[field] === undefined) { - return '' - } - const v = this[field] instanceof Date ? this[field].getTime() / 1000 - : this[field] - const s = ' ' + - (field === 'dev' || field === 'ino' || field === 'nlink' - ? 'SCHILY.' : '') + - field + '=' + v + '\n' - const byteLen = Buffer.byteLength(s) - // the digits includes the length of the digits in ascii base-10 - // so if it's 9 characters, then adding 1 for the 9 makes it 10 - // which makes it 11 chars. - let digits = Math.floor(Math.log(byteLen) / Math.log(10)) + 1 - if (byteLen + digits >= Math.pow(10, digits)) { - digits += 1 - } - const len = digits + byteLen - return len + s - } -} - -Pax.parse = (string, ex, g) => new Pax(merge(parseKV(string), ex), g) - -const merge = (a, b) => - b ? Object.keys(a).reduce((s, k) => (s[k] = a[k], s), b) : a - -const parseKV = string => - string - .replace(/\n$/, '') - .split('\n') - .reduce(parseKVLine, Object.create(null)) - -const parseKVLine = (set, line) => { - const n = parseInt(line, 10) - - // XXX Values with \n in them will fail this. - // Refactor to not be a naive line-by-line parse. - if (n !== Buffer.byteLength(line) + 1) { - return set - } - - line = line.slice((n + ' ').length) - const kv = line.split('=') - const k = kv.shift().replace(/^SCHILY\.(dev|ino|nlink)/, '$1') - if (!k) { - return set - } - - const v = kv.join('=') - set[k] = /^([A-Z]+\.)?([mac]|birth|creation)time$/.test(k) - ? new Date(v * 1000) - : /^[0-9]+$/.test(v) ? +v - : v - return set -} - -module.exports = Pax diff --git a/lib/read-entry.js b/lib/read-entry.js deleted file mode 100644 index 6186266e..00000000 --- a/lib/read-entry.js +++ /dev/null @@ -1,107 +0,0 @@ -'use strict' -const { Minipass } = require('minipass') -const normPath = require('./normalize-windows-path.js') - -const SLURP = Symbol('slurp') -module.exports = class ReadEntry extends Minipass { - constructor (header, ex, gex) { - super() - // read entries always start life paused. this is to avoid the - // situation where Minipass's auto-ending empty streams results - // in an entry ending before we're ready for it. - this.pause() - this.extended = ex - this.globalExtended = gex - this.header = header - this.startBlockSize = 512 * Math.ceil(header.size / 512) - this.blockRemain = this.startBlockSize - this.remain = header.size - this.type = header.type - this.meta = false - this.ignore = false - switch (this.type) { - case 'File': - case 'OldFile': - case 'Link': - case 'SymbolicLink': - case 'CharacterDevice': - case 'BlockDevice': - case 'Directory': - case 'FIFO': - case 'ContiguousFile': - case 'GNUDumpDir': - break - - case 'NextFileHasLongLinkpath': - case 'NextFileHasLongPath': - case 'OldGnuLongPath': - case 'GlobalExtendedHeader': - case 'ExtendedHeader': - case 'OldExtendedHeader': - this.meta = true - break - - // NOTE: gnutar and bsdtar treat unrecognized types as 'File' - // it may be worth doing the same, but with a warning. - default: - this.ignore = true - } - - this.path = normPath(header.path) - this.mode = header.mode - if (this.mode) { - this.mode = this.mode & 0o7777 - } - this.uid = header.uid - this.gid = header.gid - this.uname = header.uname - this.gname = header.gname - this.size = header.size - this.mtime = header.mtime - this.atime = header.atime - this.ctime = header.ctime - this.linkpath = normPath(header.linkpath) - this.uname = header.uname - this.gname = header.gname - - if (ex) { - this[SLURP](ex) - } - if (gex) { - this[SLURP](gex, true) - } - } - - write (data) { - const writeLen = data.length - if (writeLen > this.blockRemain) { - throw new Error('writing more to entry than is appropriate') - } - - const r = this.remain - const br = this.blockRemain - this.remain = Math.max(0, r - writeLen) - this.blockRemain = Math.max(0, br - writeLen) - if (this.ignore) { - return true - } - - if (r >= writeLen) { - return super.write(data) - } - - // r < writeLen - return super.write(data.slice(0, r)) - } - - [SLURP] (ex, global) { - for (const k in ex) { - // we slurp in everything except for the path attribute in - // a global extended header, because that's weird. - if (ex[k] !== null && ex[k] !== undefined && - !(global && k === 'path')) { - this[k] = k === 'path' || k === 'linkpath' ? normPath(ex[k]) : ex[k] - } - } - } -} diff --git a/lib/replace.js b/lib/replace.js deleted file mode 100644 index 8db6800b..00000000 --- a/lib/replace.js +++ /dev/null @@ -1,246 +0,0 @@ -'use strict' - -// tar -r -const hlo = require('./high-level-opt.js') -const Pack = require('./pack.js') -const fs = require('fs') -const fsm = require('fs-minipass') -const t = require('./list.js') -const path = require('path') - -// starting at the head of the file, read a Header -// If the checksum is invalid, that's our position to start writing -// If it is, jump forward by the specified size (round up to 512) -// and try again. -// Write the new Pack stream starting there. - -const Header = require('./header.js') - -module.exports = (opt_, files, cb) => { - const opt = hlo(opt_) - - if (!opt.file) { - throw new TypeError('file is required') - } - - if (opt.gzip || opt.brotli || opt.file.endsWith('.br') || opt.file.endsWith('.tbr')) { - throw new TypeError('cannot append to compressed archives') - } - - if (!files || !Array.isArray(files) || !files.length) { - throw new TypeError('no files or directories specified') - } - - files = Array.from(files) - - return opt.sync ? replaceSync(opt, files) - : replace(opt, files, cb) -} - -const replaceSync = (opt, files) => { - const p = new Pack.Sync(opt) - - let threw = true - let fd - let position - - try { - try { - fd = fs.openSync(opt.file, 'r+') - } catch (er) { - if (er.code === 'ENOENT') { - fd = fs.openSync(opt.file, 'w+') - } else { - throw er - } - } - - const st = fs.fstatSync(fd) - const headBuf = Buffer.alloc(512) - - POSITION: for (position = 0; position < st.size; position += 512) { - for (let bufPos = 0, bytes = 0; bufPos < 512; bufPos += bytes) { - bytes = fs.readSync( - fd, headBuf, bufPos, headBuf.length - bufPos, position + bufPos - ) - - if (position === 0 && headBuf[0] === 0x1f && headBuf[1] === 0x8b) { - throw new Error('cannot append to compressed archives') - } - - if (!bytes) { - break POSITION - } - } - - const h = new Header(headBuf) - if (!h.cksumValid) { - break - } - const entryBlockSize = 512 * Math.ceil(h.size / 512) - if (position + entryBlockSize + 512 > st.size) { - break - } - // the 512 for the header we just parsed will be added as well - // also jump ahead all the blocks for the body - position += entryBlockSize - if (opt.mtimeCache) { - opt.mtimeCache.set(h.path, h.mtime) - } - } - threw = false - - streamSync(opt, p, position, fd, files) - } finally { - if (threw) { - try { - fs.closeSync(fd) - } catch (er) {} - } - } -} - -const streamSync = (opt, p, position, fd, files) => { - const stream = new fsm.WriteStreamSync(opt.file, { - fd: fd, - start: position, - }) - p.pipe(stream) - addFilesSync(p, files) -} - -const replace = (opt, files, cb) => { - files = Array.from(files) - const p = new Pack(opt) - - const getPos = (fd, size, cb_) => { - const cb = (er, pos) => { - if (er) { - fs.close(fd, _ => cb_(er)) - } else { - cb_(null, pos) - } - } - - let position = 0 - if (size === 0) { - return cb(null, 0) - } - - let bufPos = 0 - const headBuf = Buffer.alloc(512) - const onread = (er, bytes) => { - if (er) { - return cb(er) - } - bufPos += bytes - if (bufPos < 512 && bytes) { - return fs.read( - fd, headBuf, bufPos, headBuf.length - bufPos, - position + bufPos, onread - ) - } - - if (position === 0 && headBuf[0] === 0x1f && headBuf[1] === 0x8b) { - return cb(new Error('cannot append to compressed archives')) - } - - // truncated header - if (bufPos < 512) { - return cb(null, position) - } - - const h = new Header(headBuf) - if (!h.cksumValid) { - return cb(null, position) - } - - const entryBlockSize = 512 * Math.ceil(h.size / 512) - if (position + entryBlockSize + 512 > size) { - return cb(null, position) - } - - position += entryBlockSize + 512 - if (position >= size) { - return cb(null, position) - } - - if (opt.mtimeCache) { - opt.mtimeCache.set(h.path, h.mtime) - } - bufPos = 0 - fs.read(fd, headBuf, 0, 512, position, onread) - } - fs.read(fd, headBuf, 0, 512, position, onread) - } - - const promise = new Promise((resolve, reject) => { - p.on('error', reject) - let flag = 'r+' - const onopen = (er, fd) => { - if (er && er.code === 'ENOENT' && flag === 'r+') { - flag = 'w+' - return fs.open(opt.file, flag, onopen) - } - - if (er) { - return reject(er) - } - - fs.fstat(fd, (er, st) => { - if (er) { - return fs.close(fd, () => reject(er)) - } - - getPos(fd, st.size, (er, position) => { - if (er) { - return reject(er) - } - const stream = new fsm.WriteStream(opt.file, { - fd: fd, - start: position, - }) - p.pipe(stream) - stream.on('error', reject) - stream.on('close', resolve) - addFilesAsync(p, files) - }) - }) - } - fs.open(opt.file, flag, onopen) - }) - - return cb ? promise.then(cb, cb) : promise -} - -const addFilesSync = (p, files) => { - files.forEach(file => { - if (file.charAt(0) === '@') { - t({ - file: path.resolve(p.cwd, file.slice(1)), - sync: true, - noResume: true, - onentry: entry => p.add(entry), - }) - } else { - p.add(file) - } - }) - p.end() -} - -const addFilesAsync = (p, files) => { - while (files.length) { - const file = files.shift() - if (file.charAt(0) === '@') { - return t({ - file: path.resolve(p.cwd, file.slice(1)), - noResume: true, - onentry: entry => p.add(entry), - }).then(_ => addFilesAsync(p, files)) - } else { - p.add(file) - } - } - p.end() -} diff --git a/lib/strip-absolute-path.js b/lib/strip-absolute-path.js deleted file mode 100644 index 185e2dea..00000000 --- a/lib/strip-absolute-path.js +++ /dev/null @@ -1,24 +0,0 @@ -// unix absolute paths are also absolute on win32, so we use this for both -const { isAbsolute, parse } = require('path').win32 - -// returns [root, stripped] -// Note that windows will think that //x/y/z/a has a "root" of //x/y, and in -// those cases, we want to sanitize it to x/y/z/a, not z/a, so we strip / -// explicitly if it's the first character. -// drive-specific relative paths on Windows get their root stripped off even -// though they are not absolute, so `c:../foo` becomes ['c:', '../foo'] -module.exports = path => { - let r = '' - - let parsed = parse(path) - while (isAbsolute(path) || parsed.root) { - // windows will think that //x/y/z has a "root" of //x/y/ - // but strip the //?/C:/ off of //?/C:/path - const root = path.charAt(0) === '/' && path.slice(0, 4) !== '//?/' ? '/' - : parsed.root - path = path.slice(root.length) - r += root - parsed = parse(path) - } - return [r, path] -} diff --git a/lib/strip-trailing-slashes.js b/lib/strip-trailing-slashes.js deleted file mode 100644 index 3e3ecec5..00000000 --- a/lib/strip-trailing-slashes.js +++ /dev/null @@ -1,13 +0,0 @@ -// warning: extremely hot code path. -// This has been meticulously optimized for use -// within npm install on large package trees. -// Do not edit without careful benchmarking. -module.exports = str => { - let i = str.length - 1 - let slashesStart = -1 - while (i > -1 && str.charAt(i) === '/') { - slashesStart = i - i-- - } - return slashesStart === -1 ? str : str.slice(0, slashesStart) -} diff --git a/lib/types.js b/lib/types.js deleted file mode 100644 index 7bfc2546..00000000 --- a/lib/types.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict' -// map types from key to human-friendly name -exports.name = new Map([ - ['0', 'File'], - // same as File - ['', 'OldFile'], - ['1', 'Link'], - ['2', 'SymbolicLink'], - // Devices and FIFOs aren't fully supported - // they are parsed, but skipped when unpacking - ['3', 'CharacterDevice'], - ['4', 'BlockDevice'], - ['5', 'Directory'], - ['6', 'FIFO'], - // same as File - ['7', 'ContiguousFile'], - // pax headers - ['g', 'GlobalExtendedHeader'], - ['x', 'ExtendedHeader'], - // vendor-specific stuff - // skip - ['A', 'SolarisACL'], - // like 5, but with data, which should be skipped - ['D', 'GNUDumpDir'], - // metadata only, skip - ['I', 'Inode'], - // data = link path of next file - ['K', 'NextFileHasLongLinkpath'], - // data = path of next file - ['L', 'NextFileHasLongPath'], - // skip - ['M', 'ContinuationFile'], - // like L - ['N', 'OldGnuLongPath'], - // skip - ['S', 'SparseFile'], - // skip - ['V', 'TapeVolumeHeader'], - // like x - ['X', 'OldExtendedHeader'], -]) - -// map the other direction -exports.code = new Map(Array.from(exports.name).map(kv => [kv[1], kv[0]])) diff --git a/lib/unpack.js b/lib/unpack.js deleted file mode 100644 index 03172e2c..00000000 --- a/lib/unpack.js +++ /dev/null @@ -1,923 +0,0 @@ -'use strict' - -// the PEND/UNPEND stuff tracks whether we're ready to emit end/close yet. -// but the path reservations are required to avoid race conditions where -// parallelized unpack ops may mess with one another, due to dependencies -// (like a Link depending on its target) or destructive operations (like -// clobbering an fs object to create one of a different type.) - -const assert = require('assert') -const Parser = require('./parse.js') -const fs = require('fs') -const fsm = require('fs-minipass') -const path = require('path') -const mkdir = require('./mkdir.js') -const wc = require('./winchars.js') -const pathReservations = require('./path-reservations.js') -const stripAbsolutePath = require('./strip-absolute-path.js') -const normPath = require('./normalize-windows-path.js') -const stripSlash = require('./strip-trailing-slashes.js') -const normalize = require('./normalize-unicode.js') - -const ONENTRY = Symbol('onEntry') -const CHECKFS = Symbol('checkFs') -const CHECKFS2 = Symbol('checkFs2') -const PRUNECACHE = Symbol('pruneCache') -const ISREUSABLE = Symbol('isReusable') -const MAKEFS = Symbol('makeFs') -const FILE = Symbol('file') -const DIRECTORY = Symbol('directory') -const LINK = Symbol('link') -const SYMLINK = Symbol('symlink') -const HARDLINK = Symbol('hardlink') -const UNSUPPORTED = Symbol('unsupported') -const CHECKPATH = Symbol('checkPath') -const MKDIR = Symbol('mkdir') -const ONERROR = Symbol('onError') -const PENDING = Symbol('pending') -const PEND = Symbol('pend') -const UNPEND = Symbol('unpend') -const ENDED = Symbol('ended') -const MAYBECLOSE = Symbol('maybeClose') -const SKIP = Symbol('skip') -const DOCHOWN = Symbol('doChown') -const UID = Symbol('uid') -const GID = Symbol('gid') -const CHECKED_CWD = Symbol('checkedCwd') -const crypto = require('crypto') -const getFlag = require('./get-write-flag.js') -const platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform -const isWindows = platform === 'win32' -const DEFAULT_MAX_DEPTH = 1024 - -// Unlinks on Windows are not atomic. -// -// This means that if you have a file entry, followed by another -// file entry with an identical name, and you cannot re-use the file -// (because it's a hardlink, or because unlink:true is set, or it's -// Windows, which does not have useful nlink values), then the unlink -// will be committed to the disk AFTER the new file has been written -// over the old one, deleting the new file. -// -// To work around this, on Windows systems, we rename the file and then -// delete the renamed file. It's a sloppy kludge, but frankly, I do not -// know of a better way to do this, given windows' non-atomic unlink -// semantics. -// -// See: https://github.com/npm/node-tar/issues/183 -/* istanbul ignore next */ -const unlinkFile = (path, cb) => { - if (!isWindows) { - return fs.unlink(path, cb) - } - - const name = path + '.DELETE.' + crypto.randomBytes(16).toString('hex') - fs.rename(path, name, er => { - if (er) { - return cb(er) - } - fs.unlink(name, cb) - }) -} - -/* istanbul ignore next */ -const unlinkFileSync = path => { - if (!isWindows) { - return fs.unlinkSync(path) - } - - const name = path + '.DELETE.' + crypto.randomBytes(16).toString('hex') - fs.renameSync(path, name) - fs.unlinkSync(name) -} - -// this.gid, entry.gid, this.processUid -const uint32 = (a, b, c) => - a === a >>> 0 ? a - : b === b >>> 0 ? b - : c - -// clear the cache if it's a case-insensitive unicode-squashing match. -// we can't know if the current file system is case-sensitive or supports -// unicode fully, so we check for similarity on the maximally compatible -// representation. Err on the side of pruning, since all it's doing is -// preventing lstats, and it's not the end of the world if we get a false -// positive. -// Note that on windows, we always drop the entire cache whenever a -// symbolic link is encountered, because 8.3 filenames are impossible -// to reason about, and collisions are hazards rather than just failures. -const cacheKeyNormalize = path => stripSlash(normPath(normalize(path))) - .toLowerCase() - -const pruneCache = (cache, abs) => { - abs = cacheKeyNormalize(abs) - for (const path of cache.keys()) { - const pnorm = cacheKeyNormalize(path) - if (pnorm === abs || pnorm.indexOf(abs + '/') === 0) { - cache.delete(path) - } - } -} - -const dropCache = cache => { - for (const key of cache.keys()) { - cache.delete(key) - } -} - -class Unpack extends Parser { - constructor (opt) { - if (!opt) { - opt = {} - } - - opt.ondone = _ => { - this[ENDED] = true - this[MAYBECLOSE]() - } - - super(opt) - - this[CHECKED_CWD] = false - - this.reservations = pathReservations() - - this.transform = typeof opt.transform === 'function' ? opt.transform : null - - this.writable = true - this.readable = false - - this[PENDING] = 0 - this[ENDED] = false - - this.dirCache = opt.dirCache || new Map() - - if (typeof opt.uid === 'number' || typeof opt.gid === 'number') { - // need both or neither - if (typeof opt.uid !== 'number' || typeof opt.gid !== 'number') { - throw new TypeError('cannot set owner without number uid and gid') - } - if (opt.preserveOwner) { - throw new TypeError( - 'cannot preserve owner in archive and also set owner explicitly') - } - this.uid = opt.uid - this.gid = opt.gid - this.setOwner = true - } else { - this.uid = null - this.gid = null - this.setOwner = false - } - - // default true for root - if (opt.preserveOwner === undefined && typeof opt.uid !== 'number') { - this.preserveOwner = process.getuid && process.getuid() === 0 - } else { - this.preserveOwner = !!opt.preserveOwner - } - - this.processUid = (this.preserveOwner || this.setOwner) && process.getuid ? - process.getuid() : null - this.processGid = (this.preserveOwner || this.setOwner) && process.getgid ? - process.getgid() : null - - // prevent excessively deep nesting of subfolders - // set to `Infinity` to remove this restriction - this.maxDepth = typeof opt.maxDepth === 'number' - ? opt.maxDepth - : DEFAULT_MAX_DEPTH - - // mostly just for testing, but useful in some cases. - // Forcibly trigger a chown on every entry, no matter what - this.forceChown = opt.forceChown === true - - // turn ><?| in filenames into 0xf000-higher encoded forms - this.win32 = !!opt.win32 || isWindows - - // do not unpack over files that are newer than what's in the archive - this.newer = !!opt.newer - - // do not unpack over ANY files - this.keep = !!opt.keep - - // do not set mtime/atime of extracted entries - this.noMtime = !!opt.noMtime - - // allow .., absolute path entries, and unpacking through symlinks - // without this, warn and skip .., relativize absolutes, and error - // on symlinks in extraction path - this.preservePaths = !!opt.preservePaths - - // unlink files and links before writing. This breaks existing hard - // links, and removes symlink directories rather than erroring - this.unlink = !!opt.unlink - - this.cwd = normPath(path.resolve(opt.cwd || process.cwd())) - this.strip = +opt.strip || 0 - // if we're not chmodding, then we don't need the process umask - this.processUmask = opt.noChmod ? 0 : process.umask() - this.umask = typeof opt.umask === 'number' ? opt.umask : this.processUmask - - // default mode for dirs created as parents - this.dmode = opt.dmode || (0o0777 & (~this.umask)) - this.fmode = opt.fmode || (0o0666 & (~this.umask)) - - this.on('entry', entry => this[ONENTRY](entry)) - } - - // a bad or damaged archive is a warning for Parser, but an error - // when extracting. Mark those errors as unrecoverable, because - // the Unpack contract cannot be met. - warn (code, msg, data = {}) { - if (code === 'TAR_BAD_ARCHIVE' || code === 'TAR_ABORT') { - data.recoverable = false - } - return super.warn(code, msg, data) - } - - [MAYBECLOSE] () { - if (this[ENDED] && this[PENDING] === 0) { - this.emit('prefinish') - this.emit('finish') - this.emit('end') - } - } - - [CHECKPATH] (entry) { - const p = normPath(entry.path) - const parts = p.split('/') - - if (this.strip) { - if (parts.length < this.strip) { - return false - } - if (entry.type === 'Link') { - const linkparts = normPath(entry.linkpath).split('/') - if (linkparts.length >= this.strip) { - entry.linkpath = linkparts.slice(this.strip).join('/') - } else { - return false - } - } - parts.splice(0, this.strip) - entry.path = parts.join('/') - } - - if (isFinite(this.maxDepth) && parts.length > this.maxDepth) { - this.warn('TAR_ENTRY_ERROR', 'path excessively deep', { - entry, - path: p, - depth: parts.length, - maxDepth: this.maxDepth, - }) - return false - } - - if (!this.preservePaths) { - if (parts.includes('..') || isWindows && /^[a-z]:\.\.$/i.test(parts[0])) { - this.warn('TAR_ENTRY_ERROR', `path contains '..'`, { - entry, - path: p, - }) - return false - } - - // strip off the root - const [root, stripped] = stripAbsolutePath(p) - if (root) { - entry.path = stripped - this.warn('TAR_ENTRY_INFO', `stripping ${root} from absolute path`, { - entry, - path: p, - }) - } - } - - if (path.isAbsolute(entry.path)) { - entry.absolute = normPath(path.resolve(entry.path)) - } else { - entry.absolute = normPath(path.resolve(this.cwd, entry.path)) - } - - // if we somehow ended up with a path that escapes the cwd, and we are - // not in preservePaths mode, then something is fishy! This should have - // been prevented above, so ignore this for coverage. - /* istanbul ignore if - defense in depth */ - if (!this.preservePaths && - entry.absolute.indexOf(this.cwd + '/') !== 0 && - entry.absolute !== this.cwd) { - this.warn('TAR_ENTRY_ERROR', 'path escaped extraction target', { - entry, - path: normPath(entry.path), - resolvedPath: entry.absolute, - cwd: this.cwd, - }) - return false - } - - // an archive can set properties on the extraction directory, but it - // may not replace the cwd with a different kind of thing entirely. - if (entry.absolute === this.cwd && - entry.type !== 'Directory' && - entry.type !== 'GNUDumpDir') { - return false - } - - // only encode : chars that aren't drive letter indicators - if (this.win32) { - const { root: aRoot } = path.win32.parse(entry.absolute) - entry.absolute = aRoot + wc.encode(entry.absolute.slice(aRoot.length)) - const { root: pRoot } = path.win32.parse(entry.path) - entry.path = pRoot + wc.encode(entry.path.slice(pRoot.length)) - } - - return true - } - - [ONENTRY] (entry) { - if (!this[CHECKPATH](entry)) { - return entry.resume() - } - - assert.equal(typeof entry.absolute, 'string') - - switch (entry.type) { - case 'Directory': - case 'GNUDumpDir': - if (entry.mode) { - entry.mode = entry.mode | 0o700 - } - - // eslint-disable-next-line no-fallthrough - case 'File': - case 'OldFile': - case 'ContiguousFile': - case 'Link': - case 'SymbolicLink': - return this[CHECKFS](entry) - - case 'CharacterDevice': - case 'BlockDevice': - case 'FIFO': - default: - return this[UNSUPPORTED](entry) - } - } - - [ONERROR] (er, entry) { - // Cwd has to exist, or else nothing works. That's serious. - // Other errors are warnings, which raise the error in strict - // mode, but otherwise continue on. - if (er.name === 'CwdError') { - this.emit('error', er) - } else { - this.warn('TAR_ENTRY_ERROR', er, { entry }) - this[UNPEND]() - entry.resume() - } - } - - [MKDIR] (dir, mode, cb) { - mkdir(normPath(dir), { - uid: this.uid, - gid: this.gid, - processUid: this.processUid, - processGid: this.processGid, - umask: this.processUmask, - preserve: this.preservePaths, - unlink: this.unlink, - cache: this.dirCache, - cwd: this.cwd, - mode: mode, - noChmod: this.noChmod, - }, cb) - } - - [DOCHOWN] (entry) { - // in preserve owner mode, chown if the entry doesn't match process - // in set owner mode, chown if setting doesn't match process - return this.forceChown || - this.preserveOwner && - (typeof entry.uid === 'number' && entry.uid !== this.processUid || - typeof entry.gid === 'number' && entry.gid !== this.processGid) - || - (typeof this.uid === 'number' && this.uid !== this.processUid || - typeof this.gid === 'number' && this.gid !== this.processGid) - } - - [UID] (entry) { - return uint32(this.uid, entry.uid, this.processUid) - } - - [GID] (entry) { - return uint32(this.gid, entry.gid, this.processGid) - } - - [FILE] (entry, fullyDone) { - const mode = entry.mode & 0o7777 || this.fmode - const stream = new fsm.WriteStream(entry.absolute, { - flags: getFlag(entry.size), - mode: mode, - autoClose: false, - }) - stream.on('error', er => { - if (stream.fd) { - fs.close(stream.fd, () => {}) - } - - // flush all the data out so that we aren't left hanging - // if the error wasn't actually fatal. otherwise the parse - // is blocked, and we never proceed. - stream.write = () => true - this[ONERROR](er, entry) - fullyDone() - }) - - let actions = 1 - const done = er => { - if (er) { - /* istanbul ignore else - we should always have a fd by now */ - if (stream.fd) { - fs.close(stream.fd, () => {}) - } - - this[ONERROR](er, entry) - fullyDone() - return - } - - if (--actions === 0) { - fs.close(stream.fd, er => { - if (er) { - this[ONERROR](er, entry) - } else { - this[UNPEND]() - } - fullyDone() - }) - } - } - - stream.on('finish', _ => { - // if futimes fails, try utimes - // if utimes fails, fail with the original error - // same for fchown/chown - const abs = entry.absolute - const fd = stream.fd - - if (entry.mtime && !this.noMtime) { - actions++ - const atime = entry.atime || new Date() - const mtime = entry.mtime - fs.futimes(fd, atime, mtime, er => - er ? fs.utimes(abs, atime, mtime, er2 => done(er2 && er)) - : done()) - } - - if (this[DOCHOWN](entry)) { - actions++ - const uid = this[UID](entry) - const gid = this[GID](entry) - fs.fchown(fd, uid, gid, er => - er ? fs.chown(abs, uid, gid, er2 => done(er2 && er)) - : done()) - } - - done() - }) - - const tx = this.transform ? this.transform(entry) || entry : entry - if (tx !== entry) { - tx.on('error', er => { - this[ONERROR](er, entry) - fullyDone() - }) - entry.pipe(tx) - } - tx.pipe(stream) - } - - [DIRECTORY] (entry, fullyDone) { - const mode = entry.mode & 0o7777 || this.dmode - this[MKDIR](entry.absolute, mode, er => { - if (er) { - this[ONERROR](er, entry) - fullyDone() - return - } - - let actions = 1 - const done = _ => { - if (--actions === 0) { - fullyDone() - this[UNPEND]() - entry.resume() - } - } - - if (entry.mtime && !this.noMtime) { - actions++ - fs.utimes(entry.absolute, entry.atime || new Date(), entry.mtime, done) - } - - if (this[DOCHOWN](entry)) { - actions++ - fs.chown(entry.absolute, this[UID](entry), this[GID](entry), done) - } - - done() - }) - } - - [UNSUPPORTED] (entry) { - entry.unsupported = true - this.warn('TAR_ENTRY_UNSUPPORTED', - `unsupported entry type: ${entry.type}`, { entry }) - entry.resume() - } - - [SYMLINK] (entry, done) { - this[LINK](entry, entry.linkpath, 'symlink', done) - } - - [HARDLINK] (entry, done) { - const linkpath = normPath(path.resolve(this.cwd, entry.linkpath)) - this[LINK](entry, linkpath, 'link', done) - } - - [PEND] () { - this[PENDING]++ - } - - [UNPEND] () { - this[PENDING]-- - this[MAYBECLOSE]() - } - - [SKIP] (entry) { - this[UNPEND]() - entry.resume() - } - - // Check if we can reuse an existing filesystem entry safely and - // overwrite it, rather than unlinking and recreating - // Windows doesn't report a useful nlink, so we just never reuse entries - [ISREUSABLE] (entry, st) { - return entry.type === 'File' && - !this.unlink && - st.isFile() && - st.nlink <= 1 && - !isWindows - } - - // check if a thing is there, and if so, try to clobber it - [CHECKFS] (entry) { - this[PEND]() - const paths = [entry.path] - if (entry.linkpath) { - paths.push(entry.linkpath) - } - this.reservations.reserve(paths, done => this[CHECKFS2](entry, done)) - } - - [PRUNECACHE] (entry) { - // if we are not creating a directory, and the path is in the dirCache, - // then that means we are about to delete the directory we created - // previously, and it is no longer going to be a directory, and neither - // is any of its children. - // If a symbolic link is encountered, all bets are off. There is no - // reasonable way to sanitize the cache in such a way we will be able to - // avoid having filesystem collisions. If this happens with a non-symlink - // entry, it'll just fail to unpack, but a symlink to a directory, using an - // 8.3 shortname or certain unicode attacks, can evade detection and lead - // to arbitrary writes to anywhere on the system. - if (entry.type === 'SymbolicLink') { - dropCache(this.dirCache) - } else if (entry.type !== 'Directory') { - pruneCache(this.dirCache, entry.absolute) - } - } - - [CHECKFS2] (entry, fullyDone) { - this[PRUNECACHE](entry) - - const done = er => { - this[PRUNECACHE](entry) - fullyDone(er) - } - - const checkCwd = () => { - this[MKDIR](this.cwd, this.dmode, er => { - if (er) { - this[ONERROR](er, entry) - done() - return - } - this[CHECKED_CWD] = true - start() - }) - } - - const start = () => { - if (entry.absolute !== this.cwd) { - const parent = normPath(path.dirname(entry.absolute)) - if (parent !== this.cwd) { - return this[MKDIR](parent, this.dmode, er => { - if (er) { - this[ONERROR](er, entry) - done() - return - } - afterMakeParent() - }) - } - } - afterMakeParent() - } - - const afterMakeParent = () => { - fs.lstat(entry.absolute, (lstatEr, st) => { - if (st && (this.keep || this.newer && st.mtime > entry.mtime)) { - this[SKIP](entry) - done() - return - } - if (lstatEr || this[ISREUSABLE](entry, st)) { - return this[MAKEFS](null, entry, done) - } - - if (st.isDirectory()) { - if (entry.type === 'Directory') { - const needChmod = !this.noChmod && - entry.mode && - (st.mode & 0o7777) !== entry.mode - const afterChmod = er => this[MAKEFS](er, entry, done) - if (!needChmod) { - return afterChmod() - } - return fs.chmod(entry.absolute, entry.mode, afterChmod) - } - // Not a dir entry, have to remove it. - // NB: the only way to end up with an entry that is the cwd - // itself, in such a way that == does not detect, is a - // tricky windows absolute path with UNC or 8.3 parts (and - // preservePaths:true, or else it will have been stripped). - // In that case, the user has opted out of path protections - // explicitly, so if they blow away the cwd, c'est la vie. - if (entry.absolute !== this.cwd) { - return fs.rmdir(entry.absolute, er => - this[MAKEFS](er, entry, done)) - } - } - - // not a dir, and not reusable - // don't remove if the cwd, we want that error - if (entry.absolute === this.cwd) { - return this[MAKEFS](null, entry, done) - } - - unlinkFile(entry.absolute, er => - this[MAKEFS](er, entry, done)) - }) - } - - if (this[CHECKED_CWD]) { - start() - } else { - checkCwd() - } - } - - [MAKEFS] (er, entry, done) { - if (er) { - this[ONERROR](er, entry) - done() - return - } - - switch (entry.type) { - case 'File': - case 'OldFile': - case 'ContiguousFile': - return this[FILE](entry, done) - - case 'Link': - return this[HARDLINK](entry, done) - - case 'SymbolicLink': - return this[SYMLINK](entry, done) - - case 'Directory': - case 'GNUDumpDir': - return this[DIRECTORY](entry, done) - } - } - - [LINK] (entry, linkpath, link, done) { - // XXX: get the type ('symlink' or 'junction') for windows - fs[link](linkpath, entry.absolute, er => { - if (er) { - this[ONERROR](er, entry) - } else { - this[UNPEND]() - entry.resume() - } - done() - }) - } -} - -const callSync = fn => { - try { - return [null, fn()] - } catch (er) { - return [er, null] - } -} -class UnpackSync extends Unpack { - [MAKEFS] (er, entry) { - return super[MAKEFS](er, entry, () => {}) - } - - [CHECKFS] (entry) { - this[PRUNECACHE](entry) - - if (!this[CHECKED_CWD]) { - const er = this[MKDIR](this.cwd, this.dmode) - if (er) { - return this[ONERROR](er, entry) - } - this[CHECKED_CWD] = true - } - - // don't bother to make the parent if the current entry is the cwd, - // we've already checked it. - if (entry.absolute !== this.cwd) { - const parent = normPath(path.dirname(entry.absolute)) - if (parent !== this.cwd) { - const mkParent = this[MKDIR](parent, this.dmode) - if (mkParent) { - return this[ONERROR](mkParent, entry) - } - } - } - - const [lstatEr, st] = callSync(() => fs.lstatSync(entry.absolute)) - if (st && (this.keep || this.newer && st.mtime > entry.mtime)) { - return this[SKIP](entry) - } - - if (lstatEr || this[ISREUSABLE](entry, st)) { - return this[MAKEFS](null, entry) - } - - if (st.isDirectory()) { - if (entry.type === 'Directory') { - const needChmod = !this.noChmod && - entry.mode && - (st.mode & 0o7777) !== entry.mode - const [er] = needChmod ? callSync(() => { - fs.chmodSync(entry.absolute, entry.mode) - }) : [] - return this[MAKEFS](er, entry) - } - // not a dir entry, have to remove it - const [er] = callSync(() => fs.rmdirSync(entry.absolute)) - this[MAKEFS](er, entry) - } - - // not a dir, and not reusable. - // don't remove if it's the cwd, since we want that error. - const [er] = entry.absolute === this.cwd ? [] - : callSync(() => unlinkFileSync(entry.absolute)) - this[MAKEFS](er, entry) - } - - [FILE] (entry, done) { - const mode = entry.mode & 0o7777 || this.fmode - - const oner = er => { - let closeError - try { - fs.closeSync(fd) - } catch (e) { - closeError = e - } - if (er || closeError) { - this[ONERROR](er || closeError, entry) - } - done() - } - - let fd - try { - fd = fs.openSync(entry.absolute, getFlag(entry.size), mode) - } catch (er) { - return oner(er) - } - const tx = this.transform ? this.transform(entry) || entry : entry - if (tx !== entry) { - tx.on('error', er => this[ONERROR](er, entry)) - entry.pipe(tx) - } - - tx.on('data', chunk => { - try { - fs.writeSync(fd, chunk, 0, chunk.length) - } catch (er) { - oner(er) - } - }) - - tx.on('end', _ => { - let er = null - // try both, falling futimes back to utimes - // if either fails, handle the first error - if (entry.mtime && !this.noMtime) { - const atime = entry.atime || new Date() - const mtime = entry.mtime - try { - fs.futimesSync(fd, atime, mtime) - } catch (futimeser) { - try { - fs.utimesSync(entry.absolute, atime, mtime) - } catch (utimeser) { - er = futimeser - } - } - } - - if (this[DOCHOWN](entry)) { - const uid = this[UID](entry) - const gid = this[GID](entry) - - try { - fs.fchownSync(fd, uid, gid) - } catch (fchowner) { - try { - fs.chownSync(entry.absolute, uid, gid) - } catch (chowner) { - er = er || fchowner - } - } - } - - oner(er) - }) - } - - [DIRECTORY] (entry, done) { - const mode = entry.mode & 0o7777 || this.dmode - const er = this[MKDIR](entry.absolute, mode) - if (er) { - this[ONERROR](er, entry) - done() - return - } - if (entry.mtime && !this.noMtime) { - try { - fs.utimesSync(entry.absolute, entry.atime || new Date(), entry.mtime) - } catch (er) {} - } - if (this[DOCHOWN](entry)) { - try { - fs.chownSync(entry.absolute, this[UID](entry), this[GID](entry)) - } catch (er) {} - } - done() - entry.resume() - } - - [MKDIR] (dir, mode) { - try { - return mkdir.sync(normPath(dir), { - uid: this.uid, - gid: this.gid, - processUid: this.processUid, - processGid: this.processGid, - umask: this.processUmask, - preserve: this.preservePaths, - unlink: this.unlink, - cache: this.dirCache, - cwd: this.cwd, - mode: mode, - }) - } catch (er) { - return er - } - } - - [LINK] (entry, linkpath, link, done) { - try { - fs[link + 'Sync'](linkpath, entry.absolute) - done() - entry.resume() - } catch (er) { - return this[ONERROR](er, entry) - } - } -} - -Unpack.Sync = UnpackSync -module.exports = Unpack diff --git a/lib/update.js b/lib/update.js deleted file mode 100644 index 4d328543..00000000 --- a/lib/update.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict' - -// tar -u - -const hlo = require('./high-level-opt.js') -const r = require('./replace.js') -// just call tar.r with the filter and mtimeCache - -module.exports = (opt_, files, cb) => { - const opt = hlo(opt_) - - if (!opt.file) { - throw new TypeError('file is required') - } - - if (opt.gzip || opt.brotli || opt.file.endsWith('.br') || opt.file.endsWith('.tbr')) { - throw new TypeError('cannot append to compressed archives') - } - - if (!files || !Array.isArray(files) || !files.length) { - throw new TypeError('no files or directories specified') - } - - files = Array.from(files) - - mtimeFilter(opt) - return r(opt, files, cb) -} - -const mtimeFilter = opt => { - const filter = opt.filter - - if (!opt.mtimeCache) { - opt.mtimeCache = new Map() - } - - opt.filter = filter ? (path, stat) => - filter(path, stat) && !(opt.mtimeCache.get(path) > stat.mtime) - : (path, stat) => !(opt.mtimeCache.get(path) > stat.mtime) -} diff --git a/lib/warn-mixin.js b/lib/warn-mixin.js deleted file mode 100644 index a9406396..00000000 --- a/lib/warn-mixin.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict' -module.exports = Base => class extends Base { - warn (code, message, data = {}) { - if (this.file) { - data.file = this.file - } - if (this.cwd) { - data.cwd = this.cwd - } - data.code = message instanceof Error && message.code || code - data.tarCode = code - if (!this.strict && data.recoverable !== false) { - if (message instanceof Error) { - data = Object.assign(message, data) - message = message.message - } - this.emit('warn', data.tarCode, message, data) - } else if (message instanceof Error) { - this.emit('error', Object.assign(message, data)) - } else { - this.emit('error', Object.assign(new Error(`${code}: ${message}`), data)) - } - } -} diff --git a/lib/winchars.js b/lib/winchars.js deleted file mode 100644 index ebcab4ae..00000000 --- a/lib/winchars.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict' - -// When writing files on Windows, translate the characters to their -// 0xf000 higher-encoded versions. - -const raw = [ - '|', - '<', - '>', - '?', - ':', -] - -const win = raw.map(char => - String.fromCharCode(0xf000 + char.charCodeAt(0))) - -const toWin = new Map(raw.map((char, i) => [char, win[i]])) -const toRaw = new Map(win.map((char, i) => [char, raw[i]])) - -module.exports = { - encode: s => raw.reduce((s, c) => s.split(c).join(toWin.get(c)), s), - decode: s => win.reduce((s, c) => s.split(c).join(toRaw.get(c)), s), -} diff --git a/lib/write-entry.js b/lib/write-entry.js deleted file mode 100644 index 7d2f3eb1..00000000 --- a/lib/write-entry.js +++ /dev/null @@ -1,546 +0,0 @@ -'use strict' -const { Minipass } = require('minipass') -const Pax = require('./pax.js') -const Header = require('./header.js') -const fs = require('fs') -const path = require('path') -const normPath = require('./normalize-windows-path.js') -const stripSlash = require('./strip-trailing-slashes.js') - -const prefixPath = (path, prefix) => { - if (!prefix) { - return normPath(path) - } - path = normPath(path).replace(/^\.(\/|$)/, '') - return stripSlash(prefix) + '/' + path -} - -const maxReadSize = 16 * 1024 * 1024 -const PROCESS = Symbol('process') -const FILE = Symbol('file') -const DIRECTORY = Symbol('directory') -const SYMLINK = Symbol('symlink') -const HARDLINK = Symbol('hardlink') -const HEADER = Symbol('header') -const READ = Symbol('read') -const LSTAT = Symbol('lstat') -const ONLSTAT = Symbol('onlstat') -const ONREAD = Symbol('onread') -const ONREADLINK = Symbol('onreadlink') -const OPENFILE = Symbol('openfile') -const ONOPENFILE = Symbol('onopenfile') -const CLOSE = Symbol('close') -const MODE = Symbol('mode') -const AWAITDRAIN = Symbol('awaitDrain') -const ONDRAIN = Symbol('ondrain') -const PREFIX = Symbol('prefix') -const HAD_ERROR = Symbol('hadError') -const warner = require('./warn-mixin.js') -const winchars = require('./winchars.js') -const stripAbsolutePath = require('./strip-absolute-path.js') - -const modeFix = require('./mode-fix.js') - -const WriteEntry = warner(class WriteEntry extends Minipass { - constructor (p, opt) { - opt = opt || {} - super(opt) - if (typeof p !== 'string') { - throw new TypeError('path is required') - } - this.path = normPath(p) - // suppress atime, ctime, uid, gid, uname, gname - this.portable = !!opt.portable - // until node has builtin pwnam functions, this'll have to do - this.myuid = process.getuid && process.getuid() || 0 - this.myuser = process.env.USER || '' - this.maxReadSize = opt.maxReadSize || maxReadSize - this.linkCache = opt.linkCache || new Map() - this.statCache = opt.statCache || new Map() - this.preservePaths = !!opt.preservePaths - this.cwd = normPath(opt.cwd || process.cwd()) - this.strict = !!opt.strict - this.noPax = !!opt.noPax - this.noMtime = !!opt.noMtime - this.mtime = opt.mtime || null - this.prefix = opt.prefix ? normPath(opt.prefix) : null - - this.fd = null - this.blockLen = null - this.blockRemain = null - this.buf = null - this.offset = null - this.length = null - this.pos = null - this.remain = null - - if (typeof opt.onwarn === 'function') { - this.on('warn', opt.onwarn) - } - - let pathWarn = false - if (!this.preservePaths) { - const [root, stripped] = stripAbsolutePath(this.path) - if (root) { - this.path = stripped - pathWarn = root - } - } - - this.win32 = !!opt.win32 || process.platform === 'win32' - if (this.win32) { - // force the \ to / normalization, since we might not *actually* - // be on windows, but want \ to be considered a path separator. - this.path = winchars.decode(this.path.replace(/\\/g, '/')) - p = p.replace(/\\/g, '/') - } - - this.absolute = normPath(opt.absolute || path.resolve(this.cwd, p)) - - if (this.path === '') { - this.path = './' - } - - if (pathWarn) { - this.warn('TAR_ENTRY_INFO', `stripping ${pathWarn} from absolute path`, { - entry: this, - path: pathWarn + this.path, - }) - } - - if (this.statCache.has(this.absolute)) { - this[ONLSTAT](this.statCache.get(this.absolute)) - } else { - this[LSTAT]() - } - } - - emit (ev, ...data) { - if (ev === 'error') { - this[HAD_ERROR] = true - } - return super.emit(ev, ...data) - } - - [LSTAT] () { - fs.lstat(this.absolute, (er, stat) => { - if (er) { - return this.emit('error', er) - } - this[ONLSTAT](stat) - }) - } - - [ONLSTAT] (stat) { - this.statCache.set(this.absolute, stat) - this.stat = stat - if (!stat.isFile()) { - stat.size = 0 - } - this.type = getType(stat) - this.emit('stat', stat) - this[PROCESS]() - } - - [PROCESS] () { - switch (this.type) { - case 'File': return this[FILE]() - case 'Directory': return this[DIRECTORY]() - case 'SymbolicLink': return this[SYMLINK]() - // unsupported types are ignored. - default: return this.end() - } - } - - [MODE] (mode) { - return modeFix(mode, this.type === 'Directory', this.portable) - } - - [PREFIX] (path) { - return prefixPath(path, this.prefix) - } - - [HEADER] () { - if (this.type === 'Directory' && this.portable) { - this.noMtime = true - } - - this.header = new Header({ - path: this[PREFIX](this.path), - // only apply the prefix to hard links. - linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath) - : this.linkpath, - // only the permissions and setuid/setgid/sticky bitflags - // not the higher-order bits that specify file type - mode: this[MODE](this.stat.mode), - uid: this.portable ? null : this.stat.uid, - gid: this.portable ? null : this.stat.gid, - size: this.stat.size, - mtime: this.noMtime ? null : this.mtime || this.stat.mtime, - type: this.type, - uname: this.portable ? null : - this.stat.uid === this.myuid ? this.myuser : '', - atime: this.portable ? null : this.stat.atime, - ctime: this.portable ? null : this.stat.ctime, - }) - - if (this.header.encode() && !this.noPax) { - super.write(new Pax({ - atime: this.portable ? null : this.header.atime, - ctime: this.portable ? null : this.header.ctime, - gid: this.portable ? null : this.header.gid, - mtime: this.noMtime ? null : this.mtime || this.header.mtime, - path: this[PREFIX](this.path), - linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath) - : this.linkpath, - size: this.header.size, - uid: this.portable ? null : this.header.uid, - uname: this.portable ? null : this.header.uname, - dev: this.portable ? null : this.stat.dev, - ino: this.portable ? null : this.stat.ino, - nlink: this.portable ? null : this.stat.nlink, - }).encode()) - } - super.write(this.header.block) - } - - [DIRECTORY] () { - if (this.path.slice(-1) !== '/') { - this.path += '/' - } - this.stat.size = 0 - this[HEADER]() - this.end() - } - - [SYMLINK] () { - fs.readlink(this.absolute, (er, linkpath) => { - if (er) { - return this.emit('error', er) - } - this[ONREADLINK](linkpath) - }) - } - - [ONREADLINK] (linkpath) { - this.linkpath = normPath(linkpath) - this[HEADER]() - this.end() - } - - [HARDLINK] (linkpath) { - this.type = 'Link' - this.linkpath = normPath(path.relative(this.cwd, linkpath)) - this.stat.size = 0 - this[HEADER]() - this.end() - } - - [FILE] () { - if (this.stat.nlink > 1) { - const linkKey = this.stat.dev + ':' + this.stat.ino - if (this.linkCache.has(linkKey)) { - const linkpath = this.linkCache.get(linkKey) - if (linkpath.indexOf(this.cwd) === 0) { - return this[HARDLINK](linkpath) - } - } - this.linkCache.set(linkKey, this.absolute) - } - - this[HEADER]() - if (this.stat.size === 0) { - return this.end() - } - - this[OPENFILE]() - } - - [OPENFILE] () { - fs.open(this.absolute, 'r', (er, fd) => { - if (er) { - return this.emit('error', er) - } - this[ONOPENFILE](fd) - }) - } - - [ONOPENFILE] (fd) { - this.fd = fd - if (this[HAD_ERROR]) { - return this[CLOSE]() - } - - this.blockLen = 512 * Math.ceil(this.stat.size / 512) - this.blockRemain = this.blockLen - const bufLen = Math.min(this.blockLen, this.maxReadSize) - this.buf = Buffer.allocUnsafe(bufLen) - this.offset = 0 - this.pos = 0 - this.remain = this.stat.size - this.length = this.buf.length - this[READ]() - } - - [READ] () { - const { fd, buf, offset, length, pos } = this - fs.read(fd, buf, offset, length, pos, (er, bytesRead) => { - if (er) { - // ignoring the error from close(2) is a bad practice, but at - // this point we already have an error, don't need another one - return this[CLOSE](() => this.emit('error', er)) - } - this[ONREAD](bytesRead) - }) - } - - [CLOSE] (cb) { - fs.close(this.fd, cb) - } - - [ONREAD] (bytesRead) { - if (bytesRead <= 0 && this.remain > 0) { - const er = new Error('encountered unexpected EOF') - er.path = this.absolute - er.syscall = 'read' - er.code = 'EOF' - return this[CLOSE](() => this.emit('error', er)) - } - - if (bytesRead > this.remain) { - const er = new Error('did not encounter expected EOF') - er.path = this.absolute - er.syscall = 'read' - er.code = 'EOF' - return this[CLOSE](() => this.emit('error', er)) - } - - // null out the rest of the buffer, if we could fit the block padding - // at the end of this loop, we've incremented bytesRead and this.remain - // to be incremented up to the blockRemain level, as if we had expected - // to get a null-padded file, and read it until the end. then we will - // decrement both remain and blockRemain by bytesRead, and know that we - // reached the expected EOF, without any null buffer to append. - if (bytesRead === this.remain) { - for (let i = bytesRead; i < this.length && bytesRead < this.blockRemain; i++) { - this.buf[i + this.offset] = 0 - bytesRead++ - this.remain++ - } - } - - const writeBuf = this.offset === 0 && bytesRead === this.buf.length ? - this.buf : this.buf.slice(this.offset, this.offset + bytesRead) - - const flushed = this.write(writeBuf) - if (!flushed) { - this[AWAITDRAIN](() => this[ONDRAIN]()) - } else { - this[ONDRAIN]() - } - } - - [AWAITDRAIN] (cb) { - this.once('drain', cb) - } - - write (writeBuf) { - if (this.blockRemain < writeBuf.length) { - const er = new Error('writing more data than expected') - er.path = this.absolute - return this.emit('error', er) - } - this.remain -= writeBuf.length - this.blockRemain -= writeBuf.length - this.pos += writeBuf.length - this.offset += writeBuf.length - return super.write(writeBuf) - } - - [ONDRAIN] () { - if (!this.remain) { - if (this.blockRemain) { - super.write(Buffer.alloc(this.blockRemain)) - } - return this[CLOSE](er => er ? this.emit('error', er) : this.end()) - } - - if (this.offset >= this.length) { - // if we only have a smaller bit left to read, alloc a smaller buffer - // otherwise, keep it the same length it was before. - this.buf = Buffer.allocUnsafe(Math.min(this.blockRemain, this.buf.length)) - this.offset = 0 - } - this.length = this.buf.length - this.offset - this[READ]() - } -}) - -class WriteEntrySync extends WriteEntry { - [LSTAT] () { - this[ONLSTAT](fs.lstatSync(this.absolute)) - } - - [SYMLINK] () { - this[ONREADLINK](fs.readlinkSync(this.absolute)) - } - - [OPENFILE] () { - this[ONOPENFILE](fs.openSync(this.absolute, 'r')) - } - - [READ] () { - let threw = true - try { - const { fd, buf, offset, length, pos } = this - const bytesRead = fs.readSync(fd, buf, offset, length, pos) - this[ONREAD](bytesRead) - threw = false - } finally { - // ignoring the error from close(2) is a bad practice, but at - // this point we already have an error, don't need another one - if (threw) { - try { - this[CLOSE](() => {}) - } catch (er) {} - } - } - } - - [AWAITDRAIN] (cb) { - cb() - } - - [CLOSE] (cb) { - fs.closeSync(this.fd) - cb() - } -} - -const WriteEntryTar = warner(class WriteEntryTar extends Minipass { - constructor (readEntry, opt) { - opt = opt || {} - super(opt) - this.preservePaths = !!opt.preservePaths - this.portable = !!opt.portable - this.strict = !!opt.strict - this.noPax = !!opt.noPax - this.noMtime = !!opt.noMtime - - this.readEntry = readEntry - this.type = readEntry.type - if (this.type === 'Directory' && this.portable) { - this.noMtime = true - } - - this.prefix = opt.prefix || null - - this.path = normPath(readEntry.path) - this.mode = this[MODE](readEntry.mode) - this.uid = this.portable ? null : readEntry.uid - this.gid = this.portable ? null : readEntry.gid - this.uname = this.portable ? null : readEntry.uname - this.gname = this.portable ? null : readEntry.gname - this.size = readEntry.size - this.mtime = this.noMtime ? null : opt.mtime || readEntry.mtime - this.atime = this.portable ? null : readEntry.atime - this.ctime = this.portable ? null : readEntry.ctime - this.linkpath = normPath(readEntry.linkpath) - - if (typeof opt.onwarn === 'function') { - this.on('warn', opt.onwarn) - } - - let pathWarn = false - if (!this.preservePaths) { - const [root, stripped] = stripAbsolutePath(this.path) - if (root) { - this.path = stripped - pathWarn = root - } - } - - this.remain = readEntry.size - this.blockRemain = readEntry.startBlockSize - - this.header = new Header({ - path: this[PREFIX](this.path), - linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath) - : this.linkpath, - // only the permissions and setuid/setgid/sticky bitflags - // not the higher-order bits that specify file type - mode: this.mode, - uid: this.portable ? null : this.uid, - gid: this.portable ? null : this.gid, - size: this.size, - mtime: this.noMtime ? null : this.mtime, - type: this.type, - uname: this.portable ? null : this.uname, - atime: this.portable ? null : this.atime, - ctime: this.portable ? null : this.ctime, - }) - - if (pathWarn) { - this.warn('TAR_ENTRY_INFO', `stripping ${pathWarn} from absolute path`, { - entry: this, - path: pathWarn + this.path, - }) - } - - if (this.header.encode() && !this.noPax) { - super.write(new Pax({ - atime: this.portable ? null : this.atime, - ctime: this.portable ? null : this.ctime, - gid: this.portable ? null : this.gid, - mtime: this.noMtime ? null : this.mtime, - path: this[PREFIX](this.path), - linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath) - : this.linkpath, - size: this.size, - uid: this.portable ? null : this.uid, - uname: this.portable ? null : this.uname, - dev: this.portable ? null : this.readEntry.dev, - ino: this.portable ? null : this.readEntry.ino, - nlink: this.portable ? null : this.readEntry.nlink, - }).encode()) - } - - super.write(this.header.block) - readEntry.pipe(this) - } - - [PREFIX] (path) { - return prefixPath(path, this.prefix) - } - - [MODE] (mode) { - return modeFix(mode, this.type === 'Directory', this.portable) - } - - write (data) { - const writeLen = data.length - if (writeLen > this.blockRemain) { - throw new Error('writing more to entry than is appropriate') - } - this.blockRemain -= writeLen - return super.write(data) - } - - end () { - if (this.blockRemain) { - super.write(Buffer.alloc(this.blockRemain)) - } - return super.end() - } -}) - -WriteEntry.Sync = WriteEntrySync -WriteEntry.Tar = WriteEntryTar - -const getType = stat => - stat.isFile() ? 'File' - : stat.isDirectory() ? 'Directory' - : stat.isSymbolicLink() ? 'SymbolicLink' - : 'Unsupported' - -module.exports = WriteEntry From b0fbdea4631f9f65f15786fb5333695a9164a536 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 10 Apr 2024 13:07:07 -0700 Subject: [PATCH 72/96] 7.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4090358b..ae876dfa 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "6.2.1", + "version": "7.0.0", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From af043922c09d12d28e21ecb463c7c9ff375cbf47 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Sun, 14 Apr 2024 14:43:59 -0700 Subject: [PATCH 73/96] Do not apply linkpath,global from global pax header --- src/header.ts | 7 +++++-- test/header.js | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/header.ts b/src/header.ts index e648876e..0ff3f84b 100644 --- a/src/header.ts +++ b/src/header.ts @@ -96,8 +96,9 @@ export class Header implements HeaderData { // if we have extended or global extended headers, apply them now // See https://github.com/npm/node-tar/pull/187 - if (ex) this.#slurp(ex) + // Apply global before local, so it overrides if (gex) this.#slurp(gex, true) + if (ex) this.#slurp(ex) // old tar versions marked dirs as a file with a trailing / const t = decString(buf, off + 156, 1) @@ -168,7 +169,9 @@ export class Header implements HeaderData { return !( v === null || v === undefined || - (k === 'path' && gex) + (k === 'path' && gex) || + (k === 'linkpath' && gex) || + (k === 'global') ) }), ), diff --git a/test/header.js b/test/header.js index 8d3eb06e..92554a65 100644 --- a/test/header.js +++ b/test/header.js @@ -614,6 +614,8 @@ t.test('null block, global extended header', t => { { path: '/global.path', foo: 'global foo', + global: true, + linkpath: 'asdf' }, ) t.match(h, { From d99fce38ebf5175cce4c6623c53f4b17d6d31157 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Sun, 14 Apr 2024 14:45:08 -0700 Subject: [PATCH 74/96] 7.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ae876dfa..44fa84ac 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "7.0.0", + "version": "7.0.1", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From faf9359ca738b2ba8c5527973cd9529c69add15e Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Tue, 16 Apr 2024 11:10:36 -0700 Subject: [PATCH 75/96] remove temlate-oss stuff --- scripts/template-oss/_step-git.yml | 4 ---- scripts/template-oss/_step-node.yml | 31 ----------------------------- scripts/template-oss/_step-test.yml | 3 --- 3 files changed, 38 deletions(-) delete mode 100644 scripts/template-oss/_step-git.yml delete mode 100644 scripts/template-oss/_step-node.yml delete mode 100644 scripts/template-oss/_step-test.yml diff --git a/scripts/template-oss/_step-git.yml b/scripts/template-oss/_step-git.yml deleted file mode 100644 index 329bf5bb..00000000 --- a/scripts/template-oss/_step-git.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: Support Long Paths - if: matrix.platform.os == 'windows-latest' - run: git config --system core.longpaths true -{{> defaultStepGit }} diff --git a/scripts/template-oss/_step-node.yml b/scripts/template-oss/_step-node.yml deleted file mode 100644 index f15e8698..00000000 --- a/scripts/template-oss/_step-node.yml +++ /dev/null @@ -1,31 +0,0 @@ -- name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: {{#if jobIsMatrix}}$\{{ matrix.node-version }}{{else}}{{ last ciVersions }}{{/if}} - {{#if lockfile}} - cache: npm - {{/if}} -{{#if updateNpm}} -{{#if jobIsMatrix}} -- name: Update Windows npm - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package -- name: Install npm@7 - if: startsWith(matrix.node-version, '10.') || startsWith(matrix.node-version, '12.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 -- name: Install npm@latest - if: $\{{ !startsWith(matrix.node-version, '10.') && !startsWith(matrix.node-version, '12.') }} -{{else}} -- name: Install npm@latest -{{/if}} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest -- name: npm Version - run: npm -v -{{/if}} diff --git a/scripts/template-oss/_step-test.yml b/scripts/template-oss/_step-test.yml deleted file mode 100644 index 84b6d549..00000000 --- a/scripts/template-oss/_step-test.yml +++ /dev/null @@ -1,3 +0,0 @@ -- name: Set Tap RC - run: node ./test/fixtures/taprc.js -{{> defaultStepTest }} From bead873b5c22915b15da72e95b0da6b87eeb384e Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Tue, 16 Apr 2024 11:11:59 -0700 Subject: [PATCH 76/96] remove more cruft, format codes --- .commitlintrc.js | 10 - .eslintrc.js | 17 -- .eslintrc.local.js | 16 -- README.md | 380 ++++++++++++++--------------- map.js | 11 +- package.json | 3 +- scripts/generate-parse-fixtures.js | 127 +++++----- src/create.ts | 13 +- src/extract.ts | 23 +- src/get-write-flag.ts | 5 +- src/header.ts | 44 ++-- src/large-numbers.ts | 19 +- src/list.ts | 25 +- src/mode-fix.ts | 6 +- src/normalize-windows-path.ts | 6 +- src/parse.ts | 34 ++- src/path-reservations.ts | 5 +- src/pax.ts | 16 +- src/read-entry.ts | 5 +- src/replace.ts | 4 +- src/strip-absolute-path.ts | 6 +- src/symlink-error.ts | 2 +- src/unpack.ts | 82 +++---- src/update.ts | 17 +- src/write-entry.ts | 79 +++--- test/get-write-flag.js | 30 +-- test/header.js | 4 +- test/large-numbers.js | 43 +++- test/normalize-unicode.js | 2 +- test/pack.js | 65 ++++- test/parse.js | 99 ++++---- test/path-reservations.js | 19 +- test/pax.js | 230 ++++++++--------- test/replace.js | 355 +++++++++++++++++---------- test/unpack.js | 5 +- test/update.js | 297 +++++++++++++--------- test/warn-method.js | 25 +- test/write-entry.js | 24 +- 38 files changed, 1198 insertions(+), 955 deletions(-) delete mode 100644 .commitlintrc.js delete mode 100644 .eslintrc.js delete mode 100644 .eslintrc.local.js diff --git a/.commitlintrc.js b/.commitlintrc.js deleted file mode 100644 index 5b0b1a52..00000000 --- a/.commitlintrc.js +++ /dev/null @@ -1,10 +0,0 @@ -/* This file is automatically added by @npmcli/template-oss. Do not edit. */ - -module.exports = { - extends: ['@commitlint/config-conventional'], - rules: { - 'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'deps', 'chore']], - 'header-max-length': [2, 'always', 80], - 'subject-case': [0, 'always', ['lower-case', 'sentence-case', 'start-case']], - }, -} diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 5db9f815..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,17 +0,0 @@ -/* This file is automatically added by @npmcli/template-oss. Do not edit. */ - -'use strict' - -const { readdirSync: readdir } = require('fs') - -const localConfigs = readdir(__dirname) - .filter((file) => file.startsWith('.eslintrc.local.')) - .map((file) => `./${file}`) - -module.exports = { - root: true, - extends: [ - '@npmcli', - ...localConfigs, - ], -} diff --git a/.eslintrc.local.js b/.eslintrc.local.js deleted file mode 100644 index b820d970..00000000 --- a/.eslintrc.local.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - rules: { - 'max-len': 0, - 'no-shadow': 0, - 'no-unused-expressions': 0, - 'no-sequences': 0, - 'no-empty': 0, - }, - overrides: [{ - files: ['test/**'], - rules: { - 'promise/catch-or-return': 0, - 'promise/always-return': 0, - }, - }], -} diff --git a/README.md b/README.md index 971638ab..3471a4a5 100644 --- a/README.md +++ b/README.md @@ -4,29 +4,29 @@ Fast and full-featured Tar for Node.js The API is designed to mimic the behavior of `tar(1)` on unix systems. If you are familiar with how tar works, most of this will hopefully be -straightforward for you. If not, then hopefully this module can teach +straightforward for you. If not, then hopefully this module can teach you useful unix skills that may come in handy someday :) ## Background A "tar file" or "tarball" is an archive of file system entries -(directories, files, links, etc.) The name comes from "tape archive". +(directories, files, links, etc.) The name comes from "tape archive". If you run `man tar` on almost any Unix command line, you'll learn quite a bit about what it can do, and its history. Tar has 5 main top-level commands: -* `c` Create an archive -* `r` Replace entries within an archive -* `u` Update entries within an archive (ie, replace if they're newer) -* `t` List out the contents of an archive -* `x` Extract an archive to disk +- `c` Create an archive +- `r` Replace entries within an archive +- `u` Update entries within an archive (ie, replace if they're newer) +- `t` List out the contents of an archive +- `x` Extract an archive to disk The other flags and options modify how this top level function works. ## High-Level API -These 5 functions are the high-level API. All of them have a +These 5 functions are the high-level API. All of them have a single-character name (for unix nerds familiar with `tar(1)`) as well as a long name (for everyone else). @@ -35,7 +35,7 @@ of which are optional and may be omitted. 1. `options` - An optional object specifying various options 2. `paths` - An array of paths to add or extract -3. `callback` - Called when the command is completed, if async. (If +3. `callback` - Called when the command is completed, if async. (If sync or no file specified, providing a callback throws a `TypeError`.) @@ -43,45 +43,45 @@ If the command is sync (ie, if `options.sync=true`), then the callback is not allowed, since the action will be completed immediately. If a `file` argument is specified, and the command is async, then a -`Promise` is returned. In this case, if async, a callback may be +`Promise` is returned. In this case, if async, a callback may be provided which is called when the command is completed. -If a `file` option is not specified, then a stream is returned. For -`create`, this is a readable stream of the generated archive. For +If a `file` option is not specified, then a stream is returned. For +`create`, this is a readable stream of the generated archive. For `list` and `extract` this is a writable stream that an archive should -be written into. If a file is not specified, then a callback is not +be written into. If a file is not specified, then a callback is not allowed, because you're already getting a stream to work with. `replace` and `update` only work on existing archives, and so require a `file` argument. Sync commands without a file argument return a stream that acts on its -input immediately in the same tick. For readable streams, this means +input immediately in the same tick. For readable streams, this means that all of the data is immediately available by calling -`stream.read()`. For writable streams, it will be acted upon as soon +`stream.read()`. For writable streams, it will be acted upon as soon as it is provided, but this can be at any time. ### Warnings and Errors Tar emits warnings and errors for recoverable and unrecoverable situations, -respectively. In many cases, a warning only affects a single entry in an +respectively. In many cases, a warning only affects a single entry in an archive, or is simply informing you that it's modifying an entry to comply with the settings provided. Unrecoverable warnings will always raise an error (ie, emit `'error'` on streaming actions, throw for non-streaming sync actions, reject the returned Promise for non-streaming async operations, or call a provided -callback with an `Error` as the first argument). Recoverable errors will +callback with an `Error` as the first argument). Recoverable errors will raise an error only if `strict: true` is set in the options. Respond to (recoverable) warnings by listening to the `warn` event. Handlers receive 3 arguments: -- `code` String. One of the error codes below. This may not match +- `code` String. One of the error codes below. This may not match `data.code`, which preserves the original error code from fs and zlib. -- `message` String. More details about the error. -- `data` Metadata about the error. An `Error` object for errors raised by - fs and zlib. All fields are attached to errors raisd by tar. Typically +- `message` String. More details about the error. +- `data` Metadata about the error. An `Error` object for errors raised by + fs and zlib. All fields are attached to errors raisd by tar. Typically contains the following fields, as relevant: - `tarCode` The tar error code. - `code` Either the tar error code, or the error code set by the @@ -92,17 +92,18 @@ Handlers receive 3 arguments: `TAR_ENTRY_INVALID`, and `TAR_ENTRY_ERROR` warnings. - `header` The header object (if it could be created, and the entry could not be created) for `TAR_ENTRY_INFO` and `TAR_ENTRY_INVALID` warnings. - - `recoverable` Boolean. If `false`, then the warning will emit an + - `recoverable` Boolean. If `false`, then the warning will emit an `error`, even in non-strict mode. #### Error Codes -* `TAR_ENTRY_INFO` An informative error indicating that an entry is being - modified, but otherwise processed normally. For example, removing `/` or +- `TAR_ENTRY_INFO` An informative error indicating that an entry is being + modified, but otherwise processed normally. For example, removing `/` or `C:\` from absolute paths if `preservePaths` is not set. -* `TAR_ENTRY_INVALID` An indication that a given entry is not a valid tar - archive entry, and will be skipped. This occurs when: +- `TAR_ENTRY_INVALID` An indication that a given entry is not a valid tar + archive entry, and will be skipped. This occurs when: + - a checksum fails, - a `linkpath` is missing for a link type, or - a `linkpath` is provided for a non-link type. @@ -111,9 +112,10 @@ Handlers receive 3 arguments: then the archive is presumed to be unrecoverably broken, and `TAR_BAD_ARCHIVE` will be raised. -* `TAR_ENTRY_ERROR` The entry appears to be a valid tar archive entry, but - encountered an error which prevented it from being unpacked. This occurs +- `TAR_ENTRY_ERROR` The entry appears to be a valid tar archive entry, but + encountered an error which prevented it from being unpacked. This occurs when: + - an unrecoverable fs error happens during unpacking, - an entry is trying to extract into an excessively deep location (by default, limited to 1024 subfolders), @@ -121,15 +123,15 @@ Handlers receive 3 arguments: - an entry is extracting through a symbolic link, when `preservePaths` is not set. -* `TAR_ENTRY_UNSUPPORTED` An indication that a given entry is +- `TAR_ENTRY_UNSUPPORTED` An indication that a given entry is a valid archive entry, but of a type that is unsupported, and so will be skipped in archive creation or extracting. -* `TAR_ABORT` When parsing gzipped-encoded archives, the parser will +- `TAR_ABORT` When parsing gzipped-encoded archives, the parser will abort the parse process raise a warning for any zlib errors encountered. Aborts are considered unrecoverable for both parsing and unpacking. -* `TAR_BAD_ARCHIVE` The archive file is totally hosed. This can happen for +- `TAR_BAD_ARCHIVE` The archive file is totally hosed. This can happen for a number of reasons, and always occurs at the end of a parse or extract: - An entry body was truncated before seeing the full number of bytes. @@ -138,7 +140,7 @@ Handlers receive 3 arguments: parse. `TAR_BAD_ARCHIVE` is considered informative for parse operations, but - unrecoverable for extraction. Note that, if encountered at the end of an + unrecoverable for extraction. Note that, if encountered at the end of an extraction, tar WILL still have extracted as much it could from the archive, so there may be some garbage files to clean up. @@ -154,7 +156,7 @@ to see how tar is handling the issue. ### Examples The API mimics the `tar(1)` command line functionality, with aliases -for more human-readable option and function names. The goal is that +for more human-readable option and function names. The goal is that if you know how to use `tar(1)` in Unix, then you know how to use `import('tar')` in JavaScript. @@ -202,8 +204,8 @@ To replicate `cat my-tarball.tgz | tar x -C some-dir --strip=1`: fs.createReadStream('my-tarball.tgz').pipe( tar.x({ strip: 1, - C: 'some-dir' // alias for cwd:'some-dir', also ok - }) + C: 'some-dir', // alias for cwd:'some-dir', also ok + }), ) ``` @@ -237,10 +239,10 @@ fs.createReadStream('my-tarball.tgz') .on('entry', entry => { .. do whatever with it .. }) ``` -To do anything synchronous, add `sync: true` to the options. Note +To do anything synchronous, add `sync: true` to the options. Note that sync functions don't take a callback and don't return a promise. -When the function returns, it's already done. Sync methods without a -file argument return a sync stream, which flushes immediately. But, +When the function returns, it's already done. Sync methods without a +file argument return a sync stream, which flushes immediately. But, of course, it still won't be done until you `.end()` it. ```js @@ -258,7 +260,7 @@ const getEntryFilenamesSync = tarballFilename => { To filter entries, add `filter: <function>` to the options. Tar-creating methods call the filter with `filter(path, stat)`. Tar-reading methods (including extraction) call the filter with -`filter(path, entry)`. The filter is called in the `this`-context of +`filter(path, entry)`. The filter is called in the `this`-context of the `Pack` or `Unpack` stream object. The arguments list to `tar t` and `tar x` specify a list of filenames @@ -282,49 +284,49 @@ the low-level API that they are built on. Create a tarball archive. -The `fileList` is an array of paths to add to the tarball. Adding a +The `fileList` is an array of paths to add to the tarball. Adding a directory also adds its children recursively. An entry in `fileList` that starts with an `@` symbol is a tar archive -whose entries will be added. To add a file that starts with `@`, +whose entries will be added. To add a file that starts with `@`, prepend it with `./`. The following options are supported: -- `file` Write the tarball archive to the specified filename. If this +- `file` Write the tarball archive to the specified filename. If this is specified, then the callback will be fired when the file has been written, and a promise will be returned that resolves when the file - is written. If a filename is not specified, then a Readable Stream + is written. If a filename is not specified, then a Readable Stream will be returned which will emit the file data. [Alias: `f`] -- `sync` Act synchronously. If this is set, then any provided file - will be fully written after the call to `tar.c`. If this is set, +- `sync` Act synchronously. If this is set, then any provided file + will be fully written after the call to `tar.c`. If this is set, and a file is not provided, then the resulting stream will already have the data ready to `read` or `emit('data')` as soon as you request it. - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") -- `strict` Treat warnings as crash-worthy errors. Default false. + any warnings encountered. (See "Warnings and Errors") +- `strict` Treat warnings as crash-worthy errors. Default false. - `cwd` The current working directory for creating the archive. - Defaults to `process.cwd()`. [Alias: `C`] + Defaults to `process.cwd()`. [Alias: `C`] - `prefix` A path portion to prefix onto the entries in the archive. - `gzip` Set to any truthy value to create a gzipped archive, or an object with settings for `zlib.Gzip()` [Alias: `z`] - `filter` A function that gets called with `(path, stat)` for each - entry being added. Return `true` to add the entry to the archive, + entry being added. Return `true` to add the entry to the archive, or `false` to omit it. - `portable` Omit metadata that is system-specific: `ctime`, `atime`, - `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note + `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note that `mtime` is still included, because this is necessary for other - time-based operations. Additionally, `mode` is set to a "reasonable + time-based operations. Additionally, `mode` is set to a "reasonable default" for most unix systems, based on a `umask` value of `0o22`. -- `preservePaths` Allow absolute paths. By default, `/` is stripped +- `preservePaths` Allow absolute paths. By default, `/` is stripped from absolute paths. [Alias: `P`] - `mode` The mode to set on the created file archive - `noDirRecurse` Do not recursively archive the contents of directories. [Alias: `n`] -- `follow` Set to true to pack the targets of symbolic links. Without +- `follow` Set to true to pack the targets of symbolic links. Without this option, symbolic links are archived as such. [Alias: `L`, `h`] -- `noPax` Suppress pax extended headers. Note that this means that +- `noPax` Suppress pax extended headers. Note that this means that long paths and linkpaths will be truncated, and large or negative numeric values may be interpreted incorrectly. - `noMtime` Set to true to omit writing `mtime` values for entries. @@ -332,7 +334,7 @@ The following options are supported: `tar.update` or the `keepNewer` option with the resulting tar archive. [Alias: `m`, `no-mtime`] - `mtime` Set to a `Date` object to force a specific `mtime` for - everything added to the archive. Overridden by `noMtime`. + everything added to the archive. Overridden by `noMtime`. The following options are mostly internal, but can be modified in some advanced use cases, such as re-using caches between runs. @@ -350,7 +352,7 @@ advanced use cases, such as re-using caches between runs. Extract a tarball archive. -The `fileList` is an array of paths to extract from the tarball. If +The `fileList` is an array of paths to extract from the tarball. If no paths are provided, then all the entries are extracted. If the archive is gzipped, then tar will detect this and unzip it. @@ -360,77 +362,77 @@ writable, readable, and listable by their owner, to avoid cases where a directory prevents extraction of child entries by virtue of its mode. -Most extraction errors will cause a `warn` event to be emitted. If +Most extraction errors will cause a `warn` event to be emitted. If the `cwd` is missing, or not a directory, then the extraction will fail completely. The following options are supported: -- `cwd` Extract files relative to the specified directory. Defaults - to `process.cwd()`. If provided, this must exist and must be a +- `cwd` Extract files relative to the specified directory. Defaults + to `process.cwd()`. If provided, this must exist and must be a directory. [Alias: `C`] -- `file` The archive file to extract. If not specified, then a +- `file` The archive file to extract. If not specified, then a Writable stream is returned where the archive data should be written. [Alias: `f`] - `sync` Create files and directories synchronously. -- `strict` Treat warnings as crash-worthy errors. Default false. +- `strict` Treat warnings as crash-worthy errors. Default false. - `filter` A function that gets called with `(path, entry)` for each - entry being unpacked. Return `true` to unpack the entry from the + entry being unpacked. Return `true` to unpack the entry from the archive, or `false` to skip it. - `newer` Set to true to keep the existing file on disk if it's newer than the file in the archive. [Alias: `keep-newer`, `keep-newer-files`] -- `keep` Do not overwrite existing files. In particular, if a file +- `keep` Do not overwrite existing files. In particular, if a file appears more than once in an archive, later copies will not overwrite earlier copies. [Alias: `k`, `keep-existing`] - `preservePaths` Allow absolute paths, paths containing `..`, and - extracting through symbolic links. By default, `/` is stripped from + extracting through symbolic links. By default, `/` is stripped from absolute paths, `..` paths are not extracted, and any file whose location would be modified by a symbolic link is not extracted. [Alias: `P`] -- `unlink` Unlink files before creating them. Without this option, +- `unlink` Unlink files before creating them. Without this option, tar overwrites existing files, which preserves existing hardlinks. With this option, existing hardlinks will be broken, as will any symlink that would affect the location of an extracted file. [Alias: `U`] - `strip` Remove the specified number of leading path elements. - Pathnames with fewer elements will be silently skipped. Note that + Pathnames with fewer elements will be silently skipped. Note that the pathname is edited after applying the filter, but before security checks. [Alias: `strip-components`, `stripComponents`] - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") + any warnings encountered. (See "Warnings and Errors") - `preserveOwner` If true, tar will set the `uid` and `gid` of extracted entries to the `uid` and `gid` fields in the archive. - This defaults to true when run as root, and false otherwise. If + This defaults to true when run as root, and false otherwise. If false, then files and directories will be set with the owner and - group of the user running the process. This is similar to `-p` in + group of the user running the process. This is similar to `-p` in `tar(1)`, but ACLs and other system-specific data is never unpacked in this implementation, and modes are set by default already. [Alias: `p`] - `uid` Set to a number to force ownership of all extracted files and folders, and all implicitly created directories, to be owned by the specified user id, regardless of the `uid` field in the archive. - Cannot be used along with `preserveOwner`. Requires also setting a + Cannot be used along with `preserveOwner`. Requires also setting a `gid` option. - `gid` Set to a number to force ownership of all extracted files and folders, and all implicitly created directories, to be owned by the specified group id, regardless of the `gid` field in the archive. - Cannot be used along with `preserveOwner`. Requires also setting a + Cannot be used along with `preserveOwner`. Requires also setting a `uid` option. - `noMtime` Set to true to omit writing `mtime` value for extracted entries. [Alias: `m`, `no-mtime`] - `transform` Provide a function that takes an `entry` object, and - returns a stream, or any falsey value. If a stream is provided, + returns a stream, or any falsey value. If a stream is provided, then that stream's data will be written instead of the contents of - the archive entry. If a falsey value is provided, then the entry is - written to disk as normal. (To exclude items from extraction, use + the archive entry. If a falsey value is provided, then the entry is + written to disk as normal. (To exclude items from extraction, use the `filter` option described above.) - `onentry` A function that gets called with `(entry)` for each entry that passes the filter. - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") + any warnings encountered. (See "Warnings and Errors") - `chmod` Set to true to call `fs.chmod()` to ensure that the - extracted file matches the entry mode. This may necessitate a + extracted file matches the entry mode. This may necessitate a call to the deprecated and thread-unsafe `process.umask()` method to determine the default umask value, unless a `processUmask` options is also provided. Otherwise tar will @@ -453,7 +455,7 @@ advanced use cases, such as re-using caches between runs. - `fmode` Default mode for files - `dirCache` A Map object of which directories exist. - `maxMetaEntrySize` The maximum size of meta entries that is - supported. Defaults to 1 MB. + supported. Defaults to 1 MB. Note that using an asynchronous stream type with the `transform` option will cause undefined behavior in sync extractions. @@ -464,88 +466,88 @@ use case. List the contents of a tarball archive. -The `fileList` is an array of paths to list from the tarball. If +The `fileList` is an array of paths to list from the tarball. If no paths are provided, then all the entries are listed. If the archive is gzipped, then tar will detect this and unzip it. If the `file` option is _not_ provided, then returns an event emitter that -emits `entry` events with `tar.ReadEntry` objects. However, they don't -emit `'data'` or `'end'` events. (If you want to get actual readable +emits `entry` events with `tar.ReadEntry` objects. However, they don't +emit `'data'` or `'end'` events. (If you want to get actual readable entries, use the `tar.Parse` class instead.) If a `file` option _is_ provided, then the return value will be a promise that resolves when the file has been fully traversed in async mode, or -`undefined` if `sync: true` is set. Thus, you _must_ specify an `onentry` +`undefined` if `sync: true` is set. Thus, you _must_ specify an `onentry` method in order to do anything useful with the data it parses. The following options are supported: -- `file` The archive file to list. If not specified, then a +- `file` The archive file to list. If not specified, then a Writable stream is returned where the archive data should be written. [Alias: `f`] -- `sync` Read the specified file synchronously. (This has no effect +- `sync` Read the specified file synchronously. (This has no effect when a file option isn't specified, because entries are emitted as fast as they are parsed from the stream anyway.) -- `strict` Treat warnings as crash-worthy errors. Default false. +- `strict` Treat warnings as crash-worthy errors. Default false. - `filter` A function that gets called with `(path, entry)` for each - entry being listed. Return `true` to emit the entry from the + entry being listed. Return `true` to emit the entry from the archive, or `false` to skip it. - `onentry` A function that gets called with `(entry)` for each entry - that passes the filter. This is important for when `file` is set, + that passes the filter. This is important for when `file` is set, because there is no other way to do anything useful with this method. - `maxReadSize` The maximum buffer size for `fs.read()` operations. Defaults to 16 MB. - `noResume` By default, `entry` streams are resumed immediately after - the call to `onentry`. Set `noResume: true` to suppress this - behavior. Note that by opting into this, the stream will never + the call to `onentry`. Set `noResume: true` to suppress this + behavior. Note that by opting into this, the stream will never complete until the entry data is consumed. - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") + any warnings encountered. (See "Warnings and Errors") ### tar.u(options, fileList, callback) [alias: tar.update] Add files to an archive if they are newer than the entry already in the tarball archive. -The `fileList` is an array of paths to add to the tarball. Adding a +The `fileList` is an array of paths to add to the tarball. Adding a directory also adds its children recursively. An entry in `fileList` that starts with an `@` symbol is a tar archive -whose entries will be added. To add a file that starts with `@`, +whose entries will be added. To add a file that starts with `@`, prepend it with `./`. The following options are supported: - `file` Required. Write the tarball archive to the specified filename. [Alias: `f`] -- `sync` Act synchronously. If this is set, then any provided file +- `sync` Act synchronously. If this is set, then any provided file will be fully written after the call to `tar.c`. - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") -- `strict` Treat warnings as crash-worthy errors. Default false. + any warnings encountered. (See "Warnings and Errors") +- `strict` Treat warnings as crash-worthy errors. Default false. - `cwd` The current working directory for adding entries to the - archive. Defaults to `process.cwd()`. [Alias: `C`] + archive. Defaults to `process.cwd()`. [Alias: `C`] - `prefix` A path portion to prefix onto the entries in the archive. - `gzip` Set to any truthy value to create a gzipped archive, or an object with settings for `zlib.Gzip()` [Alias: `z`] - `filter` A function that gets called with `(path, stat)` for each - entry being added. Return `true` to add the entry to the archive, + entry being added. Return `true` to add the entry to the archive, or `false` to omit it. - `portable` Omit metadata that is system-specific: `ctime`, `atime`, - `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note + `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note that `mtime` is still included, because this is necessary for other - time-based operations. Additionally, `mode` is set to a "reasonable + time-based operations. Additionally, `mode` is set to a "reasonable default" for most unix systems, based on a `umask` value of `0o22`. -- `preservePaths` Allow absolute paths. By default, `/` is stripped +- `preservePaths` Allow absolute paths. By default, `/` is stripped from absolute paths. [Alias: `P`] - `maxReadSize` The maximum buffer size for `fs.read()` operations. Defaults to 16 MB. - `noDirRecurse` Do not recursively archive the contents of directories. [Alias: `n`] -- `follow` Set to true to pack the targets of symbolic links. Without +- `follow` Set to true to pack the targets of symbolic links. Without this option, symbolic links are archived as such. [Alias: `L`, `h`] -- `noPax` Suppress pax extended headers. Note that this means that +- `noPax` Suppress pax extended headers. Note that this means that long paths and linkpaths will be truncated, and large or negative numeric values may be interpreted incorrectly. - `noMtime` Set to true to omit writing `mtime` values for entries. @@ -553,51 +555,51 @@ The following options are supported: `tar.update` or the `keepNewer` option with the resulting tar archive. [Alias: `m`, `no-mtime`] - `mtime` Set to a `Date` object to force a specific `mtime` for - everything added to the archive. Overridden by `noMtime`. + everything added to the archive. Overridden by `noMtime`. ### tar.r(options, fileList, callback) [alias: tar.replace] -Add files to an existing archive. Because later entries override +Add files to an existing archive. Because later entries override earlier entries, this effectively replaces any existing entries. -The `fileList` is an array of paths to add to the tarball. Adding a +The `fileList` is an array of paths to add to the tarball. Adding a directory also adds its children recursively. An entry in `fileList` that starts with an `@` symbol is a tar archive -whose entries will be added. To add a file that starts with `@`, +whose entries will be added. To add a file that starts with `@`, prepend it with `./`. The following options are supported: - `file` Required. Write the tarball archive to the specified filename. [Alias: `f`] -- `sync` Act synchronously. If this is set, then any provided file +- `sync` Act synchronously. If this is set, then any provided file will be fully written after the call to `tar.c`. - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") -- `strict` Treat warnings as crash-worthy errors. Default false. + any warnings encountered. (See "Warnings and Errors") +- `strict` Treat warnings as crash-worthy errors. Default false. - `cwd` The current working directory for adding entries to the - archive. Defaults to `process.cwd()`. [Alias: `C`] + archive. Defaults to `process.cwd()`. [Alias: `C`] - `prefix` A path portion to prefix onto the entries in the archive. - `gzip` Set to any truthy value to create a gzipped archive, or an object with settings for `zlib.Gzip()` [Alias: `z`] - `filter` A function that gets called with `(path, stat)` for each - entry being added. Return `true` to add the entry to the archive, + entry being added. Return `true` to add the entry to the archive, or `false` to omit it. - `portable` Omit metadata that is system-specific: `ctime`, `atime`, - `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note + `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note that `mtime` is still included, because this is necessary for other - time-based operations. Additionally, `mode` is set to a "reasonable + time-based operations. Additionally, `mode` is set to a "reasonable default" for most unix systems, based on a `umask` value of `0o22`. -- `preservePaths` Allow absolute paths. By default, `/` is stripped +- `preservePaths` Allow absolute paths. By default, `/` is stripped from absolute paths. [Alias: `P`] - `maxReadSize` The maximum buffer size for `fs.read()` operations. Defaults to 16 MB. - `noDirRecurse` Do not recursively archive the contents of directories. [Alias: `n`] -- `follow` Set to true to pack the targets of symbolic links. Without +- `follow` Set to true to pack the targets of symbolic links. Without this option, symbolic links are archived as such. [Alias: `L`, `h`] -- `noPax` Suppress pax extended headers. Note that this means that +- `noPax` Suppress pax extended headers. Note that this means that long paths and linkpaths will be truncated, and large or negative numeric values may be interpreted incorrectly. - `noMtime` Set to true to omit writing `mtime` values for entries. @@ -605,8 +607,7 @@ The following options are supported: `tar.update` or the `keepNewer` option with the resulting tar archive. [Alias: `m`, `no-mtime`] - `mtime` Set to a `Date` object to force a specific `mtime` for - everything added to the archive. Overridden by `noMtime`. - + everything added to the archive. Overridden by `noMtime`. ## Low-Level API @@ -614,7 +615,7 @@ The following options are supported: A readable tar stream. -Has all the standard readable stream interface stuff. `'data'` and +Has all the standard readable stream interface stuff. `'data'` and `'end'` events, `read()` method, `pause()` and `resume()`, etc. #### constructor(options) @@ -622,22 +623,22 @@ Has all the standard readable stream interface stuff. `'data'` and The following options are supported: - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") -- `strict` Treat warnings as crash-worthy errors. Default false. + any warnings encountered. (See "Warnings and Errors") +- `strict` Treat warnings as crash-worthy errors. Default false. - `cwd` The current working directory for creating the archive. Defaults to `process.cwd()`. - `prefix` A path portion to prefix onto the entries in the archive. - `gzip` Set to any truthy value to create a gzipped archive, or an object with settings for `zlib.Gzip()` - `filter` A function that gets called with `(path, stat)` for each - entry being added. Return `true` to add the entry to the archive, + entry being added. Return `true` to add the entry to the archive, or `false` to omit it. - `portable` Omit metadata that is system-specific: `ctime`, `atime`, - `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note + `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note that `mtime` is still included, because this is necessary for other - time-based operations. Additionally, `mode` is set to a "reasonable + time-based operations. Additionally, `mode` is set to a "reasonable default" for most unix systems, based on a `umask` value of `0o22`. -- `preservePaths` Allow absolute paths. By default, `/` is stripped +- `preservePaths` Allow absolute paths. By default, `/` is stripped from absolute paths. - `linkCache` A Map object containing the device and inode value for @@ -650,24 +651,24 @@ The following options are supported: Defaults to 16 MB. - `noDirRecurse` Do not recursively archive the contents of directories. -- `follow` Set to true to pack the targets of symbolic links. Without +- `follow` Set to true to pack the targets of symbolic links. Without this option, symbolic links are archived as such. -- `noPax` Suppress pax extended headers. Note that this means that +- `noPax` Suppress pax extended headers. Note that this means that long paths and linkpaths will be truncated, and large or negative numeric values may be interpreted incorrectly. - `noMtime` Set to true to omit writing `mtime` values for entries. Note that this prevents using other mtime-based features like `tar.update` or the `keepNewer` option with the resulting tar archive. - `mtime` Set to a `Date` object to force a specific `mtime` for - everything added to the archive. Overridden by `noMtime`. + everything added to the archive. Overridden by `noMtime`. #### add(path) -Adds an entry to the archive. Returns the Pack stream. +Adds an entry to the archive. Returns the Pack stream. #### write(path) -Adds an entry to the archive. Returns true if flushed. +Adds an entry to the archive. Returns true if flushed. #### end() @@ -681,7 +682,7 @@ Synchronous version of `tar.Pack`. A writable stream that unpacks a tar archive onto the file system. -All the normal writable stream stuff is supported. `write()` and +All the normal writable stream stuff is supported. `write()` and `end()` methods, `'drain'` events, etc. Note that all directories that are created will be forced to be @@ -691,77 +692,77 @@ mode. `'close'` is emitted when it's done writing stuff to the file system. -Most unpack errors will cause a `warn` event to be emitted. If the +Most unpack errors will cause a `warn` event to be emitted. If the `cwd` is missing, or not a directory, then an error will be emitted. #### constructor(options) -- `cwd` Extract files relative to the specified directory. Defaults - to `process.cwd()`. If provided, this must exist and must be a +- `cwd` Extract files relative to the specified directory. Defaults + to `process.cwd()`. If provided, this must exist and must be a directory. - `filter` A function that gets called with `(path, entry)` for each - entry being unpacked. Return `true` to unpack the entry from the + entry being unpacked. Return `true` to unpack the entry from the archive, or `false` to skip it. - `newer` Set to true to keep the existing file on disk if it's newer than the file in the archive. -- `keep` Do not overwrite existing files. In particular, if a file +- `keep` Do not overwrite existing files. In particular, if a file appears more than once in an archive, later copies will not overwrite earlier copies. - `preservePaths` Allow absolute paths, paths containing `..`, and - extracting through symbolic links. By default, `/` is stripped from + extracting through symbolic links. By default, `/` is stripped from absolute paths, `..` paths are not extracted, and any file whose location would be modified by a symbolic link is not extracted. -- `unlink` Unlink files before creating them. Without this option, +- `unlink` Unlink files before creating them. Without this option, tar overwrites existing files, which preserves existing hardlinks. With this option, existing hardlinks will be broken, as will any symlink that would affect the location of an extracted file. - `strip` Remove the specified number of leading path elements. - Pathnames with fewer elements will be silently skipped. Note that + Pathnames with fewer elements will be silently skipped. Note that the pathname is edited after applying the filter, but before security checks. - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") + any warnings encountered. (See "Warnings and Errors") - `umask` Filter the modes of entries like `process.umask()`. - `dmode` Default mode for directories - `fmode` Default mode for files - `dirCache` A Map object of which directories exist. - `maxMetaEntrySize` The maximum size of meta entries that is - supported. Defaults to 1 MB. + supported. Defaults to 1 MB. - `preserveOwner` If true, tar will set the `uid` and `gid` of extracted entries to the `uid` and `gid` fields in the archive. - This defaults to true when run as root, and false otherwise. If + This defaults to true when run as root, and false otherwise. If false, then files and directories will be set with the owner and - group of the user running the process. This is similar to `-p` in + group of the user running the process. This is similar to `-p` in `tar(1)`, but ACLs and other system-specific data is never unpacked in this implementation, and modes are set by default already. -- `win32` True if on a windows platform. Causes behavior where +- `win32` True if on a windows platform. Causes behavior where filenames containing `<|>?` chars are converted to windows-compatible values while being unpacked. - `uid` Set to a number to force ownership of all extracted files and folders, and all implicitly created directories, to be owned by the specified user id, regardless of the `uid` field in the archive. - Cannot be used along with `preserveOwner`. Requires also setting a + Cannot be used along with `preserveOwner`. Requires also setting a `gid` option. - `gid` Set to a number to force ownership of all extracted files and folders, and all implicitly created directories, to be owned by the specified group id, regardless of the `gid` field in the archive. - Cannot be used along with `preserveOwner`. Requires also setting a + Cannot be used along with `preserveOwner`. Requires also setting a `uid` option. - `noMtime` Set to true to omit writing `mtime` value for extracted entries. - `transform` Provide a function that takes an `entry` object, and - returns a stream, or any falsey value. If a stream is provided, + returns a stream, or any falsey value. If a stream is provided, then that stream's data will be written instead of the contents of - the archive entry. If a falsey value is provided, then the entry is - written to disk as normal. (To exclude items from extraction, use + the archive entry. If a falsey value is provided, then the entry is + written to disk as normal. (To exclude items from extraction, use the `filter` option described above.) -- `strict` Treat warnings as crash-worthy errors. Default false. +- `strict` Treat warnings as crash-worthy errors. Default false. - `onentry` A function that gets called with `(entry)` for each entry that passes the filter. - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") + any warnings encountered. (See "Warnings and Errors") - `chmod` Set to true to call `fs.chmod()` to ensure that the - extracted file matches the entry mode. This may necessitate a + extracted file matches the entry mode. This may necessitate a call to the deprecated and thread-unsafe `process.umask()` method to determine the default umask value, unless a `processUmask` options is also provided. Otherwise tar will @@ -785,7 +786,7 @@ use case. ### class tar.Parse -A writable stream that parses a tar archive stream. All the standard +A writable stream that parses a tar archive stream. All the standard writable stream stuff is supported. If the archive is gzipped, then tar will detect this and unzip it. @@ -805,19 +806,19 @@ Returns an event emitter that emits `entry` events with The following options are supported: -- `strict` Treat warnings as crash-worthy errors. Default false. +- `strict` Treat warnings as crash-worthy errors. Default false. - `filter` A function that gets called with `(path, entry)` for each - entry being listed. Return `true` to emit the entry from the + entry being listed. Return `true` to emit the entry from the archive, or `false` to skip it. - `onentry` A function that gets called with `(entry)` for each entry that passes the filter. - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") + any warnings encountered. (See "Warnings and Errors") #### abort(error) -Stop all parsing activities. This is called when there are zlib -errors. It also emits an unrecoverable warning with the error provided. +Stop all parsing activities. This is called when there are zlib +errors. It also emits an unrecoverable warning with the error provided. ### class tar.ReadEntry extends [MiniPass](http://npm.im/minipass) @@ -836,7 +837,7 @@ It has the following fields: - `meta` True if this represents metadata about the next entry, false if it represents a filesystem object. - All the fields from the header, extended header, and global extended - header are added to the ReadEntry object. So it has `path`, `type`, + header are added to the ReadEntry object. So it has `path`, `type`, `size`, `mode`, and so on. #### constructor(header, extended, globalExtended) @@ -857,43 +858,42 @@ WriteEntry objects for all of the directory contents. It has the following fields: -- `path` The path field that will be written to the archive. By +- `path` The path field that will be written to the archive. By default, this is also the path from the cwd to the file system object. - `portable` Omit metadata that is system-specific: `ctime`, `atime`, - `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note + `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note that `mtime` is still included, because this is necessary for other - time-based operations. Additionally, `mode` is set to a "reasonable + time-based operations. Additionally, `mode` is set to a "reasonable default" for most unix systems, based on a `umask` value of `0o22`. - `myuid` If supported, the uid of the user running the current process. -- `myuser` The `env.USER` string if set, or `''`. Set as the entry +- `myuser` The `env.USER` string if set, or `''`. Set as the entry `uname` field if the file's `uid` matches `this.myuid`. - `maxReadSize` The maximum buffer size for `fs.read()` operations. Defaults to 1 MB. - `linkCache` A Map object containing the device and inode value for any file whose nlink is > 1, to identify hard links. - `statCache` A Map object that caches calls `lstat`. -- `preservePaths` Allow absolute paths. By default, `/` is stripped +- `preservePaths` Allow absolute paths. By default, `/` is stripped from absolute paths. - `cwd` The current working directory for creating the archive. Defaults to `process.cwd()`. -- `absolute` The absolute path to the entry on the filesystem. By +- `absolute` The absolute path to the entry on the filesystem. By default, this is `path.resolve(this.cwd, this.path)`, but it can be overridden explicitly. -- `strict` Treat warnings as crash-worthy errors. Default false. -- `win32` True if on a windows platform. Causes behavior where paths +- `strict` Treat warnings as crash-worthy errors. Default false. +- `win32` True if on a windows platform. Causes behavior where paths replace `\` with `/` and filenames containing the windows-compatible forms of `<|>?:` characters are converted to actual `<|>?:` characters in the archive. -- `noPax` Suppress pax extended headers. Note that this means that +- `noPax` Suppress pax extended headers. Note that this means that long paths and linkpaths will be truncated, and large or negative numeric values may be interpreted incorrectly. - `noMtime` Set to true to omit writing `mtime` values for entries. Note that this prevents using other mtime-based features like `tar.update` or the `keepNewer` option with the resulting tar archive. - #### constructor(path, options) `path` is the path of the entry as it is written in the archive. @@ -901,32 +901,32 @@ It has the following fields: The following options are supported: - `portable` Omit metadata that is system-specific: `ctime`, `atime`, - `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note + `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note that `mtime` is still included, because this is necessary for other - time-based operations. Additionally, `mode` is set to a "reasonable + time-based operations. Additionally, `mode` is set to a "reasonable default" for most unix systems, based on a `umask` value of `0o22`. - `maxReadSize` The maximum buffer size for `fs.read()` operations. Defaults to 1 MB. - `linkCache` A Map object containing the device and inode value for any file whose nlink is > 1, to identify hard links. - `statCache` A Map object that caches calls `lstat`. -- `preservePaths` Allow absolute paths. By default, `/` is stripped +- `preservePaths` Allow absolute paths. By default, `/` is stripped from absolute paths. - `cwd` The current working directory for creating the archive. Defaults to `process.cwd()`. -- `absolute` The absolute path to the entry on the filesystem. By +- `absolute` The absolute path to the entry on the filesystem. By default, this is `path.resolve(this.cwd, this.path)`, but it can be overridden explicitly. -- `strict` Treat warnings as crash-worthy errors. Default false. -- `win32` True if on a windows platform. Causes behavior where paths +- `strict` Treat warnings as crash-worthy errors. Default false. +- `win32` True if on a windows platform. Causes behavior where paths replace `\` with `/`. - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") + any warnings encountered. (See "Warnings and Errors") - `noMtime` Set to true to omit writing `mtime` values for entries. Note that this prevents using other mtime-based features like `tar.update` or the `keepNewer` option with the resulting tar archive. - `umask` Set to restrict the modes on the entries in the archive, - somewhat like how umask works on file creation. Defaults to + somewhat like how umask works on file creation. Defaults to `process.umask()` on unix systems, or `0o22` on Windows. #### warn(message, data) @@ -951,15 +951,15 @@ instead of from the filesystem. The following options are supported: - `portable` Omit metadata that is system-specific: `ctime`, `atime`, - `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note + `uid`, `gid`, `uname`, `gname`, `dev`, `ino`, and `nlink`. Note that `mtime` is still included, because this is necessary for other - time-based operations. Additionally, `mode` is set to a "reasonable + time-based operations. Additionally, `mode` is set to a "reasonable default" for most unix systems, based on a `umask` value of `0o22`. -- `preservePaths` Allow absolute paths. By default, `/` is stripped +- `preservePaths` Allow absolute paths. By default, `/` is stripped from absolute paths. -- `strict` Treat warnings as crash-worthy errors. Default false. +- `strict` Treat warnings as crash-worthy errors. Default false. - `onwarn` A function that will get called with `(code, message, data)` for - any warnings encountered. (See "Warnings and Errors") + any warnings encountered. (See "Warnings and Errors") - `noMtime` Set to true to omit writing `mtime` values for entries. Note that this prevents using other mtime-based features like `tar.update` or the `keepNewer` option with the resulting tar archive. @@ -971,21 +971,21 @@ A class for reading and writing header blocks. It has the following fields: - `nullBlock` True if decoding a block which is entirely composed of - `0x00` null bytes. (Useful because tar files are terminated by + `0x00` null bytes. (Useful because tar files are terminated by at least 2 null blocks.) - `cksumValid` True if the checksum in the header is valid, false otherwise. - `needPax` True if the values, as encoded, will require a Pax extended header. - `path` The path of the entry. -- `mode` The 4 lowest-order octal digits of the file mode. That is, +- `mode` The 4 lowest-order octal digits of the file mode. That is, read/write/execute permissions for world, group, and owner, and the setuid, setgid, and sticky bits. - `uid` Numeric user id of the file owner - `gid` Numeric group id of the file owner - `size` Size of the file in bytes - `mtime` Modified time of the file -- `cksum` The checksum of the header. This is generated by adding all +- `cksum` The checksum of the header. This is generated by adding all the bytes of the header block, treating the checksum field itself as all ascii space characters (that is, `0x20`). - `type` The human-readable name of the type of entry this represents, @@ -995,16 +995,16 @@ It has the following fields: - `linkpath` The target of Link and SymbolicLink entries. - `uname` Human-readable user name of the file owner - `gname` Human-readable group name of the file owner -- `devmaj` The major portion of the device number. Always `0` for +- `devmaj` The major portion of the device number. Always `0` for files, directories, and links. -- `devmin` The minor portion of the device number. Always `0` for +- `devmin` The minor portion of the device number. Always `0` for files, directories, and links. - `atime` File access time. - `ctime` File change time. #### constructor(data, [offset=0]) -`data` is optional. It is either a Buffer that should be interpreted +`data` is optional. It is either a Buffer that should be interpreted as a tar Header starting at the specified offset and continuing for 512 bytes, or a data object of keys and values to set on the header object, and eventually encode as a tar Header. @@ -1031,7 +1031,7 @@ required to properly encode the specified data. An object representing a set of key-value pairs in an Pax extended header entry. -It has the following fields. Where the same name is used, they have +It has the following fields. Where the same name is used, they have the same semantics as the tar.Header field of the same name. - `global` True if this represents a global extended header, or false @@ -1054,7 +1054,7 @@ the same semantics as the tar.Header field of the same name. #### constructor(object, global) -Set the fields set in the object. `global` is a boolean that defaults +Set the fields set in the object. `global` is a boolean that defaults to false. #### encode() @@ -1078,7 +1078,7 @@ Return a new Pax object created by parsing the contents of the string provided. If the `extended` object is set, then also add the fields from that -object. (This is necessary because multiple metadata entries can +object. (This is necessary because multiple metadata entries can occur in sequence.) ### tar.types diff --git a/map.js b/map.js index e7ef1050..b5f52c9b 100644 --- a/map.js +++ b/map.js @@ -1,12 +1,9 @@ import { basename } from 'path' const map = test => - test === 'map.js' - ? test - : test === 'unpack.js' - ? ['src/unpack.ts', 'src/mkdir.ts'] - : test === 'load-all.js' - ? [] - : `src/${test.replace(/js$/, 'ts')}` + test === 'map.js' ? test + : test === 'unpack.js' ? ['src/unpack.ts', 'src/mkdir.ts'] + : test === 'load-all.js' ? [] + : `src/${test.replace(/js$/, 'ts')}` export default test => map(basename(test)) diff --git a/package.json b/package.json index 44fa84ac..f1321305 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "preversion": "npm test", "postversion": "npm publish", "prepublishOnly": "git push origin --follow-tags", - "format": "prettier --write . --loglevel warn", + "format": "prettier --write . --log-level warn", "typedoc": "typedoc --tsconfig .tshy/esm.json ./src/*.ts" }, "dependencies": { @@ -52,6 +52,7 @@ "timeout": 0 }, "prettier": { + "experimentalTernaries": true, "semi": false, "printWidth": 70, "tabWidth": 2, diff --git a/scripts/generate-parse-fixtures.js b/scripts/generate-parse-fixtures.js index ff7d864f..b81f5265 100644 --- a/scripts/generate-parse-fixtures.js +++ b/scripts/generate-parse-fixtures.js @@ -1,7 +1,7 @@ import { Parser } from '../dist/esm/parse.js' import fs from 'fs' -import path, {dirname, resolve} from 'path' -import {fileURLToPath} from 'url' +import path, { dirname, resolve } from 'path' +import { fileURLToPath } from 'url' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) @@ -17,7 +17,8 @@ const makeTest = (tarfile, tardata, maxMeta, filter, strict) => { (filter ? '-filter' : '') + (strict ? '-strict' : '') const tail = (o ? '-' + o : '') + '.json' - const eventsfile = parsedir + '/' + path.basename(tarfile, '.tar') + tail + const eventsfile = + parsedir + '/' + path.basename(tarfile, '.tar') + tail const p = new Parser({ maxMetaEntrySize: maxMeta, @@ -27,57 +28,67 @@ const makeTest = (tarfile, tardata, maxMeta, filter, strict) => { const events = [] const pushEntry = type => entry => { - events.push([type, { - extended: entry.extended, - globalExtended: entry.globalExtended, - type: entry.type, - meta: entry.meta, - ignore: entry.ignore, - path: entry.path, - mode: entry.mode, - uid: entry.uid, - gid: entry.gid, - uname: entry.uname, - gname: entry.gname, - size: entry.size, - mtime: entry.mtime, - atime: entry.atime, - ctime: entry.ctime, - linkpath: entry.linkpath, - header: { - cksumValid: entry.header.cksumValid, - needPax: entry.header.needPax, - path: entry.header.path, - mode: entry.header.mode, - uid: entry.header.uid, - gid: entry.header.gid, - size: entry.header.size, - mtime: entry.header.mtime, - cksum: entry.header.cksum, - linkpath: entry.header.linkpath, - ustar: entry.header.ustar, - ustarver: entry.header.ustarver, - uname: entry.header.uname, - gname: entry.header.gname, - devmaj: entry.header.devmaj, - devmin: entry.header.devmin, - ustarPrefix: entry.header.ustarPrefix, - xstarPrefix: entry.header.xstarPrefix, - prefixTerminator: entry.header.prefixTerminator, - atime: entry.header.atime, - ctime: entry.header.atime, + events.push([ + type, + { + extended: entry.extended, + globalExtended: entry.globalExtended, + type: entry.type, + meta: entry.meta, + ignore: entry.ignore, + path: entry.path, + mode: entry.mode, + uid: entry.uid, + gid: entry.gid, + uname: entry.uname, + gname: entry.gname, + size: entry.size, + mtime: entry.mtime, + atime: entry.atime, + ctime: entry.ctime, + linkpath: entry.linkpath, + header: { + cksumValid: entry.header.cksumValid, + needPax: entry.header.needPax, + path: entry.header.path, + mode: entry.header.mode, + uid: entry.header.uid, + gid: entry.header.gid, + size: entry.header.size, + mtime: entry.header.mtime, + cksum: entry.header.cksum, + linkpath: entry.header.linkpath, + ustar: entry.header.ustar, + ustarver: entry.header.ustarver, + uname: entry.header.uname, + gname: entry.header.gname, + devmaj: entry.header.devmaj, + devmin: entry.header.devmin, + ustarPrefix: entry.header.ustarPrefix, + xstarPrefix: entry.header.xstarPrefix, + prefixTerminator: entry.header.prefixTerminator, + atime: entry.header.atime, + ctime: entry.header.atime, + }, }, - }]) + ]) entry.resume() } p.on('entry', pushEntry('entry')) p.on('ignoredEntry', pushEntry('ignoredEntry')) - p.on('warn', (code, message, _data) => events.push(['warn', code, message])) - p.on('error', er => events.push(['error', { - message: er.message, - code: er.code, - }])) + p.on('warn', (code, message, _data) => + events.push(['warn', code, message]), + ) + p.on('error', er => + events.push([ + 'error', + { + message: er.message, + code: er.code, + }, + ]), + ) p.on('end', _ => events.push(['end'])) p.on('nullBlock', _ => events.push(['nullBlock'])) p.on('eof', _ => events.push(['eof'])) @@ -88,12 +99,14 @@ const makeTest = (tarfile, tardata, maxMeta, filter, strict) => { fs.writeFileSync(eventsfile, JSON.stringify(events, null, 2) + '\n') } -fs.readdirSync(tardir) - .forEach(tar => { - const tarfile = tardir + '/' + tar - const tardata = fs.readFileSync(tarfile) - maxMetaOpt.forEach(maxMeta => - filterOpt.forEach(filter => - strictOpt.forEach(strict => - makeTest(tarfile, tardata, maxMeta, filter, strict)))) - }) +fs.readdirSync(tardir).forEach(tar => { + const tarfile = tardir + '/' + tar + const tardata = fs.readFileSync(tarfile) + maxMetaOpt.forEach(maxMeta => + filterOpt.forEach(filter => + strictOpt.forEach(strict => + makeTest(tarfile, tardata, maxMeta, filter, strict), + ), + ), + ) +}) diff --git a/src/create.ts b/src/create.ts index 85b27c38..33af4b31 100644 --- a/src/create.ts +++ b/src/create.ts @@ -71,13 +71,12 @@ export function create( throw new TypeError('callback only supported with file option') } - return isSyncFile(opt) - ? createFileSync(opt, files) - : isFile(opt) - ? createFile(opt, files, cb) - : isSync(opt) - ? createSync(opt, files) - : create_(opt, files) + return ( + isSyncFile(opt) ? createFileSync(opt, files) + : isFile(opt) ? createFile(opt, files, cb) + : isSync(opt) ? createSync(opt, files) + : create_(opt, files) + ) } const createFileSync = (opt: TarOptionsSyncFile, files: string[]) => { diff --git a/src/extract.ts b/src/extract.ts index b3cb3b0b..35dc4946 100644 --- a/src/extract.ts +++ b/src/extract.ts @@ -77,13 +77,12 @@ export function extract( filesFilter(opt, files) } - return isSyncFile(opt) - ? extractFileSync(opt) - : isFile(opt) - ? extractFile(opt, cb) - : isSync(opt) - ? extractSync(opt) - : extract_(opt) + return ( + isSyncFile(opt) ? extractFileSync(opt) + : isFile(opt) ? extractFile(opt, cb) + : isSync(opt) ? extractSync(opt) + : extract_(opt) + ) } // construct a filter that limits the file entries listed @@ -109,8 +108,9 @@ const filesFilter = (opt: TarOptions, files: string[]) => { return ret } - opt.filter = filter - ? (file, entry) => + opt.filter = + filter ? + (file, entry) => filter(file, entry) && mapHas(stripTrailingSlashes(file)) : file => mapHas(stripTrailingSlashes(file)) } @@ -130,10 +130,7 @@ const extractFileSync = (opt: TarOptionsSyncFile) => { stream.pipe(u) } -const extractFile = ( - opt: TarOptionsFile, - cb?: () => void, -) => { +const extractFile = (opt: TarOptionsFile, cb?: () => void) => { const u = new Unpack(opt) const readSize = opt.maxReadSize || 16 * 1024 * 1024 diff --git a/src/get-write-flag.ts b/src/get-write-flag.ts index bd8842dc..aa3fd883 100644 --- a/src/get-write-flag.ts +++ b/src/get-write-flag.ts @@ -22,6 +22,7 @@ const UV_FS_O_FILEMAP = const fMapEnabled = isWindows && !!UV_FS_O_FILEMAP const fMapLimit = 512 * 1024 const fMapFlag = UV_FS_O_FILEMAP | O_TRUNC | O_CREAT | O_WRONLY -export const getWriteFlag = !fMapEnabled - ? () => 'w' +export const getWriteFlag = + !fMapEnabled ? + () => 'w' : (size: number) => (size < fMapLimit ? fMapFlag : 'w') diff --git a/src/header.ts b/src/header.ts index 0ff3f84b..1b639c05 100644 --- a/src/header.ts +++ b/src/header.ts @@ -171,7 +171,7 @@ export class Header implements HeaderData { v === undefined || (k === 'path' && gex) || (k === 'linkpath' && gex) || - (k === 'global') + k === 'global' ) }), ), @@ -252,10 +252,9 @@ export class Header implements HeaderData { get type(): EntryTypeName { return ( - this.#type === 'Unsupported' - ? this.#type - : types.name.get(this.#type) - ) as EntryTypeName + this.#type === 'Unsupported' ? + this.#type + : types.name.get(this.#type)) as EntryTypeName } get typeKey(): EntryTypeCode | 'Unsupported' { @@ -332,9 +331,9 @@ const numToDate = (num?: number) => num === undefined ? undefined : new Date(num * 1000) const decNumber = (buf: Buffer, off: number, size: number) => - Number(buf[off]) & 0x80 - ? large.parse(buf.subarray(off, off + size)) - : decSmallNumber(buf, off, size) + Number(buf[off]) & 0x80 ? + large.parse(buf.subarray(off, off + size)) + : decSmallNumber(buf, off, size) const nanUndef = (value: number) => (isNaN(value) ? undefined : value) @@ -362,11 +361,10 @@ const encNumber = ( size: 12 | 8, num?: number, ) => - num === undefined - ? false - : num > MAXNUM[size] || num < 0 - ? (large.encode(num, buf.subarray(off, off + size)), true) - : (encSmallNumber(buf, off, size, num), false) + num === undefined ? false + : num > MAXNUM[size] || num < 0 ? + (large.encode(num, buf.subarray(off, off + size)), true) + : (encSmallNumber(buf, off, size, num), false) const encSmallNumber = ( buf: Buffer, @@ -379,9 +377,9 @@ const octalString = (num: number, size: number) => padOctal(Math.floor(num).toString(8), size) const padOctal = (str: string, size: number) => - (str.length === size - 1 - ? str - : new Array(size - str.length - 1).join('0') + str + ' ') + '\0' + (str.length === size - 1 ? + str + : new Array(size - str.length - 1).join('0') + str + ' ') + '\0' const encDate = ( buf: Buffer, @@ -389,9 +387,9 @@ const encDate = ( size: 8 | 12, date?: Date, ) => - date === undefined - ? false - : encNumber(buf, off, size, date.getTime() / 1000) + date === undefined ? false : ( + encNumber(buf, off, size, date.getTime() / 1000) + ) // enough to fill the longest string we've got const NULLS = new Array(156).join('\0') @@ -402,7 +400,7 @@ const encString = ( size: number, str?: string, ) => - str === undefined - ? false - : (buf.write(str + NULLS, off, size, 'utf8'), - str.length !== Buffer.byteLength(str) || str.length > size) + str === undefined ? false : ( + (buf.write(str + NULLS, off, size, 'utf8'), + str.length !== Buffer.byteLength(str) || str.length > size) + ) diff --git a/src/large-numbers.ts b/src/large-numbers.ts index cd62726d..cc015315 100644 --- a/src/large-numbers.ts +++ b/src/large-numbers.ts @@ -3,9 +3,11 @@ export const encode = (num: number, buf: Buffer) => { if (!Number.isSafeInteger(num)) { - // The number is so large that javascript cannot represent it with integer - // precision. - throw Error('cannot encode number outside of javascript safe integer range') + // The number is so large that javascript cannot represent it with integer + // precision. + throw Error( + 'cannot encode number outside of javascript safe integer range', + ) } else if (num < 0) { encodeNegative(num, buf) } else { @@ -43,7 +45,8 @@ const encodeNegative = (num: number, buf: Buffer) => { export const parse = (buf: Buffer) => { const pre = buf[0] - const value = pre === 0x80 ? pos(buf.subarray(1, buf.length)) + const value = + pre === 0x80 ? pos(buf.subarray(1, buf.length)) : pre === 0xff ? twos(buf) : null if (value === null) { @@ -51,9 +54,11 @@ export const parse = (buf: Buffer) => { } if (!Number.isSafeInteger(value)) { - // The number is so large that javascript cannot represent it with integer - // precision. - throw Error('parsed number outside of javascript safe integer range') + // The number is so large that javascript cannot represent it with integer + // precision. + throw Error( + 'parsed number outside of javascript safe integer range', + ) } return value diff --git a/src/list.ts b/src/list.ts index 9173edaa..f02d140a 100644 --- a/src/list.ts +++ b/src/list.ts @@ -79,17 +79,18 @@ export function list( onentryFunction(opt) } - return isSyncFile(opt) - ? listFileSync(opt) - : isFile(opt) - ? listFile(opt, cb) - : list_(opt) + return ( + isSyncFile(opt) ? listFileSync(opt) + : isFile(opt) ? listFile(opt, cb) + : list_(opt) + ) } const onentryFunction = (opt: TarOptions) => { const onentry = opt.onentry - opt.onentry = onentry - ? e => { + opt.onentry = + onentry ? + e => { onentry(e) e.resume() } @@ -121,8 +122,9 @@ const filesFilter = (opt: TarOptions, files: string[]) => { return ret } - opt.filter = filter - ? (file, entry) => + opt.filter = + filter ? + (file, entry) => filter(file, entry) && mapHas(stripTrailingSlashes(file)) : file => mapHas(stripTrailingSlashes(file)) } @@ -157,7 +159,10 @@ const listFileSync = (opt: TarOptionsSyncFile) => { } } -const listFile = (opt: TarOptionsFile, cb?: () => void): Promise<void> => { +const listFile = ( + opt: TarOptionsFile, + cb?: () => void, +): Promise<void> => { const parse = new Parser(opt) const readSize = opt.maxReadSize || 16 * 1024 * 1024 diff --git a/src/mode-fix.ts b/src/mode-fix.ts index 57bf9c98..0a7bbe54 100644 --- a/src/mode-fix.ts +++ b/src/mode-fix.ts @@ -1,4 +1,8 @@ -export const modeFix = (mode: number, isDir: boolean, portable: boolean) => { +export const modeFix = ( + mode: number, + isDir: boolean, + portable: boolean, +) => { mode &= 0o7777 // in portable mode, use the minimum reasonable umask diff --git a/src/normalize-windows-path.ts b/src/normalize-windows-path.ts index e452009b..7655119a 100644 --- a/src/normalize-windows-path.ts +++ b/src/normalize-windows-path.ts @@ -7,6 +7,6 @@ const platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform export const normalizeWindowsPath = - platform !== 'win32' - ? (p: string) => p - : (p: string) => p && p.replace(/\\/g, '/') + platform !== 'win32' ? + (p: string) => p + : (p: string) => p && p.replace(/\\/g, '/') diff --git a/src/parse.ts b/src/parse.ts index 0147f786..f260568d 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -137,11 +137,9 @@ export class Parser extends EE implements Warner { // if it's a tbr file it MIGHT be brotli, but we don't know until // we look at it and verify it's not a valid tar file. this.brotli = - !opt.gzip && opt.brotli !== undefined - ? opt.brotli - : isTBR - ? undefined - : false + !opt.gzip && opt.brotli !== undefined ? opt.brotli + : isTBR ? undefined + : false // have to set this so that streams are ok piping into it this.on('end', () => this[CLOSESTREAM]()) @@ -328,9 +326,9 @@ export class Parser extends EE implements Warner { const br = entry.blockRemain ?? 0 /* c8 ignore stop */ const c = - br >= chunk.length && position === 0 - ? chunk - : chunk.subarray(position, position + br) + br >= chunk.length && position === 0 ? + chunk + : chunk.subarray(position, position + br) entry.write(c) @@ -466,9 +464,9 @@ export class Parser extends EE implements Warner { const ended = this[ENDED] this[ENDED] = false this[UNZIP] = - this[UNZIP] === undefined - ? new Unzip({}) - : new BrotliDecompress({}) + this[UNZIP] === undefined ? + new Unzip({}) + : new BrotliDecompress({}) this[UNZIP].on('data', chunk => this[CONSUMECHUNK](chunk)) this[UNZIP].on('error', er => this.abort(er as Error)) this[UNZIP].on('end', () => { @@ -491,11 +489,10 @@ export class Parser extends EE implements Warner { this[WRITING] = false // return false if there's a queue, or if the current entry isn't flowing - const ret = this[QUEUE].length - ? false - : this[READENTRY] - ? this[READENTRY].flowing - : true + const ret = + this[QUEUE].length ? false + : this[READENTRY] ? this[READENTRY].flowing + : true // if we have no queue, then that means a clogged READENTRY if (!ret && !this[QUEUE].length) { @@ -507,9 +504,8 @@ export class Parser extends EE implements Warner { [BUFFERCONCAT](c: Buffer) { if (c && !this[ABORTED]) { - this[BUFFER] = this[BUFFER] - ? Buffer.concat([this[BUFFER], c]) - : c + this[BUFFER] = + this[BUFFER] ? Buffer.concat([this[BUFFER], c]) : c } } diff --git a/src/path-reservations.ts b/src/path-reservations.ts index 79407710..9edc7fb6 100644 --- a/src/path-reservations.ts +++ b/src/path-reservations.ts @@ -51,8 +51,9 @@ export class PathReservations { #running = new Set<Handler>() reserve(paths: string[], fn: Handler) { - paths = isWindows - ? ['win32 parallelization disabled'] + paths = + isWindows ? + ['win32 parallelization disabled'] : paths.map(p => { // don't need normPath, because we skip this entirely for windows return stripTrailingSlashes( diff --git a/src/pax.ts b/src/pax.ts index 680c9234..f72e85c8 100644 --- a/src/pax.ts +++ b/src/pax.ts @@ -120,9 +120,9 @@ export class Pax implements HeaderData { const v = r instanceof Date ? r.getTime() / 1000 : r const s = ' ' + - (field === 'dev' || field === 'ino' || field === 'nlink' - ? 'SCHILY.' - : '') + + (field === 'dev' || field === 'ino' || field === 'nlink' ? + 'SCHILY.' + : '') + field + '=' + v + @@ -173,10 +173,10 @@ const parseKVLine = (set: Record<string, any>, line: string) => { const k = r.replace(/^SCHILY\.(dev|ino|nlink)/, '$1') const v = kv.join('=') - set[k] = /^([A-Z]+\.)?([mac]|birth|creation)time$/.test(k) - ? new Date(Number(v) * 1000) - : /^[0-9]+$/.test(v) - ? +v - : v + set[k] = + /^([A-Z]+\.)?([mac]|birth|creation)time$/.test(k) ? + new Date(Number(v) * 1000) + : /^[0-9]+$/.test(v) ? +v + : v return set } diff --git a/src/read-entry.ts b/src/read-entry.ts index a4ca7eb7..0649bc99 100644 --- a/src/read-entry.ts +++ b/src/read-entry.ts @@ -96,8 +96,9 @@ export class ReadEntry extends Minipass<Buffer, Buffer> { this.atime = header.atime this.ctime = header.ctime /* c8 ignore start */ - this.linkpath = header.linkpath - ? normalizeWindowsPath(header.linkpath) + this.linkpath = + header.linkpath ? + normalizeWindowsPath(header.linkpath) : undefined /* c8 ignore stop */ this.uname = header.uname diff --git a/src/replace.ts b/src/replace.ts index 579b9b78..b65d2c13 100644 --- a/src/replace.ts +++ b/src/replace.ts @@ -62,8 +62,8 @@ export function replace( files = Array.from(files) - return isSyncFile(opt) - ? replaceSync(opt, files) + return isSyncFile(opt) ? + replaceSync(opt, files) : replace_(opt, files, cb) } diff --git a/src/strip-absolute-path.ts b/src/strip-absolute-path.ts index f127e329..49a446c2 100644 --- a/src/strip-absolute-path.ts +++ b/src/strip-absolute-path.ts @@ -16,9 +16,9 @@ export const stripAbsolutePath = (path: string) => { // windows will think that //x/y/z has a "root" of //x/y/ // but strip the //?/C:/ off of //?/C:/path const root = - path.charAt(0) === '/' && path.slice(0, 4) !== '//?/' - ? '/' - : parsed.root + path.charAt(0) === '/' && path.slice(0, 4) !== '//?/' ? + '/' + : parsed.root path = path.slice(root.length) r += root parsed = parse(path) diff --git a/src/symlink-error.ts b/src/symlink-error.ts index 7aa5ea78..13c4531d 100644 --- a/src/symlink-error.ts +++ b/src/symlink-error.ts @@ -3,7 +3,7 @@ export class SymlinkError extends Error { symlink: string syscall: 'symlink' = 'symlink' code: 'TAR_SYMLINK_ERROR' = 'TAR_SYMLINK_ERROR' - constructor (symlink: string, path: string) { + constructor(symlink: string, path: string) { super('TAR_SYMLINK_ERROR: Cannot extract through symbolic link') this.symlink = symlink this.path = path diff --git a/src/unpack.ts b/src/unpack.ts index 933975ff..f2eb4e3a 100644 --- a/src/unpack.ts +++ b/src/unpack.ts @@ -105,11 +105,9 @@ const uint32 = ( b: number | undefined, c: number | undefined, ) => - a !== undefined && a === a >>> 0 - ? a - : b !== undefined && b === b >>> 0 - ? b - : c + a !== undefined && a === a >>> 0 ? a + : b !== undefined && b === b >>> 0 ? b + : c // clear the cache if it's a case-insensitive unicode-squashing match. // we can't know if the current file system is case-sensitive or supports @@ -224,20 +222,20 @@ export class Unpack extends Parser { } this.processUid = - (this.preserveOwner || this.setOwner) && process.getuid - ? process.getuid() - : undefined + (this.preserveOwner || this.setOwner) && process.getuid ? + process.getuid() + : undefined this.processGid = - (this.preserveOwner || this.setOwner) && process.getgid - ? process.getgid() - : undefined + (this.preserveOwner || this.setOwner) && process.getgid ? + process.getgid() + : undefined // prevent excessively deep nesting of subfolders // set to `Infinity` to remove this restriction this.maxDepth = - typeof opt.maxDepth === 'number' - ? opt.maxDepth - : DEFAULT_MAX_DEPTH + typeof opt.maxDepth === 'number' ? + opt.maxDepth + : DEFAULT_MAX_DEPTH // mostly just for testing, but useful in some cases. // Forcibly trigger a chown on every entry, no matter what @@ -269,11 +267,10 @@ export class Unpack extends Parser { ) this.strip = Number(opt.strip) || 0 // if we're not chmodding, then we don't need the process umask - this.processUmask = !this.chmod - ? 0 - : typeof opt.processUmask === 'number' - ? opt.processUmask - : process.umask() + this.processUmask = + !this.chmod ? 0 + : typeof opt.processUmask === 'number' ? opt.processUmask + : process.umask() this.umask = typeof opt.umask === 'number' ? opt.umask : this.processUmask @@ -504,9 +501,9 @@ export class Unpack extends Parser { [FILE](entry: ReadEntry, fullyDone: () => void) { const mode = - typeof entry.mode === 'number' - ? entry.mode & 0o7777 - : this.fmode + typeof entry.mode === 'number' ? + entry.mode & 0o7777 + : this.fmode const stream = new fsm.WriteStream(String(entry.absolute), { // slight lie, but it can be numeric flags flags: getWriteFlag(entry.size) as string, @@ -566,9 +563,9 @@ export class Unpack extends Parser { const atime = entry.atime || new Date() const mtime = entry.mtime fs.futimes(fd, atime, mtime, er => - er - ? fs.utimes(abs, atime, mtime, er2 => done(er2 && er)) - : done(), + er ? + fs.utimes(abs, atime, mtime, er2 => done(er2 && er)) + : done(), ) } @@ -578,9 +575,9 @@ export class Unpack extends Parser { const gid = this[GID](entry) if (typeof uid === 'number' && typeof gid === 'number') { fs.fchown(fd, uid, gid, er => - er - ? fs.chown(abs, uid, gid, er2 => done(er2 && er)) - : done(), + er ? + fs.chown(abs, uid, gid, er2 => done(er2 && er)) + : done(), ) } } @@ -601,9 +598,9 @@ export class Unpack extends Parser { [DIRECTORY](entry: ReadEntry, fullyDone: () => void) { const mode = - typeof entry.mode === 'number' - ? entry.mode & 0o7777 - : this.dmode + typeof entry.mode === 'number' ? + entry.mode & 0o7777 + : this.dmode this[MKDIR](String(entry.absolute), mode, er => { if (er) { this[ONERROR](er, entry) @@ -937,8 +934,9 @@ export class UnpackSync extends Unpack { this.chmod && entry.mode && (st.mode & 0o7777) !== entry.mode - const [er] = needChmod - ? callSync(() => { + const [er] = + needChmod ? + callSync(() => { fs.chmodSync(String(entry.absolute), Number(entry.mode)) }) : [] @@ -954,17 +952,17 @@ export class UnpackSync extends Unpack { // not a dir, and not reusable. // don't remove if it's the cwd, since we want that error. const [er] = - entry.absolute === this.cwd - ? [] - : callSync(() => unlinkFileSync(String(entry.absolute))) + entry.absolute === this.cwd ? + [] + : callSync(() => unlinkFileSync(String(entry.absolute))) this[MAKEFS](er, entry) } [FILE](entry: ReadEntry, done: () => void) { const mode = - typeof entry.mode === 'number' - ? entry.mode & 0o7777 - : this.fmode + typeof entry.mode === 'number' ? + entry.mode & 0o7777 + : this.fmode const oner = (er?: null | Error | undefined) => { let closeError @@ -1046,9 +1044,9 @@ export class UnpackSync extends Unpack { [DIRECTORY](entry: ReadEntry, done: () => void) { const mode = - typeof entry.mode === 'number' - ? entry.mode & 0o7777 - : this.dmode + typeof entry.mode === 'number' ? + entry.mode & 0o7777 + : this.dmode const er = this[MKDIR](String(entry.absolute), mode) if (er) { this[ONERROR](er as Error, entry) diff --git a/src/update.ts b/src/update.ts index d30b2daa..c824bbef 100644 --- a/src/update.ts +++ b/src/update.ts @@ -47,20 +47,25 @@ const mtimeFilter = (opt: TarOptionsWithAliases) => { opt.mtimeCache = new Map() } - opt.filter = filter - ? (path, stat) => + opt.filter = + filter ? + (path, stat) => filter(path, stat) && !( /* c8 ignore start */ - (opt.mtimeCache?.get(path) ?? stat.mtime ?? 0) > - (stat.mtime ?? 0) + ( + (opt.mtimeCache?.get(path) ?? stat.mtime ?? 0) > + (stat.mtime ?? 0) + ) /* c8 ignore stop */ ) : (path, stat) => !( /* c8 ignore start */ - (opt.mtimeCache?.get(path) ?? stat.mtime ?? 0) > - (stat.mtime ?? 0) + ( + (opt.mtimeCache?.get(path) ?? stat.mtime ?? 0) > + (stat.mtime ?? 0) + ) /* c8 ignore stop */ ) } diff --git a/src/write-entry.ts b/src/write-entry.ts index 5d728585..c528cf8a 100644 --- a/src/write-entry.ts +++ b/src/write-entry.ts @@ -99,9 +99,8 @@ export class WriteEntry extends Minipass<Buffer> implements Warner { this.noPax = !!opt.noPax this.noMtime = !!opt.noMtime this.mtime = opt.mtime - this.prefix = opt.prefix - ? normalizeWindowsPath(opt.prefix) - : undefined + this.prefix = + opt.prefix ? normalizeWindowsPath(opt.prefix) : undefined if (typeof opt.onwarn === 'function') { this.on('warn', opt.onwarn) @@ -219,9 +218,9 @@ export class WriteEntry extends Minipass<Buffer> implements Warner { path: this[PREFIX](this.path), // only apply the prefix to hard links. linkpath: - this.type === 'Link' && this.linkpath !== undefined - ? this[PREFIX](this.linkpath) - : this.linkpath, + this.type === 'Link' && this.linkpath !== undefined ? + this[PREFIX](this.linkpath) + : this.linkpath, // only the permissions and setuid/setgid/sticky bitflags // not the higher-order bits that specify file type mode: this[MODE](this.stat.mode), @@ -231,11 +230,10 @@ export class WriteEntry extends Minipass<Buffer> implements Warner { mtime: this.noMtime ? undefined : this.mtime || this.stat.mtime, /* c8 ignore next */ type: this.type === 'Unsupported' ? undefined : this.type, - uname: this.portable - ? undefined - : this.stat.uid === this.myuid - ? this.myuser - : '', + uname: + this.portable ? undefined + : this.stat.uid === this.myuid ? this.myuser + : '', atime: this.portable ? undefined : this.stat.atime, ctime: this.portable ? undefined : this.stat.ctime, }) @@ -246,14 +244,15 @@ export class WriteEntry extends Minipass<Buffer> implements Warner { atime: this.portable ? undefined : this.header.atime, ctime: this.portable ? undefined : this.header.ctime, gid: this.portable ? undefined : this.header.gid, - mtime: this.noMtime - ? undefined - : this.mtime || this.header.mtime, + mtime: + this.noMtime ? undefined : ( + this.mtime || this.header.mtime + ), path: this[PREFIX](this.path), linkpath: - this.type === 'Link' && this.linkpath !== undefined - ? this[PREFIX](this.linkpath) - : this.linkpath, + this.type === 'Link' && this.linkpath !== undefined ? + this[PREFIX](this.linkpath) + : this.linkpath, size: this.header.size, uid: this.portable ? undefined : this.header.uid, uname: this.portable ? undefined : this.header.uname, @@ -444,9 +443,9 @@ export class WriteEntry extends Minipass<Buffer> implements Warner { } const writeBuf = - this.offset === 0 && bytesRead === this.buf.length - ? this.buf - : this.buf.subarray(this.offset, this.offset + bytesRead) + this.offset === 0 && bytesRead === this.buf.length ? + this.buf + : this.buf.subarray(this.offset, this.offset + bytesRead) const flushed = this.write(writeBuf) if (!flushed) { @@ -619,23 +618,22 @@ export class WriteEntryTar this.path = normalizeWindowsPath(readEntry.path) this.mode = - readEntry.mode !== undefined - ? this[MODE](readEntry.mode) - : undefined + readEntry.mode !== undefined ? + this[MODE](readEntry.mode) + : undefined this.uid = this.portable ? undefined : readEntry.uid this.gid = this.portable ? undefined : readEntry.gid this.uname = this.portable ? undefined : readEntry.uname this.gname = this.portable ? undefined : readEntry.gname this.size = readEntry.size - this.mtime = this.noMtime - ? undefined - : opt.mtime || readEntry.mtime + this.mtime = + this.noMtime ? undefined : opt.mtime || readEntry.mtime this.atime = this.portable ? undefined : readEntry.atime this.ctime = this.portable ? undefined : readEntry.ctime this.linkpath = - readEntry.linkpath !== undefined - ? normalizeWindowsPath(readEntry.linkpath) - : undefined + readEntry.linkpath !== undefined ? + normalizeWindowsPath(readEntry.linkpath) + : undefined if (typeof opt.onwarn === 'function') { this.on('warn', opt.onwarn) @@ -656,9 +654,9 @@ export class WriteEntryTar this.header = new Header({ path: this[PREFIX](this.path), linkpath: - this.type === 'Link' && this.linkpath !== undefined - ? this[PREFIX](this.linkpath) - : this.linkpath, + this.type === 'Link' && this.linkpath !== undefined ? + this[PREFIX](this.linkpath) + : this.linkpath, // only the permissions and setuid/setgid/sticky bitflags // not the higher-order bits that specify file type mode: this.mode, @@ -692,9 +690,9 @@ export class WriteEntryTar mtime: this.noMtime ? undefined : this.mtime, path: this[PREFIX](this.path), linkpath: - this.type === 'Link' && this.linkpath !== undefined - ? this[PREFIX](this.linkpath) - : this.linkpath, + this.type === 'Link' && this.linkpath !== undefined ? + this[PREFIX](this.linkpath) + : this.linkpath, size: this.size, uid: this.portable ? undefined : this.uid, uname: this.portable ? undefined : this.uname, @@ -739,10 +737,7 @@ export class WriteEntryTar } const getType = (stat: Stats): EntryTypeName | 'Unsupported' => - stat.isFile() - ? 'File' - : stat.isDirectory() - ? 'Directory' - : stat.isSymbolicLink() - ? 'SymbolicLink' - : 'Unsupported' + stat.isFile() ? 'File' + : stat.isDirectory() ? 'Directory' + : stat.isSymbolicLink() ? 'SymbolicLink' + : 'Unsupported' diff --git a/test/get-write-flag.js b/test/get-write-flag.js index 63c4a2bf..1e81ba20 100644 --- a/test/get-write-flag.js +++ b/test/get-write-flag.js @@ -42,31 +42,31 @@ switch (process.argv[2]) { t.spawn(node, [__filename, 'win32-fmap'], { env: { ...process.env, - ...(platform === 'win32' - ? {} - : { - __FAKE_FS_O_FILENAME__: String(UV_FS_O_FILEMAP), - __FAKE_PLATFORM__: 'win32', - }), + ...(platform === 'win32' ? + {} + : { + __FAKE_FS_O_FILENAME__: String(UV_FS_O_FILEMAP), + __FAKE_PLATFORM__: 'win32', + }), }, }) t.spawn(node, [__filename, 'win32-nofmap'], { env: { ...process.env, - ...(platform === 'win32' - ? {} - : { - __FAKE_FS_O_FILENAME__: '0', - __FAKE_PLATFORM__: 'win32', - }), + ...(platform === 'win32' ? + {} + : { + __FAKE_FS_O_FILENAME__: '0', + __FAKE_PLATFORM__: 'win32', + }), }, }) t.spawn(node, [__filename, 'unix'], { env: { ...process.env, - ...(platform === 'win32' - ? { __FAKE_PLATFORM__: 'linux' } - : {}), + ...(platform === 'win32' ? + { __FAKE_PLATFORM__: 'linux' } + : {}), }, }) } diff --git a/test/header.js b/test/header.js index 92554a65..40332a45 100644 --- a/test/header.js +++ b/test/header.js @@ -615,7 +615,7 @@ t.test('null block, global extended header', t => { path: '/global.path', foo: 'global foo', global: true, - linkpath: 'asdf' + linkpath: 'asdf', }, ) t.match(h, { @@ -666,6 +666,6 @@ t.test('gnutar-generated 10gb file size', t => { const h = new Header(b) t.equal(h.size, 1024 * 1024 * 1024 * 10, 'should be 10gb file') // cannot set type to something invalid - t.throws(() => h.type = 'Z') + t.throws(() => (h.type = 'Z')) t.end() }) diff --git a/test/large-numbers.js b/test/large-numbers.js index f2b80467..c84956d2 100644 --- a/test/large-numbers.js +++ b/test/large-numbers.js @@ -1,5 +1,5 @@ import t from 'tap' -import { encode, parse } from '../dist/esm/large-numbers.js' +import { encode, parse } from '../dist/esm/large-numbers.js' t.test('parse', t => { const cases = new Map([ @@ -16,7 +16,8 @@ t.test('parse', t => { ]) t.plan(cases.size) cases.forEach((value, hex) => - t.equal(parse(Buffer.from(hex, 'hex')), value)) + t.equal(parse(Buffer.from(hex, 'hex')), value), + ) }) t.test('parse out of range', t => { @@ -27,9 +28,12 @@ t.test('parse out of range', t => { 'fffffffffdd0000000000000', ] t.plan(cases.length) - cases.forEach((hex) => - t.throws(_ => parse(Buffer.from(hex, 'hex')), - Error('parsed number outside of javascript safe integer range'))) + cases.forEach(hex => + t.throws( + _ => parse(Buffer.from(hex, 'hex')), + Error('parsed number outside of javascript safe integer range'), + ), + ) }) t.test('parse invalid base256 encoding', t => { @@ -38,9 +42,12 @@ t.test('parse invalid base256 encoding', t => { '700000030000000000000000', // does not start with 0x80 or 0xff ] t.plan(cases.length) - cases.forEach((hex) => - t.throws(_ => parse(Buffer.from(hex, 'hex')), - Error('invalid base256 encoding'))) + cases.forEach(hex => + t.throws( + _ => parse(Buffer.from(hex, 'hex')), + Error('invalid base256 encoding'), + ), + ) }) t.test('encode', t => { @@ -58,12 +65,17 @@ t.test('encode', t => { t.test('alloc', t => { t.plan(cases.size) cases.forEach((value, hex) => - t.equal(encode(value, Buffer.alloc(12)).toString('hex'), hex)) + t.equal(encode(value, Buffer.alloc(12)).toString('hex'), hex), + ) }) t.test('allocUnsafe', t => { t.plan(cases.size) cases.forEach((value, hex) => - t.equal(encode(value, Buffer.allocUnsafe(12)).toString('hex'), hex)) + t.equal( + encode(value, Buffer.allocUnsafe(12)).toString('hex'), + hex, + ), + ) }) }) @@ -76,7 +88,12 @@ t.test('encode unsafe numbers', t => { ] t.plan(cases.length) - cases.forEach((value) => - t.throws(_ => encode(value), - Error('cannot encode number outside of javascript safe integer range'))) + cases.forEach(value => + t.throws( + _ => encode(value), + Error( + 'cannot encode number outside of javascript safe integer range', + ), + ), + ) }) diff --git a/test/normalize-unicode.js b/test/normalize-unicode.js index ae3efd4d..ffbb07bf 100644 --- a/test/normalize-unicode.js +++ b/test/normalize-unicode.js @@ -58,6 +58,6 @@ if (fakePlatform !== 'win32') { env: { ...process.env, TESTING_TAR_FAKE_PLATFORM: 'win32', - } + }, }) } diff --git a/test/pack.js b/test/pack.js index dae2fba9..c64a92b2 100644 --- a/test/pack.js +++ b/test/pack.js @@ -92,7 +92,10 @@ t.test('pack a file', t => { throw new Error('no data!') } - t.equal(sync.subarray(512).toString(), data.subarray(512).toString()) + t.equal( + sync.subarray(512).toString(), + data.subarray(512).toString(), + ) const hs = new Header(sync) t.match(hs, expect) t.end() @@ -132,7 +135,10 @@ t.test('pack a file with a prefix', t => { .add('.dotfile') .end() .read() - t.equal(sync.subarray(512).toString(), data.subarray(512).toString()) + t.equal( + sync.subarray(512).toString(), + data.subarray(512).toString(), + ) const hs = new Header(sync) t.match(hs, expect) t.end() @@ -187,7 +193,10 @@ t.test('portable pack a dir', t => { t.equal(syncgz[9], 255, 'gzip OS flag set to "unknown"') const sync = new miniz.Gunzip().end(zipped).read() - t.equal(sync.subarray(512).toString(), data.subarray(512).toString()) + t.equal( + sync.subarray(512).toString(), + data.subarray(512).toString(), + ) const hs = new Header(sync) t.match(hs, expect) @@ -257,7 +266,10 @@ t.test('use process cwd if cwd not specified', t => { .add('dir') .end() .read() - t.equal(sync.subarray(512).toString(), data.subarray(512).toString()) + t.equal( + sync.subarray(512).toString(), + data.subarray(512).toString(), + ) const hs = new Header(sync) t.match(hs, expect) @@ -325,7 +337,10 @@ t.test('filter', t => { .add('dir') .end() .read() - t.equal(sync.subarray(512).toString(), data.subarray(512).toString()) + t.equal( + sync.subarray(512).toString(), + data.subarray(512).toString(), + ) const hs = new Header(sync) t.match(hs, expect) t.end() @@ -976,7 +991,10 @@ t.test('pipe into a slow reader', t => { } t.match(h, expect) t.equal(data.length, 21504) - t.match(data.subarray(data.length - 1024).toString(), /^\0{1024}$/) + t.match( + data.subarray(data.length - 1024).toString(), + /^\0{1024}$/, + ) t.end() }) }) @@ -1037,7 +1055,10 @@ t.test('pipe into a slow gzip reader', t => { } t.match(h, expect) t.equal(data.length, 21504) - t.match(data.subarray(data.length - 1024).toString(), /^\0{1024}$/) + t.match( + data.subarray(data.length - 1024).toString(), + /^\0{1024}$/, + ) t.end() }) }) @@ -1066,8 +1087,14 @@ t.test('ignores mid-queue', t => { p.on('data', c => out.push(c)) p.on('end', _ => { const data = Buffer.concat(out) - t.equal(data.subarray(0, 100).toString().replace(/\0.*$/, ''), './') - const file = data.subarray(512, 612).toString().replace(/\0.*$/, '') + t.equal( + data.subarray(0, 100).toString().replace(/\0.*$/, ''), + './', + ) + const file = data + .subarray(512, 612) + .toString() + .replace(/\0.*$/, '') t.not(files.indexOf(file), -1) t.end() }) @@ -1256,7 +1283,10 @@ t.test('pack ReadEntries', t => { const data = Buffer.concat(out) t.equal(data.length, 2048) t.match(data.subarray(1024).toString(), /^\0+$/) - t.equal(data.subarray(0, 100).toString().replace(/\0.*$/, ''), 'x') + t.equal( + data.subarray(0, 100).toString().replace(/\0.*$/, ''), + 'x', + ) t.equal(data.subarray(512, 514).toString(), 'x\0') t.end() }) @@ -1325,7 +1355,10 @@ t.test('pack ReadEntries', t => { const data = Buffer.concat(out) t.equal(data.length, 2048) t.match(data.subarray(1024).toString(), /^\0+$/) - t.equal(data.subarray(0, 100).toString().replace(/\0.*$/, ''), 'x') + t.equal( + data.subarray(0, 100).toString().replace(/\0.*$/, ''), + 'x', + ) t.equal(data.subarray(512, 514).toString(), 'x\0') t.end() }) @@ -1468,7 +1501,10 @@ t.test('prefix and subdirs', t => { const check = (out, t) => { const data = Buffer.concat(out) expect.forEach((e, i) => - t.equal(e, data.subarray(i * 512, i * 512 + e.length).toString()), + t.equal( + e, + data.subarray(i * 512, i * 512 + e.length).toString(), + ), ) t.end() } @@ -1546,7 +1582,10 @@ t.test('prefix and hard links', t => { const data = Buffer.concat(out) expect.forEach((e, i) => { if (typeof e === 'string') { - t.equal(data.subarray(i * 512, i * 512 + e.length).toString(), e) + t.equal( + data.subarray(i * 512, i * 512 + e.length).toString(), + e, + ) } else { t.match(new Header(data.subarray(i * 512, (i + 1) * 512)), e) } diff --git a/test/parse.js b/test/parse.js index ebee05e6..db60ce0c 100644 --- a/test/parse.js +++ b/test/parse.js @@ -20,7 +20,9 @@ t.test('fixture tests', t => { super.write(chunk.subarray(i, i + 1)) } - const ret = super.write(chunk.subarray(chunk.length - 1, chunk.length)) + const ret = super.write( + chunk.subarray(chunk.length - 1, chunk.length), + ) if (ret === false) { throw new Error('BS write return false') } @@ -106,15 +108,16 @@ t.test('fixture tests', t => { if (c.length !== 1) throw new Error('wat2') }) const opt = - maxMeta || filter || strict - ? { - maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 - : undefined, - strict: strict, - } - : undefined + maxMeta || filter || strict ? + { + maxMetaEntrySize: maxMeta, + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + } + : undefined const p = new Parser(opt) trackEvents(t, expect, p) bs.pipe(p) @@ -125,8 +128,9 @@ t.test('fixture tests', t => { t.test('uncompressed all at once', t => { const p = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 : undefined, strict: strict, }) @@ -139,16 +143,17 @@ t.test('fixture tests', t => { t => { const bs = new ByteStream() const opt = - maxMeta || filter || strict - ? { - maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 - : undefined, - strict: strict, - file: 'example.tbr', - } - : undefined + maxMeta || filter || strict ? + { + maxMetaEntrySize: maxMeta, + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 + : undefined, + strict: strict, + file: 'example.tbr', + } + : undefined const bp = new Parser(opt) trackEvents(t, expect, bp) bs.pipe(bp) @@ -159,8 +164,9 @@ t.test('fixture tests', t => { t.test('uncompressed all at once, filename .tar.br', t => { const p = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 : undefined, strict: strict, file: 'example.tar.br', @@ -172,8 +178,9 @@ t.test('fixture tests', t => { t.test('gzipped all at once', t => { const p = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 : undefined, strict: strict, }) @@ -184,8 +191,9 @@ t.test('fixture tests', t => { t.test('gzipped all at once, filename .tbr', t => { const p = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 : undefined, strict: strict, file: 'example.tbr', @@ -198,8 +206,9 @@ t.test('fixture tests', t => { const bs = new ByteStream() const bp = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 : undefined, strict: strict, }) @@ -213,8 +222,9 @@ t.test('fixture tests', t => { t => { const p = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 : undefined, strict: strict, file: 'example.tar.br', @@ -227,8 +237,9 @@ t.test('fixture tests', t => { t.test('compress with brotli based on filename .tbr', t => { const p = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 : undefined, strict: strict, file: 'example.tbr', @@ -240,8 +251,9 @@ t.test('fixture tests', t => { t.test('compress with brotli all at once', t => { const p = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 : undefined, strict: strict, brotli: {}, @@ -254,8 +266,9 @@ t.test('fixture tests', t => { const bs = new ByteStream() const bp = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 : undefined, strict: strict, brotli: {}, @@ -269,8 +282,9 @@ t.test('fixture tests', t => { const bs = new ByteStream() const bp = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 : undefined, strict: strict, file: 'example.tbr', @@ -283,8 +297,9 @@ t.test('fixture tests', t => { t.test('async chunks', t => { const p = new Parser({ maxMetaEntrySize: maxMeta, - filter: filter - ? (_path, entry) => entry.size % 2 !== 0 + filter: + filter ? + (_path, entry) => entry.size % 2 !== 0 : undefined, strict: strict, }) diff --git a/test/path-reservations.js b/test/path-reservations.js index 6d9f7452..67f9ab17 100644 --- a/test/path-reservations.js +++ b/test/path-reservations.js @@ -7,19 +7,24 @@ if (process.platform === 'win32') { process.env.TESTING_TAR_FAKE_PLATFORM = 'posix' } - -const { PathReservations } = await t.mockImport('../dist/esm/path-reservations.js', { - path: posix, -}) +const { PathReservations } = await t.mockImport( + '../dist/esm/path-reservations.js', + { + path: posix, + }, +) delete process.env.TESTING_TAR_FAKE_PLATFORM if (process.platform !== 'win32') { process.env.TESTING_TAR_FAKE_PLATFORM = 'win32' } -const { PathReservations: WinPathReservations } = await t.mockImport('../dist/esm/path-reservations.js', { - path: win32, -}) +const { PathReservations: WinPathReservations } = await t.mockImport( + '../dist/esm/path-reservations.js', + { + path: win32, + }, +) t.test('basic race', t => { // simulate the race conditions we care about diff --git a/test/pax.js b/test/pax.js index eb7f9260..ea325b37 100644 --- a/test/pax.js +++ b/test/pax.js @@ -20,40 +20,40 @@ t.test('create a pax', t => { const buf = Buffer.from( // pax entry header '5061784865616465722f666f6f2e747874000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000030303036343420003035373736312000303030303234200030303030' + - '3030303330342000323136373231373631302000303136373332200078000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461720030306973616163730000000000000000000000000000000000' + - '0000000000000000007374616666000000000000000000000000000000000000' + - '0000000000000000003030303030302000303030303030200000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000032313637' + - '3231373631302000323136373231373631302000000000000000000000000000' + - - // entry body - '313620706174683d666f6f2e7478740a3139206374696d653d32393937303432' + - '30300a3139206174696d653d3239393730343230300a323120534348494c592e' + - '6465763d3132333435360a313920534348494c592e696e6f3d373839300a3138' + - '20534348494c592e6e6c696e6b3d310a39206769643d32300a313520676e616d' + - '653d73746166660a3139206d74696d653d3239393730343230300a3132207369' + - '7a653d3130300a3133207569643d32343536310a313620756e616d653d697361' + - '6163730a00000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000', - 'hex') + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000030303036343420003035373736312000303030303234200030303030' + + '3030303330342000323136373231373631302000303136373332200078000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461720030306973616163730000000000000000000000000000000000' + + '0000000000000000007374616666000000000000000000000000000000000000' + + '0000000000000000003030303030302000303030303030200000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000032313637' + + '3231373631302000323136373231373631302000000000000000000000000000' + + // entry body + '313620706174683d666f6f2e7478740a3139206374696d653d32393937303432' + + '30300a3139206174696d653d3239393730343230300a323120534348494c592e' + + '6465763d3132333435360a313920534348494c592e696e6f3d373839300a3138' + + '20534348494c592e6e6c696e6b3d310a39206769643d32300a313520676e616d' + + '653d73746166660a3139206d74696d653d3239393730343230300a3132207369' + + '7a653d3130300a3133207569643d32343536310a313620756e616d653d697361' + + '6163730a00000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', + ) const actual = p.encode() t.match(actual, buf) @@ -75,45 +75,45 @@ t.test('tiny pax', t => { const buf = Buffer.from( // header '5061784865616465722f61620000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000030303036343420000000000000000000000000000000000030303030' + - '3030303031332000000000000000000000000000303037303534200067000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0075737461720030300000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000003030303030302000303030303030200000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - - // body - // note that a 2-char path is 11, but a 1 char path is 9, because - // adding the second char bumps the n to 10, which adds 1, which - // means it has to be 11. - // a 1-char path COULD be encoded as EITHER "10 path=x\n", or as - // "9 path=x\n", and it'd be true either way. - '313120706174683d61620a000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000' + - '0000000000000000000000000000000000000000000000000000000000000000', - 'hex') + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000030303036343420000000000000000000000000000000000030303030' + + '3030303031332000000000000000000000000000303037303534200067000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0075737461720030300000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000003030303030302000303030303030200000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + // body + // note that a 2-char path is 11, but a 1 char path is 9, because + // adding the second char bumps the n to 10, which adds 1, which + // means it has to be 11. + // a 1-char path COULD be encoded as EITHER "10 path=x\n", or as + // "9 path=x\n", and it'd be true either way. + '313120706174683d61620a000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000' + + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', + ) t.same(actual, buf) @@ -122,46 +122,52 @@ t.test('tiny pax', t => { t.test('parse', t => { const p = Pax.parse('11 path=ab\n', { uid: 24561 }, true) - t.same(p, Object.assign(Object.create(Pax.prototype), { - atime: undefined, - mode: undefined, - charset: undefined, - comment: undefined, - ctime: undefined, - gid: undefined, - gname: undefined, - linkpath: undefined, - mtime: undefined, - path: 'ab', - size: undefined, - uid: 24561, - uname: undefined, - dev: undefined, - ino: undefined, - nlink: undefined, - global: true, - })) + t.same( + p, + Object.assign(Object.create(Pax.prototype), { + atime: undefined, + mode: undefined, + charset: undefined, + comment: undefined, + ctime: undefined, + gid: undefined, + gname: undefined, + linkpath: undefined, + mtime: undefined, + path: 'ab', + size: undefined, + uid: 24561, + uname: undefined, + dev: undefined, + ino: undefined, + nlink: undefined, + global: true, + }), + ) - t.same(Pax.parse('11 path=ab\n'), Object.assign(Object.create(Pax.prototype), { - atime: undefined, - mtime: undefined, - ctime: undefined, - charset: undefined, - comment: undefined, - gid: undefined, - gname: undefined, - uname: undefined, - linkpath: undefined, - path: 'ab', - size: undefined, - mode: undefined, - uid: undefined, - uname: undefined, - dev: undefined, - ino: undefined, - nlink: undefined, - global: false, - })) + t.same( + Pax.parse('11 path=ab\n'), + Object.assign(Object.create(Pax.prototype), { + atime: undefined, + mtime: undefined, + ctime: undefined, + charset: undefined, + comment: undefined, + gid: undefined, + gname: undefined, + uname: undefined, + linkpath: undefined, + path: 'ab', + size: undefined, + mode: undefined, + uid: undefined, + uname: undefined, + dev: undefined, + ino: undefined, + nlink: undefined, + global: false, + }), + ) t.same(Pax.parse('9 gid=20\n9 path=x\n'), { atime: undefined, diff --git a/test/replace.js b/test/replace.js index 22af74d7..abab2965 100644 --- a/test/replace.js +++ b/test/replace.js @@ -1,10 +1,10 @@ import t from 'tap' import { replace as r } from '../dist/esm/replace.js' -import path, {dirname, resolve } from 'path' +import path, { dirname, resolve } from 'path' import fs from 'fs' import mutateFS from 'mutate-fs' import { list } from '../dist/esm/list.js' -import {fileURLToPath} from 'url' +import { fileURLToPath } from 'url' import zlib from 'zlib' import { spawn } from 'child_process' @@ -13,14 +13,19 @@ const __dirname = dirname(__filename) const fixtures = path.resolve(__dirname, 'fixtures') const tars = path.resolve(fixtures, 'tars') - const data = fs.readFileSync(tars + '/body-byte-counts.tar') const dataNoNulls = data.subarray(0, data.length - 1024) const fixtureDef = { 'body-byte-counts.tar': data, 'no-null-eof.tar': dataNoNulls, - 'truncated-head.tar': Buffer.concat([dataNoNulls, data.subarray(0, 500)]), - 'truncated-body.tar': Buffer.concat([dataNoNulls, data.subarray(0, 700)]), + 'truncated-head.tar': Buffer.concat([ + dataNoNulls, + data.subarray(0, 500), + ]), + 'truncated-body.tar': Buffer.concat([ + dataNoNulls, + data.subarray(0, 700), + ]), 'zero.tar': Buffer.from(''), 'empty.tar': Buffer.alloc(512), 'compressed.tgz': zlib.gzipSync(data), @@ -35,7 +40,10 @@ t.test('basic file add to archive (good or truncated)', t => { c.on('close', (code, signal) => { t.equal(code, 0) t.equal(signal, null) - const actual = Buffer.concat(out).toString().trim().split(/\r?\n/) + const actual = Buffer.concat(out) + .toString() + .trim() + .split(/\r?\n/) t.same(actual, [ '1024-bytes.txt', '512-bytes.txt', @@ -53,21 +61,26 @@ t.test('basic file add to archive (good or truncated)', t => { 'truncated-head.tar', 'truncated-body.tar', ] - const td = files.map(f => [f, fixtureDef[f]]).reduce((s, [k, v]) => { - s[k] = v - return s - }, {}) + const td = files + .map(f => [f, fixtureDef[f]]) + .reduce((s, [k, v]) => { + s[k] = v + return s + }, {}) const fileList = [path.basename(__filename)] t.test('sync', t => { t.plan(files.length) const dir = t.testdir(td) for (const file of files) { t.test(file, t => { - r({ - sync: true, - file: resolve(dir, file), - cwd: __dirname, - }, fileList) + r( + { + sync: true, + file: resolve(dir, file), + cwd: __dirname, + }, + fileList, + ) check(resolve(dir, file), t) }) } @@ -78,15 +91,19 @@ t.test('basic file add to archive (good or truncated)', t => { const dir = t.testdir(td) for (const file of files) { t.test(file, t => { - r({ - file: resolve(dir, file), - cwd: __dirname, - }, fileList, er => { - if (er) { - throw er - } - check(resolve(dir, file), t) - }) + r( + { + file: resolve(dir, file), + cwd: __dirname, + }, + fileList, + er => { + if (er) { + throw er + } + check(resolve(dir, file), t) + }, + ) }) } }) @@ -96,10 +113,13 @@ t.test('basic file add to archive (good or truncated)', t => { const dir = t.testdir(td) for (const file of files) { t.test(file, t => { - r({ - file: resolve(dir, file), - cwd: __dirname, - }, fileList).then(() => { + r( + { + file: resolve(dir, file), + cwd: __dirname, + }, + fileList, + ).then(() => { check(resolve(dir, file), t) }) }) @@ -118,21 +138,18 @@ t.test('add to empty archive', t => { t.equal(code, 0) t.equal(signal, null) const actual = Buffer.concat(out).toString().trim().split('\n') - t.same(actual, [ - path.basename(__filename), - ]) + t.same(actual, [path.basename(__filename)]) t.end() }) } - const files = [ - 'empty.tar', - 'zero.tar', - ] - const td = files.map(f => [f, fixtureDef[f]]).reduce((s, [k, v]) => { - s[k] = v - return s - }, {}) + const files = ['empty.tar', 'zero.tar'] + const td = files + .map(f => [f, fixtureDef[f]]) + .reduce((s, [k, v]) => { + s[k] = v + return s + }, {}) files.push('not-existing.tar') t.test('sync', t => { @@ -140,11 +157,14 @@ t.test('add to empty archive', t => { t.plan(files.length) for (const file of files) { t.test(file, t => { - r({ - sync: true, - file: resolve(dir, file), - cwd: __dirname, - }, [path.basename(__filename)]) + r( + { + sync: true, + file: resolve(dir, file), + cwd: __dirname, + }, + [path.basename(__filename)], + ) check(resolve(dir, file), t) }) } @@ -155,15 +175,19 @@ t.test('add to empty archive', t => { t.plan(files.length) for (const file of files) { t.test(file, t => { - r({ - file: resolve(dir, file), - cwd: __dirname, - }, [path.basename(__filename)], er => { - if (er) { - throw er - } - check(resolve(dir, file), t) - }) + r( + { + file: resolve(dir, file), + cwd: __dirname, + }, + [path.basename(__filename)], + er => { + if (er) { + throw er + } + check(resolve(dir, file), t) + }, + ) }) } }) @@ -173,10 +197,13 @@ t.test('add to empty archive', t => { t.plan(files.length) for (const file of files) { t.test(file, t => { - r({ - file: resolve(dir, file), - cwd: __dirname, - }, [path.basename(__filename)]).then(() => { + r( + { + file: resolve(dir, file), + cwd: __dirname, + }, + [path.basename(__filename)], + ).then(() => { check(resolve(dir, file), t) }) }) @@ -193,24 +220,44 @@ t.test('cannot append to gzipped archives', async t => { const file = resolve(dir, 'compressed.tgz') const expect = new Error('cannot append to compressed archives') - const expectT = new TypeError('cannot append to compressed archives') - - t.throws(_ => r({ - file, - cwd: __dirname, - gzip: true, - }, [path.basename(__filename)]), expectT) - - t.throws(_ => r({ - file, - cwd: __dirname, - sync: true, - }, [path.basename(__filename)]), expect) - - return r({ - file, - cwd: __dirname, - }, [path.basename(__filename)], er => t.match(er, expect)) + const expectT = new TypeError( + 'cannot append to compressed archives', + ) + + t.throws( + _ => + r( + { + file, + cwd: __dirname, + gzip: true, + }, + [path.basename(__filename)], + ), + expectT, + ) + + t.throws( + _ => + r( + { + file, + cwd: __dirname, + sync: true, + }, + [path.basename(__filename)], + ), + expect, + ) + + return r( + { + file, + cwd: __dirname, + }, + [path.basename(__filename)], + er => t.match(er, expect), + ) }) t.test('cannot append to brotli compressed archives', async t => { @@ -220,27 +267,45 @@ t.test('cannot append to brotli compressed archives', async t => { const file = resolve(dir, 'compressed.tbr') const expect = new Error('cannot append to compressed archives') - const expectT = new TypeError('cannot append to compressed archives') - - t.throws(_ => r({ - file, - cwd: __dirname, - brotli: true, - }, [path.basename(__filename)]), expectT) - - t.throws(_ => r({ - file, - cwd: __dirname, - sync: true, - }, [path.basename(__filename)]), expect) + const expectT = new TypeError( + 'cannot append to compressed archives', + ) + + t.throws( + _ => + r( + { + file, + cwd: __dirname, + brotli: true, + }, + [path.basename(__filename)], + ), + expectT, + ) + + t.throws( + _ => + r( + { + file, + cwd: __dirname, + sync: true, + }, + [path.basename(__filename)], + ), + expect, + ) t.end() }) t.test('other throws', t => { t.throws(_ => r({}, ['asdf']), new TypeError('file is required')) - t.throws(_ => r({ file: 'asdf' }, []), - new TypeError('no files or directories specified')) + t.throws( + _ => r({ file: 'asdf' }, []), + new TypeError('no files or directories specified'), + ) t.end() }) @@ -310,7 +375,10 @@ t.test('mtime cache', async t => { c.on('close', (code, signal) => { t.equal(code, 0) t.equal(signal, null) - const actual = Buffer.concat(out).toString().trim().split(/\r?\n/) + const actual = Buffer.concat(out) + .toString() + .trim() + .split(/\r?\n/) t.same(actual, [ '1024-bytes.txt', '512-bytes.txt', @@ -319,7 +387,9 @@ t.test('mtime cache', async t => { path.basename(__filename), ]) const mtc = {} - mtimeCache.forEach((_v, k) => mtc[k] = mtimeCache.get(k).toISOString()) + mtimeCache.forEach( + (_v, k) => (mtc[k] = mtimeCache.get(k).toISOString()), + ) t.same(mtc, { '1024-bytes.txt': '2017-04-10T16:57:47.000Z', '512-bytes.txt': '2017-04-10T17:08:55.000Z', @@ -333,38 +403,48 @@ t.test('mtime cache', async t => { t.test('sync', t => { const dir = t.testdir(td) const file = resolve(dir, 'body-byte-counts.tar') - r({ - sync: true, - file, - cwd: __dirname, - mtimeCache: mtimeCache = new Map(), - }, [path.basename(__filename)]) + r( + { + sync: true, + file, + cwd: __dirname, + mtimeCache: (mtimeCache = new Map()), + }, + [path.basename(__filename)], + ) check(file, t) }) t.test('async cb', t => { const dir = t.testdir(td) const file = resolve(dir, 'body-byte-counts.tar') - r({ - file, - cwd: __dirname, - mtimeCache: mtimeCache = new Map(), - }, [path.basename(__filename)], er => { - if (er) { - throw er - } - check(file, t) - }) + r( + { + file, + cwd: __dirname, + mtimeCache: (mtimeCache = new Map()), + }, + [path.basename(__filename)], + er => { + if (er) { + throw er + } + check(file, t) + }, + ) }) t.test('async promise', t => { const dir = t.testdir(td) const file = resolve(dir, 'body-byte-counts.tar') - r({ - file, - cwd: __dirname, - mtimeCache: mtimeCache = new Map(), - }, [path.basename(__filename)]).then(_ => check(file, t)) + r( + { + file, + cwd: __dirname, + mtimeCache: (mtimeCache = new Map()), + }, + [path.basename(__filename)], + ).then(_ => check(file, t)) }) t.end() @@ -387,7 +467,8 @@ t.test('create tarball out of another tarball', t => { sync: true, onentry: entry => { t.equal(entry.path, expect.shift()) - } }) + }, + }) t.same(expect, []) t.end() } @@ -395,35 +476,45 @@ t.test('create tarball out of another tarball', t => { t.test('sync', t => { const dir = t.testdir(td) const out = resolve(dir, 'out.tar') - r({ - f: out, - cwd: tars, - sync: true, - }, ['@utf8.tar']) + r( + { + f: out, + cwd: tars, + sync: true, + }, + ['@utf8.tar'], + ) check(out, t) }) t.test('async cb', t => { const dir = t.testdir(td) const out = resolve(dir, 'out.tar') - r({ - f: out, - cwd: tars, - }, ['@utf8.tar'], er => { - if (er) { - throw er - } - check(out, t) - }) + r( + { + f: out, + cwd: tars, + }, + ['@utf8.tar'], + er => { + if (er) { + throw er + } + check(out, t) + }, + ) }) t.test('async', t => { const dir = t.testdir(td) const out = resolve(dir, 'out.tar') - r({ - f: out, - cwd: tars, - }, ['@utf8.tar']).then(() => check(out, t)) + r( + { + f: out, + cwd: tars, + }, + ['@utf8.tar'], + ).then(() => check(out, t)) }) t.end() diff --git a/test/unpack.js b/test/unpack.js index bcffa0c9..d003f5a0 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -2808,8 +2808,9 @@ t.test('trying to unpack a non-zlib gzip file should fail', t => { new Unpack(opts) .once('error', er => t.match(er, expect, 'async emits')) .end(dataGzip) - const skip = !/^v([0-9]|1[0-3])\./.test(process.version) - ? false + const skip = + !/^v([0-9]|1[0-3])\./.test(process.version) ? + false : 'node prior to v14 did not raise sync zlib errors properly' t.throws( () => new UnpackSync(opts).end(dataGzip), diff --git a/test/update.js b/test/update.js index 9fb57b6f..48bdd04b 100644 --- a/test/update.js +++ b/test/update.js @@ -1,12 +1,12 @@ import t from 'tap' import { update as u } from '../dist/esm/update.js' -import path, {dirname} from 'path' +import path, { dirname } from 'path' import fs from 'fs' import mutateFS from 'mutate-fs' import { resolve } from 'path' -import {fileURLToPath} from 'url' +import { fileURLToPath } from 'url' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) const fixtures = path.resolve(__dirname, 'fixtures') @@ -14,14 +14,19 @@ const tars = path.resolve(fixtures, 'tars') import zlib from 'zlib' import { spawn } from 'child_process' - const data = fs.readFileSync(tars + '/body-byte-counts.tar') const dataNoNulls = data.subarray(0, data.length - 1024) const fixtureDef = { 'body-byte-counts.tar': data, 'no-null-eof.tar': dataNoNulls, - 'truncated-head.tar': Buffer.concat([dataNoNulls, data.subarray(0, 500)]), - 'truncated-body.tar': Buffer.concat([dataNoNulls, data.subarray(0, 700)]), + 'truncated-head.tar': Buffer.concat([ + dataNoNulls, + data.subarray(0, 500), + ]), + 'truncated-body.tar': Buffer.concat([ + dataNoNulls, + data.subarray(0, 700), + ]), 'zero.tar': Buffer.from(''), 'empty.tar': Buffer.alloc(512), 'compressed.tgz': zlib.gzipSync(data), @@ -36,7 +41,10 @@ t.test('basic file add to archive (good or truncated)', t => { c.on('close', (code, signal) => { t.equal(code, 0) t.equal(signal, null) - const actual = Buffer.concat(out).toString().trim().split(/\r?\n/) + const actual = Buffer.concat(out) + .toString() + .trim() + .split(/\r?\n/) t.same(actual, [ '1024-bytes.txt', '512-bytes.txt', @@ -54,21 +62,26 @@ t.test('basic file add to archive (good or truncated)', t => { 'truncated-head.tar', 'truncated-body.tar', ] - const td = files.map(f => [f, fixtureDef[f]]).reduce((s, [k, v]) => { - s[k] = v - return s - }, {}) + const td = files + .map(f => [f, fixtureDef[f]]) + .reduce((s, [k, v]) => { + s[k] = v + return s + }, {}) const fileList = [path.basename(__filename)] t.test('sync', t => { t.plan(files.length) const dir = t.testdir(td) for (const file of files) { t.test(file, t => { - u({ - sync: true, - file: resolve(dir, file), - cwd: __dirname, - }, fileList) + u( + { + sync: true, + file: resolve(dir, file), + cwd: __dirname, + }, + fileList, + ) check(resolve(dir, file), t) }) } @@ -79,15 +92,19 @@ t.test('basic file add to archive (good or truncated)', t => { const dir = t.testdir(td) for (const file of files) { t.test(file, t => { - u({ - file: resolve(dir, file), - cwd: __dirname, - }, fileList, er => { - if (er) { - throw er - } - check(resolve(dir, file), t) - }) + u( + { + file: resolve(dir, file), + cwd: __dirname, + }, + fileList, + er => { + if (er) { + throw er + } + check(resolve(dir, file), t) + }, + ) }) } }) @@ -97,10 +114,13 @@ t.test('basic file add to archive (good or truncated)', t => { const dir = t.testdir(td) for (const file of files) { t.test(file, t => { - u({ - file: resolve(dir, file), - cwd: __dirname, - }, fileList).then(() => { + u( + { + file: resolve(dir, file), + cwd: __dirname, + }, + fileList, + ).then(() => { check(resolve(dir, file), t) }) }) @@ -118,22 +138,22 @@ t.test('add to empty archive', t => { c.on('close', (code, signal) => { t.equal(code, 0) t.equal(signal, null) - const actual = Buffer.concat(out).toString().trim().split(/\r?\n/) - t.same(actual, [ - path.basename(__filename), - ]) + const actual = Buffer.concat(out) + .toString() + .trim() + .split(/\r?\n/) + t.same(actual, [path.basename(__filename)]) t.end() }) } - const files = [ - 'empty.tar', - 'zero.tar', - ] - const td = files.map(f => [f, fixtureDef[f]]).reduce((s, [k, v]) => { - s[k] = v - return s - }, {}) + const files = ['empty.tar', 'zero.tar'] + const td = files + .map(f => [f, fixtureDef[f]]) + .reduce((s, [k, v]) => { + s[k] = v + return s + }, {}) files.push('not-existing.tar') t.test('sync', t => { @@ -141,11 +161,14 @@ t.test('add to empty archive', t => { t.plan(files.length) for (const file of files) { t.test(file, t => { - u({ - sync: true, - file: resolve(dir, file), - cwd: __dirname, - }, [path.basename(__filename)]) + u( + { + sync: true, + file: resolve(dir, file), + cwd: __dirname, + }, + [path.basename(__filename)], + ) check(resolve(dir, file), t) }) } @@ -156,15 +179,19 @@ t.test('add to empty archive', t => { t.plan(files.length) for (const file of files) { t.test(file, t => { - u({ - file: resolve(dir, file), - cwd: __dirname, - }, [path.basename(__filename)], er => { - if (er) { - throw er - } - check(resolve(dir, file), t) - }) + u( + { + file: resolve(dir, file), + cwd: __dirname, + }, + [path.basename(__filename)], + er => { + if (er) { + throw er + } + check(resolve(dir, file), t) + }, + ) }) } }) @@ -174,10 +201,13 @@ t.test('add to empty archive', t => { t.plan(files.length) for (const file of files) { t.test(file, t => { - u({ - file: resolve(dir, file), - cwd: __dirname, - }, [path.basename(__filename)]).then(() => { + u( + { + file: resolve(dir, file), + cwd: __dirname, + }, + [path.basename(__filename)], + ).then(() => { check(resolve(dir, file), t) }) }) @@ -194,27 +224,47 @@ t.test('cannot append to gzipped archives', t => { const file = resolve(dir, 'compressed.tgz') const expect = new Error('cannot append to compressed archives') - const expectT = new TypeError('cannot append to compressed archives') - - t.throws(_ => u({ - file, - cwd: __dirname, - gzip: true, - }, [path.basename(__filename)]), expectT) - - t.throws(_ => u({ - file, - cwd: __dirname, - sync: true, - }, [path.basename(__filename)]), expect) - - u({ - file, - cwd: __dirname, - }, [path.basename(__filename)], er => { - t.match(er, expect) - t.end() - }) + const expectT = new TypeError( + 'cannot append to compressed archives', + ) + + t.throws( + _ => + u( + { + file, + cwd: __dirname, + gzip: true, + }, + [path.basename(__filename)], + ), + expectT, + ) + + t.throws( + _ => + u( + { + file, + cwd: __dirname, + sync: true, + }, + [path.basename(__filename)], + ), + expect, + ) + + u( + { + file, + cwd: __dirname, + }, + [path.basename(__filename)], + er => { + t.match(er, expect) + t.end() + }, + ) }) t.test('cannot append to brotli archives', t => { @@ -224,27 +274,45 @@ t.test('cannot append to brotli archives', t => { const file = resolve(dir, 'compressed.tbr') const expect = new Error('cannot append to compressed archives') - const expectT = new TypeError('cannot append to compressed archives') - - t.throws(_ => u({ - file, - cwd: __dirname, - brotli: true, - }, [path.basename(__filename)]), expectT) - - t.throws(_ => u({ - file, - cwd: __dirname, - sync: true, - }, [path.basename(__filename)]), expect) + const expectT = new TypeError( + 'cannot append to compressed archives', + ) + + t.throws( + _ => + u( + { + file, + cwd: __dirname, + brotli: true, + }, + [path.basename(__filename)], + ), + expectT, + ) + + t.throws( + _ => + u( + { + file, + cwd: __dirname, + sync: true, + }, + [path.basename(__filename)], + ), + expect, + ) t.end() }) t.test('other throws', t => { t.throws(_ => u({}, ['asdf']), new TypeError('file is required')) - t.throws(_ => u({ file: 'asdf' }, []), - new TypeError('no files or directories specified')) + t.throws( + _ => u({ file: 'asdf' }, []), + new TypeError('no files or directories specified'), + ) t.end() }) @@ -320,13 +388,16 @@ t.test('do not add older file', t => { } t.test('sync', t => { - u({ - mtimeCache: new Map(), - file, - cwd: dir, - sync: true, - filter: path => path === '1024-bytes.txt', - }, ['1024-bytes.txt', 'foo']) + u( + { + mtimeCache: new Map(), + file, + cwd: dir, + sync: true, + filter: path => path === '1024-bytes.txt', + }, + ['1024-bytes.txt', 'foo'], + ) check(t) }) @@ -361,7 +432,8 @@ t.test('do add newer file', t => { } // a chunk for the header, then 2 for the body - const expect = fixtureDef['body-byte-counts.tar'].length + 512 + 1024 + const expect = + fixtureDef['body-byte-counts.tar'].length + 512 + 1024 const check = (file, t) => { t.equal(fs.statSync(file).size, expect) t.end() @@ -370,20 +442,25 @@ t.test('do add newer file', t => { t.test('sync', t => { const dir = setup(t) const file = resolve(dir, 'body-byte-counts.tar') - u({ - mtimeCache: new Map(), - file, - cwd: dir, - sync: true, - filter: path => path === '1024-bytes.txt', - }, ['1024-bytes.txt', 'foo']) + u( + { + mtimeCache: new Map(), + file, + cwd: dir, + sync: true, + filter: path => path === '1024-bytes.txt', + }, + ['1024-bytes.txt', 'foo'], + ) check(file, t) }) t.test('async', t => { const dir = setup(t) const file = resolve(dir, 'body-byte-counts.tar') - u({ file, cwd: dir }, ['1024-bytes.txt']).then(_ => check(file, t)) + u({ file, cwd: dir }, ['1024-bytes.txt']).then(_ => + check(file, t), + ) }) t.test('async cb', t => { diff --git a/test/warn-method.js b/test/warn-method.js index 4d040f42..7b04ff86 100644 --- a/test/warn-method.js +++ b/test/warn-method.js @@ -8,7 +8,6 @@ class Warner extends EE { } } - const w = new Warner() t.type(w.warn, 'function') @@ -21,14 +20,20 @@ t.same(warning, ['code', 'hello', { tarCode: 'code', code: 'code' }]) warning.length = 0 w.once('warn', (code, msg, data) => warning.push(code, msg, data)) w.warn('ok', new Error('this is fine'), { foo: 'bar' }) -t.match(warning, ['ok', 'this is fine', { - message: 'this is fine', - foo: 'bar', -}]) +t.match(warning, [ + 'ok', + 'this is fine', + { + message: 'this is fine', + foo: 'bar', + }, +]) w.strict = true -t.throws(_ => w.warn('code', 'hello', { data: 123 }), - { message: 'hello', data: 123 }) +t.throws(_ => w.warn('code', 'hello', { data: 123 }), { + message: 'hello', + data: 123, +}) const poop = new Error('poop') t.throws(_ => w.warn('ok', poop), poop) @@ -38,5 +43,7 @@ w.cwd = 'some/dir' t.throws(_ => w.warn('ok', 'this is fine'), { cwd: 'some/dir' }) w.strict = false -t.throws(_ => w.warn('ok', 'this is fine', { recoverable: false }), - { cwd: 'some/dir', recoverable: false }) +t.throws(_ => w.warn('ok', 'this is fine', { recoverable: false }), { + cwd: 'some/dir', + recoverable: false, +}) diff --git a/test/write-entry.js b/test/write-entry.js index 27bd364c..7bd8aae6 100644 --- a/test/write-entry.js +++ b/test/write-entry.js @@ -417,7 +417,7 @@ t.test('absolute path', t => { const { root } = path.parse(absolute) const f = root + root + root + absolute const warn = normPath(isWindows ? root : root + root + root + root) - t.test('preservePaths=false strict=false warn='+warn, t => { + t.test('preservePaths=false strict=false warn=' + warn, t => { const warnings = [] // on windows, c:\c:\c:\... is a valid path, so just use the // single-root absolute version of it. @@ -542,7 +542,7 @@ t.test( }, t => { const ws = new WriteEntry('/dev/random', { preservePaths: true }) - ws.on('data', (_chunk) => { + ws.on('data', _chunk => { throw new Error('should not get data from random') }) ws.on('stat', stat => { @@ -1350,7 +1350,10 @@ t.test('prefix and hard links', t => { const data = Buffer.concat(out) expect.forEach((e, i) => { if (typeof e === 'string') { - t.equal(data.subarray(i * 512, i * 512 + e.length).toString(), e) + t.equal( + data.subarray(i * 512, i * 512 + e.length).toString(), + e, + ) } else if (e instanceof RegExp) { t.match(data.subarray(i * 512, (i + 1) * 512).toString(), e) } else { @@ -1527,7 +1530,10 @@ t.test('prefix and hard links from tar entries', t => { const data = Buffer.concat(out) expect.forEach((e, i) => { if (typeof e === 'string') { - t.equal(data.subarray(i * 512, i * 512 + e.length).toString(), e) + t.equal( + data.subarray(i * 512, i * 512 + e.length).toString(), + e, + ) } else if (e instanceof RegExp) { t.match(data.subarray(i * 512, (i + 1) * 512).toString(), e) } else { @@ -1622,7 +1628,10 @@ t.test('hard links and no prefix', t => { const data = Buffer.concat(out) expect.forEach((e, i) => { if (typeof e === 'string') { - t.equal(data.subarray(i * 512, i * 512 + e.length).toString(), e) + t.equal( + data.subarray(i * 512, i * 512 + e.length).toString(), + e, + ) } else { t.match(new Header(data.subarray(i * 512, (i + 1) * 512)), e) } @@ -1768,7 +1777,10 @@ t.test('hard links from tar entries and no prefix', t => { const data = Buffer.concat(out) expect.forEach((e, i) => { if (typeof e === 'string') { - t.equal(data.subarray(i * 512, i * 512 + e.length).toString(), e) + t.equal( + data.subarray(i * 512, i * 512 + e.length).toString(), + e, + ) } else if (e instanceof RegExp) { t.match(data.subarray(i * 512, (i + 1) * 512).toString(), e) } else { From 79a5c30d7bd836eee0751e2ec6c838767a70ecad Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Fri, 3 May 2024 12:17:07 -0700 Subject: [PATCH 77/96] update minipass This got overlooked in the previous update, and should address some of the portability and extension challenges with various event types. --- package.json | 2 +- src/pack.ts | 6 +++++- src/warn-method.ts | 6 ++++++ src/write-entry.ts | 20 ++++++++++++++++---- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index f1321305..6705d89a 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", - "minipass": "^5.0.0", + "minipass": "^7.0.4", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" diff --git a/src/pack.ts b/src/pack.ts index 07d6500f..1ad0a9c5 100644 --- a/src/pack.ts +++ b/src/pack.ts @@ -35,6 +35,7 @@ import * as zlib from 'minizlib' import { Yallist } from 'yallist' import { ReadEntry } from './read-entry.js' import { + WarnEvent, warnMethod, type WarnData, type Warner, @@ -66,7 +67,10 @@ import path from 'path' import { normalizeWindowsPath } from './normalize-windows-path.js' import { TarOptions } from './options.js' -export class Pack extends Minipass implements Warner { +export class Pack + extends Minipass<Minipass.ContiguousData, Buffer, WarnEvent> + implements Warner +{ opt: TarOptions cwd: string maxReadSize?: number diff --git a/src/warn-method.ts b/src/warn-method.ts index 7f2b83e1..d308edb0 100644 --- a/src/warn-method.ts +++ b/src/warn-method.ts @@ -1,3 +1,5 @@ +import { type Minipass } from 'minipass' + /** has a warn method */ export type Warner = { warn(code: string, message: string | Error, data: any): void @@ -14,6 +16,10 @@ export type Warner = { emit(event: 'error', error: TarError): void } +export type WarnEvent = Minipass.Events & { + warn: [code: string, message: string, data: WarnData] +} + export type WarnData = { file?: string cwd?: string diff --git a/src/write-entry.ts b/src/write-entry.ts index c528cf8a..714faeb0 100644 --- a/src/write-entry.ts +++ b/src/write-entry.ts @@ -15,7 +15,12 @@ import { ReadEntry } from './read-entry.js' import { stripAbsolutePath } from './strip-absolute-path.js' import { stripTrailingSlashes } from './strip-trailing-slashes.js' import { EntryTypeName } from './types.js' -import { WarnData, Warner, warnMethod } from './warn-method.js' +import { + WarnData, + Warner, + WarnEvent, + warnMethod, +} from './warn-method.js' import * as winchars from './winchars.js' const prefixPath = (path: string, prefix?: string) => { @@ -47,7 +52,14 @@ const AWAITDRAIN = Symbol('awaitDrain') const ONDRAIN = Symbol('ondrain') const PREFIX = Symbol('prefix') -export class WriteEntry extends Minipass<Buffer> implements Warner { +export class WriteEntry + extends Minipass< + Minipass.ContiguousData, + Buffer, + WarnEvent + > + implements Warner +{ path: string portable: boolean myuid: number = (process.getuid && process.getuid()) || 0 @@ -154,7 +166,7 @@ export class WriteEntry extends Minipass<Buffer> implements Warner { return warnMethod(this, code, message, data) } - emit(ev: string, ...data: any[]) { + emit(ev: keyof WarnEvent, ...data: any[]) { if (ev === 'error') { this.#hadError = true } @@ -556,7 +568,7 @@ export class WriteEntrySync extends WriteEntry implements Warner { } export class WriteEntryTar - extends Minipass<Buffer> + extends Minipass<Buffer, Buffer, WarnEvent> implements Warner { blockLen: number = 0 From 6b61030dacb86eb22f1935b73b6aa09cd2ddc208 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Fri, 3 May 2024 19:04:18 -0700 Subject: [PATCH 78/96] update types to comply with NodeJS.WritableStream Fix: #409 --- CHANGELOG.md | 8 +++ package.json | 5 +- src/parse.ts | 62 +++++++++++++++-- src/write-entry.ts | 106 +++++++++++++++++++++++++----- test/parse.js | 11 ++-- test/writable-assignment-check.ts | 14 ++++ 6 files changed, 180 insertions(+), 26 deletions(-) create mode 100644 test/writable-assignment-check.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 85ae0acb..bbe69803 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 7.1 + +- Update minipass to v7.1.0 +- Update the type definitions of `write()` and `end()` methods on + `Unpack` and `Parser` classes to be compatible with the + NodeJS.WritableStream type in the latest versions of + `@types/node`. + ## 7.0 - Rewrite in TypeScript, provide ESM and CommonJS hybrid diff --git a/package.json b/package.json index 6705d89a..d5d7ecf0 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", - "minipass": "^7.0.4", + "minipass": "^7.1.0", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" @@ -49,7 +49,8 @@ ], "tap": { "coverage-map": "map.js", - "timeout": 0 + "timeout": 0, + "typecheck": true }, "prettier": { "experimentalTernaries": true, diff --git a/src/parse.ts b/src/parse.ts index f260568d..a4afeee0 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -402,9 +402,35 @@ export class Parser extends EE implements Warner { this.warn('TAR_ABORT', error, { recoverable: false }) } - write(chunk: Buffer) { + write( + buffer: Uint8Array | string, + cb?: (err?: Error | null) => void, + ): boolean + write( + str: string, + encoding?: BufferEncoding, + cb?: (err?: Error | null) => void, + ): boolean + write( + chunk: Buffer | string, + encoding?: BufferEncoding | (() => any), + cb?: () => any, + ): boolean { + if (typeof encoding === 'function') { + cb = encoding + encoding = undefined + } + if (typeof chunk === 'string') { + chunk = Buffer.from( + chunk, + /* c8 ignore next */ + typeof encoding === 'string' ? encoding : 'utf8', + ) + } if (this[ABORTED]) { - return + /* c8 ignore next */ + cb?.() + return false } // first write, might be gzipped @@ -418,6 +444,8 @@ export class Parser extends EE implements Warner { } if (chunk.length < gzipHeader.length) { this[BUFFER] = chunk + /* c8 ignore next */ + cb?.() return true } @@ -443,6 +471,8 @@ export class Parser extends EE implements Warner { this.brotli = true } else { this[BUFFER] = chunk + /* c8 ignore next */ + cb?.() return true } } else { @@ -474,8 +504,9 @@ export class Parser extends EE implements Warner { this[CONSUMECHUNK]() }) this[WRITING] = true - const ret = this[UNZIP][ended ? 'end' : 'write'](chunk) + const ret = !!this[UNZIP][ended ? 'end' : 'write'](chunk) this[WRITING] = false + cb?.() return ret } } @@ -499,6 +530,8 @@ export class Parser extends EE implements Warner { this[READENTRY]?.once('drain', () => this.emit('drain')) } + /* c8 ignore next */ + cb?.() return ret } @@ -614,7 +647,27 @@ export class Parser extends EE implements Warner { } } - end(chunk?: Buffer) { + end(cb?: () => void): this + end(data: string | Buffer, cb?: () => void): this + end(str: string, encoding?: BufferEncoding, cb?: () => void): this + end( + chunk?: string | Buffer | (() => void), + encoding?: BufferEncoding | (() => void), + cb?: () => void, + ) { + if (typeof chunk === 'function') { + cb = chunk + encoding = undefined + chunk = undefined + } + if (typeof encoding === 'function') { + cb = encoding + encoding = undefined + } + if (typeof chunk === 'string') { + chunk = Buffer.from(chunk, encoding) + } + if (cb) this.once('finish', cb) if (!this[ABORTED]) { if (this[UNZIP]) { /* c8 ignore start */ @@ -629,5 +682,6 @@ export class Parser extends EE implements Warner { this[MAYBEEND]() } } + return this } } diff --git a/src/write-entry.ts b/src/write-entry.ts index 714faeb0..cfb797a4 100644 --- a/src/write-entry.ts +++ b/src/write-entry.ts @@ -54,8 +54,8 @@ const PREFIX = Symbol('prefix') export class WriteEntry extends Minipass< - Minipass.ContiguousData, Buffer, + Minipass.ContiguousData, WarnEvent > implements Warner @@ -454,12 +454,12 @@ export class WriteEntry } } - const writeBuf = + const chunk = this.offset === 0 && bytesRead === this.buf.length ? this.buf : this.buf.subarray(this.offset, this.offset + bytesRead) - const flushed = this.write(writeBuf) + const flushed = this.write(chunk) if (!flushed) { this[AWAITDRAIN](() => this[ONDRAIN]()) } else { @@ -471,8 +471,34 @@ export class WriteEntry this.once('drain', cb) } - write(writeBuf: Buffer) { - if (this.blockRemain < writeBuf.length) { + write( + buffer: Buffer | string, + cb?: () => void, + ): boolean + write( + str: Buffer | string, + encoding?: BufferEncoding | null, + cb?: () => void, + ): boolean + write( + chunk: Buffer | string, + encoding?: BufferEncoding | (() => any) | null, + cb?: () => any, + ): boolean { + /* c8 ignore start - just junk to comply with NodeJS.WritableStream */ + if (typeof encoding === 'function') { + cb = encoding + encoding = undefined + } + if (typeof chunk === 'string') { + chunk = Buffer.from( + chunk, + typeof encoding === 'string' ? encoding : 'utf8', + ) + } + /* c8 ignore stop */ + + if (this.blockRemain < chunk.length) { const er = Object.assign( new Error('writing more data than expected'), { @@ -481,11 +507,11 @@ export class WriteEntry ) return this.emit('error', er) } - this.remain -= writeBuf.length - this.blockRemain -= writeBuf.length - this.pos += writeBuf.length - this.offset += writeBuf.length - return super.write(writeBuf) + this.remain -= chunk.length + this.blockRemain -= chunk.length + this.pos += chunk.length + this.offset += chunk.length + return super.write(chunk, null, cb) } [ONDRAIN]() { @@ -568,7 +594,7 @@ export class WriteEntrySync extends WriteEntry implements Warner { } export class WriteEntryTar - extends Minipass<Buffer, Buffer, WarnEvent> + extends Minipass<Buffer, Buffer | string, WarnEvent> implements Warner { blockLen: number = 0 @@ -731,20 +757,68 @@ export class WriteEntryTar return modeFix(mode, this.type === 'Directory', this.portable) } - write(data: Buffer) { - const writeLen = data.length + write( + buffer: Buffer | string, + cb?: () => void, + ): boolean + write( + str: Buffer | string, + encoding?: BufferEncoding | null, + cb?: () => void, + ): boolean + write( + chunk: Buffer | string, + encoding?: BufferEncoding | (() => any) | null, + cb?: () => any, + ): boolean { + /* c8 ignore start - just junk to comply with NodeJS.WritableStream */ + if (typeof encoding === 'function') { + cb = encoding + encoding = undefined + } + if (typeof chunk === 'string') { + chunk = Buffer.from( + chunk, + typeof encoding === 'string' ? encoding : 'utf8', + ) + } + /* c8 ignore stop */ + const writeLen = chunk.length if (writeLen > this.blockRemain) { throw new Error('writing more to entry than is appropriate') } this.blockRemain -= writeLen - return super.write(data) + return super.write(chunk, cb) } - end() { + end(cb?: () => void): this + end(chunk: Buffer | string, cb?: () => void): this + end(chunk: Buffer | string, encoding?: BufferEncoding, cb?: () => void): this + end( + chunk?: Buffer | string | (() => void), + encoding?: BufferEncoding | (() => void), + cb?: () => void + ): this { if (this.blockRemain) { super.write(Buffer.alloc(this.blockRemain)) } - return super.end() + /* c8 ignore start - just junk to comply with NodeJS.WritableStream */ + if (typeof chunk === 'function') { + cb = chunk + encoding = undefined + chunk = undefined + } + if (typeof encoding === 'function') { + cb = encoding + encoding = undefined + } + if (typeof chunk === 'string') { + chunk = Buffer.from(chunk, encoding ?? 'utf8') + } + if (cb) this.once('finish', cb) + chunk ? super.end(chunk, cb) : super.end(cb) + /* c8 ignore stop */ + return this } } diff --git a/test/parse.js b/test/parse.js index db60ce0c..978caacd 100644 --- a/test/parse.js +++ b/test/parse.js @@ -126,6 +126,7 @@ t.test('fixture tests', t => { }) t.test('uncompressed all at once', t => { + // this one writes it as a string const p = new Parser({ maxMetaEntrySize: maxMeta, filter: @@ -135,7 +136,7 @@ t.test('fixture tests', t => { strict: strict, }) trackEvents(t, expect, p) - p.end(tardata) + p.end(tardata.toString('hex'), 'hex', () => {}) }) t.test( @@ -185,7 +186,7 @@ t.test('fixture tests', t => { strict: strict, }) trackEvents(t, expect, p) - p.end(zlib.gzipSync(tardata)) + p.end(zlib.gzipSync(tardata), () => {}) }) t.test('gzipped all at once, filename .tbr', t => { @@ -199,7 +200,8 @@ t.test('fixture tests', t => { file: 'example.tbr', }) trackEvents(t, expect, p) - p.end(zlib.gzipSync(tardata)) + p.write(zlib.gzipSync(tardata), () => {}) + p.end(() => {}) }) t.test('gzipped byte at a time', t => { @@ -304,7 +306,8 @@ t.test('fixture tests', t => { strict: strict, }) trackEvents(t, expect, p, true) - p.write(tardata.subarray(0, Math.floor(tardata.length / 2))) + const first = tardata.subarray(0, Math.floor(tardata.length / 2)) + p.write(first.toString('hex'), 'hex') process.nextTick(() => p.end(tardata.subarray(Math.floor(tardata.length / 2))), ) diff --git a/test/writable-assignment-check.ts b/test/writable-assignment-check.ts new file mode 100644 index 00000000..46e81595 --- /dev/null +++ b/test/writable-assignment-check.ts @@ -0,0 +1,14 @@ +import { Unpack } from "../src/unpack.js"; +import { WriteEntry } from "../src/write-entry.js"; +import { Parser } from '../src/parse.js' +import { fileURLToPath } from 'url' + +let tester: NodeJS.WritableStream +tester = new Parser() +tester = new Unpack() +tester = new WriteEntry(fileURLToPath(import.meta.url)) + +tester + +import { pass } from 'tap' +pass(`just making sure TS doesn't complain`) From ce612d0aa818f93a133a5f76e14fe6eef2abb12f Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Fri, 3 May 2024 19:06:38 -0700 Subject: [PATCH 79/96] 7.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d5d7ecf0..ce6b7785 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "7.0.1", + "version": "7.1.0", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From 3062616846dffb94e967b16e0bc93529713b5750 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 29 May 2024 17:02:29 -0700 Subject: [PATCH 80/96] DRY all commands, correct overload signature types This moves the repetitive overload definitions into a single type created by a makeCommand method. This also means that all of the repetitive setup and validation can be moved to one place as well. Corrects a bug where TS thought that a `Promise<void>` would be returned, which actually it was an instance of Unpack (or whatever). The type calculus is rather baroque. The next major will replace the overloaded function signatures with separately named functions, so there'll be `createFile`, `createSync`, `createFileSync`, etc. --- src/create.ts | 100 +++--------- src/extract.ts | 132 ++-------------- src/index.ts | 35 +++-- src/list.ts | 96 ++---------- src/make-command.ts | 246 ++++++++++++++++++++++++++++++ src/options.ts | 58 +++++-- src/pack.ts | 1 + src/replace.ts | 86 +++++------ src/unpack.ts | 2 + src/update.ts | 47 ++---- src/write-entry.ts | 26 ++-- test/{create.js => create.ts} | 43 ++++-- test/{extract.js => extract.ts} | 164 +++++++++++++------- test/{list.js => list.ts} | 85 ++++++----- test/make-command.ts | 74 +++++++++ test/options.js | 11 ++ test/parse.js | 5 +- test/{replace.js => replace.ts} | 66 ++++---- test/update.js | 2 +- test/writable-assignment-check.ts | 4 +- 20 files changed, 743 insertions(+), 540 deletions(-) create mode 100644 src/make-command.ts rename test/{create.js => create.ts} (87%) rename test/{extract.js => extract.ts} (73%) rename test/{list.js => list.ts} (76%) create mode 100644 test/make-command.ts rename test/{replace.js => replace.ts} (89%) diff --git a/src/create.ts b/src/create.ts index 33af4b31..b3fc260e 100644 --- a/src/create.ts +++ b/src/create.ts @@ -1,84 +1,16 @@ +import { WriteStream, WriteStreamSync } from '@isaacs/fs-minipass' +import { Minipass } from 'minipass' +import path from 'node:path' +import { list } from './list.js' +import { makeCommand } from './make-command.js' import { - dealias, - isFile, - isSync, - isSyncFile, TarOptions, TarOptionsFile, TarOptionsSync, TarOptionsSyncFile, - TarOptionsWithAliases, - TarOptionsWithAliasesFile, - TarOptionsWithAliasesSync, - TarOptionsWithAliasesSyncFile, } from './options.js' - -import { WriteStream, WriteStreamSync } from '@isaacs/fs-minipass' -import { Minipass } from 'minipass' -import path from 'node:path' -import { list } from './list.js' import { Pack, PackSync } from './pack.js' -export function create( - opt: TarOptionsWithAliasesSyncFile, - files?: string[], -): void -export function create( - opt: TarOptionsWithAliasesSync, - files?: string[], -): void -export function create( - opt: TarOptionsWithAliasesFile, - files?: string[], - cb?: () => any, -): Promise<void> -export function create( - opt: TarOptionsWithAliasesFile, - cb: () => any, -): Promise<void> -export function create( - opt: TarOptionsWithAliases, - files?: string[], -): Pack -export function create( - opt_: TarOptionsWithAliases, - files?: string[] | (() => any), - cb?: () => any, -): void | Promise<void> | Pack { - if (typeof files === 'function') { - cb = files - } - - if (Array.isArray(opt_)) { - ;(files = opt_), (opt_ = {}) - } - - if (!files || !Array.isArray(files) || !files.length) { - throw new TypeError('no files or directories specified') - } - - files = Array.from(files) - - const opt = dealias(opt_) - - if (opt.sync && typeof cb === 'function') { - throw new TypeError( - 'callback not supported for sync tar functions', - ) - } - - if (!opt.file && typeof cb === 'function') { - throw new TypeError('callback only supported with file option') - } - - return ( - isSyncFile(opt) ? createFileSync(opt, files) - : isFile(opt) ? createFile(opt, files, cb) - : isSync(opt) ? createSync(opt, files) - : create_(opt, files) - ) -} - const createFileSync = (opt: TarOptionsSyncFile, files: string[]) => { const p = new PackSync(opt) const stream = new WriteStreamSync(opt.file, { @@ -88,11 +20,7 @@ const createFileSync = (opt: TarOptionsSyncFile, files: string[]) => { addFilesSync(p, files) } -const createFile = ( - opt: TarOptionsFile, - files: string[], - cb?: () => any, -) => { +const createFile = (opt: TarOptionsFile, files: string[]) => { const p = new Pack(opt) const stream = new WriteStream(opt.file, { mode: opt.mode || 0o666, @@ -107,7 +35,7 @@ const createFile = ( addFilesAsync(p, files) - return cb ? promise.then(cb, cb) : promise + return promise } const addFilesSync = (p: PackSync, files: string[]) => { @@ -153,8 +81,20 @@ const createSync = (opt: TarOptionsSync, files: string[]) => { return p } -const create_ = (opt: TarOptions, files: string[]) => { +const createAsync = (opt: TarOptions, files: string[]) => { const p = new Pack(opt) addFilesAsync(p, files) return p } + +export const create = makeCommand( + createFileSync, + createFile, + createSync, + createAsync, + (_opt, files) => { + if (!files?.length) { + throw new TypeError('no paths specified to add to archive') + } + }, +) diff --git a/src/extract.ts b/src/extract.ts index 35dc4946..85a5bcdf 100644 --- a/src/extract.ts +++ b/src/extract.ts @@ -1,123 +1,13 @@ // tar -x import * as fsm from '@isaacs/fs-minipass' import fs from 'node:fs' -import { dirname, parse } from 'node:path' -import { - dealias, - isFile, - isSync, - isSyncFile, - TarOptions, - TarOptionsFile, - TarOptionsSync, - TarOptionsSyncFile, - TarOptionsWithAliases, - TarOptionsWithAliasesFile, - TarOptionsWithAliasesSync, - TarOptionsWithAliasesSyncFile, -} from './options.js' -import { stripTrailingSlashes } from './strip-trailing-slashes.js' +import { filesFilter } from './list.js' +import { makeCommand } from './make-command.js' +import { TarOptionsFile, TarOptionsSyncFile } from './options.js' import { Unpack, UnpackSync } from './unpack.js' -export function extract( - opt: TarOptionsWithAliasesSyncFile, - files?: string[], -): void -export function extract( - opt: TarOptionsWithAliasesSync, - files?: string[], -): void -export function extract( - opt: TarOptionsWithAliasesFile, - files?: string[], - cb?: () => any, -): Promise<void> -export function extract( - opt: TarOptionsWithAliasesFile, - cb: () => any, -): Promise<void> -export function extract( - opt: TarOptionsWithAliases, - files?: string[], -): Unpack -export function extract( - opt_: TarOptionsWithAliases, - files?: string[] | (() => any), - cb?: () => any, -): void | Promise<void> | Unpack { - if (typeof opt_ === 'function') { - ;(cb = opt_), (files = undefined), (opt_ = {}) - } else if (Array.isArray(opt_)) { - ;(files = opt_), (opt_ = {}) - } - - if (typeof files === 'function') { - ;(cb = files), (files = undefined) - } - - if (!files) { - files = [] - } else { - files = Array.from(files) - } - - const opt = dealias(opt_) - - if (opt.sync && typeof cb === 'function') { - throw new TypeError( - 'callback not supported for sync tar functions', - ) - } - - if (!opt.file && typeof cb === 'function') { - throw new TypeError('callback only supported with file option') - } - - if (files.length) { - filesFilter(opt, files) - } - - return ( - isSyncFile(opt) ? extractFileSync(opt) - : isFile(opt) ? extractFile(opt, cb) - : isSync(opt) ? extractSync(opt) - : extract_(opt) - ) -} - -// construct a filter that limits the file entries listed -// include child entries if a dir is included -const filesFilter = (opt: TarOptions, files: string[]) => { - const map = new Map(files.map(f => [stripTrailingSlashes(f), true])) - const filter = opt.filter - - const mapHas = (file: string, r: string = ''): boolean => { - const root = r || parse(file).root || '.' - let ret: boolean - if (file === root) ret = false - else { - const m = map.get(file) - if (m !== undefined) { - ret = m - } else { - ret = mapHas(dirname(file), root) - } - } - - map.set(file, ret) - return ret - } - - opt.filter = - filter ? - (file, entry) => - filter(file, entry) && mapHas(stripTrailingSlashes(file)) - : file => mapHas(stripTrailingSlashes(file)) -} - const extractFileSync = (opt: TarOptionsSyncFile) => { const u = new UnpackSync(opt) - const file = opt.file const stat = fs.statSync(file) // This trades a zero-byte read() syscall for a stat @@ -130,7 +20,7 @@ const extractFileSync = (opt: TarOptionsSyncFile) => { stream.pipe(u) } -const extractFile = (opt: TarOptionsFile, cb?: () => void) => { +const extractFile = (opt: TarOptionsFile, _?: string[]) => { const u = new Unpack(opt) const readSize = opt.maxReadSize || 16 * 1024 * 1024 @@ -154,9 +44,15 @@ const extractFile = (opt: TarOptionsFile, cb?: () => void) => { } }) }) - return cb ? p.then(cb, cb) : p + return p } -const extractSync = (opt: TarOptionsSync) => new UnpackSync(opt) - -const extract_ = (opt: TarOptions) => new Unpack(opt) +export const extract = makeCommand<Unpack, UnpackSync>( + extractFileSync, + extractFile, + opt => new UnpackSync(opt), + opt => new Unpack(opt), + (opt, files) => { + if (files?.length) filesFilter(opt, files) + }, +) diff --git a/src/index.ts b/src/index.ts index bc2c67fe..f19166e8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,21 +1,30 @@ -export * from './create.js' -export * from './replace.js' -export * from './list.js' -export * from './update.js' -export * from './extract.js' +export { + type TarOptionsWithAliasesAsync, + type TarOptionsWithAliasesAsyncFile, + type TarOptionsWithAliasesAsyncNoFile, + type TarOptionsWithAliasesSyncNoFile, + type TarOptionsWithAliases, + type TarOptionsWithAliasesFile, + type TarOptionsWithAliasesSync, + type TarOptionsWithAliasesSyncFile, +} from './options.js' +export * from './create.js' export { create as c } from './create.js' -export { replace as r } from './replace.js' -export { list as t } from './list.js' -export { update as u } from './update.js' +export * from './extract.js' export { extract as x } from './extract.js' - +export * from './header.js' +export * from './list.js' +export { list as t } from './list.js' // classes export * from './pack.js' -export * from './unpack.js' export * from './parse.js' -export * from './read-entry.js' -export * from './write-entry.js' -export * from './header.js' export * from './pax.js' +export * from './read-entry.js' +export * from './replace.js' +export { replace as r } from './replace.js' export * as types from './types.js' +export * from './unpack.js' +export * from './update.js' +export { update as u } from './update.js' +export * from './write-entry.js' diff --git a/src/list.ts b/src/list.ts index f02d140a..3cdfbb14 100644 --- a/src/list.ts +++ b/src/list.ts @@ -2,90 +2,15 @@ import * as fsm from '@isaacs/fs-minipass' import fs from 'node:fs' import { dirname, parse } from 'path' +import { makeCommand } from './make-command.js' import { - dealias, - isFile, - isSyncFile, TarOptions, TarOptionsFile, TarOptionsSyncFile, - TarOptionsWithAliases, - TarOptionsWithAliasesFile, - TarOptionsWithAliasesSync, - TarOptionsWithAliasesSyncFile, } from './options.js' import { Parser } from './parse.js' import { stripTrailingSlashes } from './strip-trailing-slashes.js' -export function list( - opt: TarOptionsWithAliasesSyncFile, - files?: string[], -): void -export function list( - opt: TarOptionsWithAliasesSync, - files?: string[], -): void -export function list( - opt: TarOptionsWithAliasesFile, - files?: string[], - cb?: () => any, -): Promise<void> -export function list( - opt: TarOptionsWithAliasesFile, - cb: () => any, -): Promise<void> -export function list( - opt: TarOptionsWithAliases, - files?: string[], -): Parser -export function list( - opt_: TarOptionsWithAliases, - files?: string[] | (() => any), - cb?: () => any, -): void | Promise<void> | Parser { - if (typeof opt_ === 'function') { - ;(cb = opt_), (files = undefined), (opt_ = {}) - } else if (Array.isArray(opt_)) { - ;(files = opt_), (opt_ = {}) - } - - if (typeof files === 'function') { - ;(cb = files), (files = undefined) - } - - if (!files) { - files = [] - } else { - files = Array.from(files) - } - - const opt = dealias(opt_) - - if (opt.sync && typeof cb === 'function') { - throw new TypeError( - 'callback not supported for sync tar functions', - ) - } - - if (!opt.file && typeof cb === 'function') { - throw new TypeError('callback only supported with file option') - } - - if (files.length) { - filesFilter(opt, files) - } - - if (!opt.noResume) { - onentryFunction(opt) - } - - return ( - isSyncFile(opt) ? listFileSync(opt) - : isFile(opt) ? listFile(opt, cb) - : list_(opt) - ) -} - const onentryFunction = (opt: TarOptions) => { const onentry = opt.onentry opt.onentry = @@ -99,7 +24,7 @@ const onentryFunction = (opt: TarOptions) => { // construct a filter that limits the file entries listed // include child entries if a dir is included -const filesFilter = (opt: TarOptions, files: string[]) => { +export const filesFilter = (opt: TarOptions, files: string[]) => { const map = new Map<string, boolean>( files.map(f => [stripTrailingSlashes(f), true]), ) @@ -130,7 +55,7 @@ const filesFilter = (opt: TarOptions, files: string[]) => { } const listFileSync = (opt: TarOptionsSyncFile) => { - const p = list_(opt) + const p = new Parser(opt) const file = opt.file let fd try { @@ -161,7 +86,7 @@ const listFileSync = (opt: TarOptionsSyncFile) => { const listFile = ( opt: TarOptionsFile, - cb?: () => void, + _files: string[], ): Promise<void> => { const parse = new Parser(opt) const readSize = opt.maxReadSize || 16 * 1024 * 1024 @@ -184,7 +109,16 @@ const listFile = ( } }) }) - return cb ? p.then(cb, cb) : p + return p } -const list_ = (opt: TarOptions) => new Parser(opt) +export const list = makeCommand( + listFileSync, + listFile, + opt => new Parser(opt) as Parser & { sync: true }, + opt => new Parser(opt), + (opt, files) => { + if (files?.length) filesFilter(opt, files) + if (!opt.noResume) onentryFunction(opt) + }, +) diff --git a/src/make-command.ts b/src/make-command.ts new file mode 100644 index 00000000..7a0e8b2e --- /dev/null +++ b/src/make-command.ts @@ -0,0 +1,246 @@ +import { + dealias, + isAsyncFile, + isAsyncNoFile, + isSyncFile, + isSyncNoFile, + TarOptions, + TarOptionsAsyncFile, + TarOptionsAsyncNoFile, + TarOptionsSyncFile, + TarOptionsSyncNoFile, + TarOptionsWithAliases, + TarOptionsWithAliasesAsync, + TarOptionsWithAliasesAsyncFile, + TarOptionsWithAliasesAsyncNoFile, + TarOptionsWithAliasesFile, + TarOptionsWithAliasesNoFile, + TarOptionsWithAliasesSync, + TarOptionsWithAliasesSyncFile, + TarOptionsWithAliasesSyncNoFile, +} from './options.js' + +export type CB = (er?: Error) => any + +export type TarCommand< + AsyncClass, + SyncClass extends { sync: true }, +> = { + // async and no file specified + (): AsyncClass + (opt: TarOptionsWithAliasesAsyncNoFile): AsyncClass + (entries: string[]): AsyncClass + ( + opt: TarOptionsWithAliasesAsyncNoFile, + entries: string[], + ): AsyncClass +} & { + // sync and no file + (opt: TarOptionsWithAliasesSyncNoFile): SyncClass + (opt: TarOptionsWithAliasesSyncNoFile, entries: string[]): SyncClass +} & { + // async and file + (opt: TarOptionsWithAliasesAsyncFile): Promise<void> + ( + opt: TarOptionsWithAliasesAsyncFile, + entries: string[], + ): Promise<void> + (opt: TarOptionsWithAliasesAsyncFile, cb: CB): Promise<void> + ( + opt: TarOptionsWithAliasesAsyncFile, + entries: string[], + cb: CB, + ): Promise<void> +} & { + // sync and file + (opt: TarOptionsWithAliasesSyncFile): void + (opt: TarOptionsWithAliasesSyncFile, entries: string[]): void +} & { + // sync, maybe file + (opt: TarOptionsWithAliasesSync): typeof opt extends ( + TarOptionsWithAliasesFile + ) ? + void + : typeof opt extends TarOptionsWithAliasesNoFile ? SyncClass + : void | SyncClass + ( + opt: TarOptionsWithAliasesSync, + entries: string[], + ): typeof opt extends TarOptionsWithAliasesFile ? void + : typeof opt extends TarOptionsWithAliasesNoFile ? SyncClass + : void | SyncClass +} & { + // async, maybe file + (opt: TarOptionsWithAliasesAsync): typeof opt extends ( + TarOptionsWithAliasesFile + ) ? + Promise<void> + : typeof opt extends TarOptionsWithAliasesNoFile ? AsyncClass + : Promise<void> | AsyncClass + ( + opt: TarOptionsWithAliasesAsync, + entries: string[], + ): typeof opt extends TarOptionsWithAliasesFile ? Promise<void> + : typeof opt extends TarOptionsWithAliasesNoFile ? AsyncClass + : Promise<void> | AsyncClass + (opt: TarOptionsWithAliasesAsync, cb: CB): Promise<void> + ( + opt: TarOptionsWithAliasesAsync, + entries: string[], + cb: CB, + ): typeof opt extends TarOptionsWithAliasesFile ? Promise<void> + : typeof opt extends TarOptionsWithAliasesNoFile ? never + : Promise<void> +} & { + // maybe sync, file + (opt: TarOptionsWithAliasesFile): Promise<void> | void + ( + opt: TarOptionsWithAliasesFile, + entries: string[], + ): typeof opt extends TarOptionsWithAliasesSync ? void + : typeof opt extends TarOptionsWithAliasesAsync ? Promise<void> + : Promise<void> | void + (opt: TarOptionsWithAliasesFile, cb: CB): Promise<void> + ( + opt: TarOptionsWithAliasesFile, + entries: string[], + cb: CB, + ): typeof opt extends TarOptionsWithAliasesSync ? never + : typeof opt extends TarOptionsWithAliasesAsync ? Promise<void> + : Promise<void> +} & { + // maybe sync, no file + (opt: TarOptionsWithAliasesNoFile): typeof opt extends ( + TarOptionsWithAliasesSync + ) ? + SyncClass + : typeof opt extends TarOptionsWithAliasesAsync ? AsyncClass + : SyncClass | AsyncClass + ( + opt: TarOptionsWithAliasesNoFile, + entries: string[], + ): typeof opt extends TarOptionsWithAliasesSync ? SyncClass + : typeof opt extends TarOptionsWithAliasesAsync ? AsyncClass + : SyncClass | AsyncClass +} & { + // maybe sync, maybe file + (opt: TarOptionsWithAliases): typeof opt extends ( + TarOptionsWithAliasesFile + ) ? + typeof opt extends TarOptionsWithAliasesSync ? void + : typeof opt extends TarOptionsWithAliasesAsync ? Promise<void> + : void | Promise<void> + : typeof opt extends TarOptionsWithAliasesNoFile ? + typeof opt extends TarOptionsWithAliasesSync ? SyncClass + : typeof opt extends TarOptionsWithAliasesAsync ? AsyncClass + : SyncClass | AsyncClass + : typeof opt extends TarOptionsWithAliasesSync ? SyncClass | void + : typeof opt extends TarOptionsWithAliasesAsync ? + AsyncClass | Promise<void> + : SyncClass | void | AsyncClass | Promise<void> +} & { + // extras + syncFile: (opt: TarOptionsSyncFile, entries: string[]) => void + asyncFile: ( + opt: TarOptionsAsyncFile, + entries: string[], + cb?: CB, + ) => Promise<void> + syncNoFile: ( + opt: TarOptionsSyncNoFile, + entries: string[], + ) => SyncClass + asyncNoFile: ( + opt: TarOptionsAsyncNoFile, + entries: string[], + ) => AsyncClass + validate?: (opt: TarOptions, entries?: string[]) => void +} + +export const makeCommand = < + AsyncClass, + SyncClass extends { sync: true }, +>( + syncFile: (opt: TarOptionsSyncFile, entries: string[]) => void, + asyncFile: ( + opt: TarOptionsAsyncFile, + entries: string[], + cb?: CB, + ) => Promise<void>, + syncNoFile: ( + opt: TarOptionsSyncNoFile, + entries: string[], + ) => SyncClass, + asyncNoFile: ( + opt: TarOptionsAsyncNoFile, + entries: string[], + ) => AsyncClass, + validate?: (opt: TarOptions, entries?: string[]) => void, +): TarCommand<AsyncClass, SyncClass> => { + return Object.assign( + ( + opt_: TarOptionsWithAliases | string[] = [], + entries?: string[] | CB, + cb?: CB, + ) => { + if (Array.isArray(opt_)) { + entries = opt_ + opt_ = {} + } + + if (typeof entries === 'function') { + cb = entries + entries = undefined + } + + if (!entries) { + entries = [] + } else { + entries = Array.from(entries) + } + + const opt = dealias(opt_) + + validate?.(opt, entries) + + if (isSyncFile(opt)) { + if (typeof cb === 'function') { + throw new TypeError( + 'callback not supported for sync tar functions', + ) + } + return syncFile(opt, entries) + } else if (isAsyncFile(opt)) { + const p = asyncFile(opt, entries) + // weirdness to make TS happy + const c = cb ? cb : undefined + return c ? p.then(() => c(), c) : p + } else if (isSyncNoFile(opt)) { + if (typeof cb === 'function') { + throw new TypeError( + 'callback not supported for sync tar functions', + ) + } + return syncNoFile(opt, entries) + } else if (isAsyncNoFile(opt)) { + if (typeof cb === 'function') { + throw new TypeError( + 'callback only supported with file option', + ) + } + return asyncNoFile(opt, entries) + /* c8 ignore start */ + } else { + throw new Error('impossible options??') + } + /* c8 ignore stop */ + }, + { + syncFile, + asyncFile, + syncNoFile, + asyncNoFile, + validate, + }, + ) as TarCommand<AsyncClass, SyncClass> +} diff --git a/src/options.ts b/src/options.ts index fe33ac46..5dab6724 100644 --- a/src/options.ts +++ b/src/options.ts @@ -243,14 +243,14 @@ export interface TarOptions { chmod?: boolean /** - * When setting the {@link TarOptions#noChmod} option to `false`, you may + * When setting the {@link TarOptions#chmod} option to `true`, you may * provide a value here to avoid having to call the deprecated and * thread-unsafe `process.umask()` method. * - * This has no effect with `noChmod` is not set to false explicitly, as - * mode values are not set explicitly anyway. If `noChmod` is set to `false`, - * and a value is not provided here, then `process.umask()` must be called, - * which will result in deprecation warnings. + * This has no effect with `chmod` is not set to true, as mode values are not + * set explicitly anyway. If `chmod` is set to `true`, and a value is not + * provided here, then `process.umask()` must be called, which will result in + * deprecation warnings. * * The most common values for this are `0o22` (resulting in directories * created with mode `0o755` and files with `0o644` by default) and `0o2` @@ -469,8 +469,13 @@ export interface TarOptions { } export type TarOptionsSync = TarOptions & { sync: true } +export type TarOptionsAsync = TarOptions & { sync?: false } export type TarOptionsFile = TarOptions & { file: string } +export type TarOptionsNoFile = TarOptions & { file?: undefined } export type TarOptionsSyncFile = TarOptionsSync & TarOptionsFile +export type TarOptionsAsyncFile = TarOptionsAsync & TarOptionsFile +export type TarOptionsSyncNoFile = TarOptionsSync & TarOptionsNoFile +export type TarOptionsAsyncNoFile = TarOptionsAsync & TarOptionsNoFile export type LinkCacheKey = `${number}:${number}` @@ -614,6 +619,9 @@ export interface TarOptionsWithAliases extends TarOptions { export type TarOptionsWithAliasesSync = TarOptionsWithAliases & { sync: true } +export type TarOptionsWithAliasesAsync = TarOptionsWithAliases & { + sync?: false +} export type TarOptionsWithAliasesFile = | (TarOptionsWithAliases & { file: string @@ -621,11 +629,43 @@ export type TarOptionsWithAliasesFile = | (TarOptionsWithAliases & { f: string }) export type TarOptionsWithAliasesSyncFile = TarOptionsWithAliasesSync & TarOptionsWithAliasesFile +export type TarOptionsWithAliasesAsyncFile = + TarOptionsWithAliasesAsync & TarOptionsWithAliasesFile + +export type TarOptionsWithAliasesNoFile = TarOptionsWithAliases & { + f?: undefined + file?: undefined +} -export const isSyncFile = (o: TarOptions): o is TarOptionsSyncFile => - !!o.sync && !!o.file -export const isSync = (o: TarOptions): o is TarOptionsSync => !!o.sync -export const isFile = (o: TarOptions): o is TarOptionsFile => !!o.file +export type TarOptionsWithAliasesSyncNoFile = + TarOptionsWithAliasesSync & TarOptionsWithAliasesNoFile +export type TarOptionsWithAliasesAsyncNoFile = + TarOptionsWithAliasesAsync & TarOptionsWithAliasesNoFile + +export const isSyncFile = <O extends TarOptions>( + o: O, +): o is O & TarOptionsSyncFile => !!o.sync && !!o.file +export const isAsyncFile = <O extends TarOptions>( + o: O, +): o is O & TarOptionsAsyncFile => !o.sync && !!o.file +export const isSyncNoFile = <O extends TarOptions>( + o: O, +): o is O & TarOptionsSyncNoFile => !!o.sync && !o.file +export const isAsyncNoFile = <O extends TarOptions>( + o: O, +): o is O & TarOptionsAsyncNoFile => !o.sync && !o.file +export const isSync = <O extends TarOptions>( + o: O, +): o is O & TarOptionsSync => !!o.sync +export const isAsync = <O extends TarOptions>( + o: O, +): o is O & TarOptionsAsync => !o.sync +export const isFile = <O extends TarOptions>( + o: O, +): o is O & TarOptionsFile => !!o.file +export const isNoFile = <O extends TarOptions>( + o: O, +): o is O & TarOptionsNoFile => !o.file const dealiasKey = ( k: keyof TarOptionsWithAliases, diff --git a/src/pack.ts b/src/pack.ts index 1ad0a9c5..075d4282 100644 --- a/src/pack.ts +++ b/src/pack.ts @@ -448,6 +448,7 @@ export class Pack } export class PackSync extends Pack { + sync: true = true constructor(opt: TarOptions) { super(opt) this[WRITEENTRYCLASS] = WriteEntrySync diff --git a/src/replace.ts b/src/replace.ts index b65d2c13..1d43fbb4 100644 --- a/src/replace.ts +++ b/src/replace.ts @@ -5,15 +5,11 @@ import fs from 'node:fs' import path from 'node:path' import { Header } from './header.js' import { list } from './list.js' +import { makeCommand } from './make-command.js' import { - dealias, isFile, - isSyncFile, TarOptionsFile, TarOptionsSyncFile, - TarOptionsWithAliases, - TarOptionsWithAliasesFile, - TarOptionsWithAliasesSyncFile, } from './options.js' import { Pack, PackSync } from './pack.js' @@ -23,50 +19,6 @@ import { Pack, PackSync } from './pack.js' // and try again. // Write the new Pack stream starting there. -export function replace( - opt: TarOptionsWithAliasesSyncFile, - files?: string[], -): void -export function replace( - opt: TarOptionsWithAliasesFile, - files?: string[], - cb?: () => any, -): Promise<void> -export function replace( - opt: TarOptionsWithAliasesFile, - cb: () => any, -): Promise<void> -export function replace( - opt_: TarOptionsWithAliases, - files?: string[] | (() => any), - cb?: () => any, -): void | Promise<void> { - const opt = dealias(opt_) - - if (!isFile(opt)) { - throw new TypeError('file is required') - } - - if ( - opt.gzip || - opt.brotli || - opt.file.endsWith('.br') || - opt.file.endsWith('.tbr') - ) { - throw new TypeError('cannot append to compressed archives') - } - - if (!files || !Array.isArray(files) || !files.length) { - throw new TypeError('no files or directories specified') - } - - files = Array.from(files) - - return isSyncFile(opt) ? - replaceSync(opt, files) - : replace_(opt, files, cb) -} - const replaceSync = (opt: TarOptionsSyncFile, files: string[]) => { const p = new PackSync(opt) @@ -157,10 +109,9 @@ const streamSync = ( addFilesSync(p, files) } -const replace_ = ( +const replaceAsync = ( opt: TarOptionsFile, files: string[], - cb?: () => void, ): Promise<void> => { files = Array.from(files) const p = new Pack(opt) @@ -278,7 +229,7 @@ const replace_ = ( fs.open(opt.file, flag, onopen) }) - return cb ? promise.then(cb, cb) : promise + return promise } const addFilesSync = (p: Pack, files: string[]) => { @@ -315,3 +266,34 @@ const addFilesAsync = async ( } p.end() } + +export const replace = makeCommand( + replaceSync, + replaceAsync, + /* c8 ignore start */ + (): never => { + throw new TypeError('file is required') + }, + (): never => { + throw new TypeError('file is required') + }, + /* c8 ignore stop */ + (opt, entries) => { + if (!isFile(opt)) { + throw new TypeError('file is required') + } + + if ( + opt.gzip || + opt.brotli || + opt.file.endsWith('.br') || + opt.file.endsWith('.tbr') + ) { + throw new TypeError('cannot append to compressed archives') + } + + if (!entries?.length) { + throw new TypeError('no paths specified to add/replace') + } + }, +) diff --git a/src/unpack.ts b/src/unpack.ts index f2eb4e3a..154b9492 100644 --- a/src/unpack.ts +++ b/src/unpack.ts @@ -883,6 +883,8 @@ const callSync = (fn: () => any) => { } export class UnpackSync extends Unpack { + sync: true = true; + [MAKEFS](er: null | Error | undefined, entry: ReadEntry) { return super[MAKEFS](er, entry, () => {}) } diff --git a/src/update.ts b/src/update.ts index c824bbef..06dcc46e 100644 --- a/src/update.ts +++ b/src/update.ts @@ -1,44 +1,21 @@ // tar -u -import { - dealias, - isFile, - type TarOptionsWithAliases, -} from './options.js' +import { makeCommand } from './make-command.js' +import { type TarOptionsWithAliases } from './options.js' import { replace as r } from './replace.js' // just call tar.r with the filter and mtimeCache - -export const update = ( - opt_: TarOptionsWithAliases, - files: string[], - cb?: (er?: Error) => any, -) => { - const opt = dealias(opt_) - - if (!isFile(opt)) { - throw new TypeError('file is required') - } - - if ( - opt.gzip || - opt.brotli || - opt.file.endsWith('.br') || - opt.file.endsWith('.tbr') - ) { - throw new TypeError('cannot append to compressed archives') - } - - if (!files || !Array.isArray(files) || !files.length) { - throw new TypeError('no files or directories specified') - } - - files = Array.from(files) - mtimeFilter(opt) - - return r(opt, files, cb) -} +export const update = makeCommand( + r.syncFile, + r.asyncFile, + r.syncNoFile, + r.asyncNoFile, + (opt, entries = []) => { + r.validate?.(opt, entries) + mtimeFilter(opt) + }, +) const mtimeFilter = (opt: TarOptionsWithAliases) => { const filter = opt.filter diff --git a/src/write-entry.ts b/src/write-entry.ts index cfb797a4..4a7b2c65 100644 --- a/src/write-entry.ts +++ b/src/write-entry.ts @@ -53,11 +53,7 @@ const ONDRAIN = Symbol('ondrain') const PREFIX = Symbol('prefix') export class WriteEntry - extends Minipass< - Buffer, - Minipass.ContiguousData, - WarnEvent - > + extends Minipass<Buffer, Minipass.ContiguousData, WarnEvent> implements Warner { path: string @@ -471,10 +467,7 @@ export class WriteEntry this.once('drain', cb) } - write( - buffer: Buffer | string, - cb?: () => void, - ): boolean + write(buffer: Buffer | string, cb?: () => void): boolean write( str: Buffer | string, encoding?: BufferEncoding | null, @@ -544,6 +537,8 @@ export class WriteEntry } export class WriteEntrySync extends WriteEntry implements Warner { + sync: true = true; + [LSTAT]() { this[ONLSTAT](fs.lstatSync(this.absolute)) } @@ -757,10 +752,7 @@ export class WriteEntryTar return modeFix(mode, this.type === 'Directory', this.portable) } - write( - buffer: Buffer | string, - cb?: () => void, - ): boolean + write(buffer: Buffer | string, cb?: () => void): boolean write( str: Buffer | string, encoding?: BufferEncoding | null, @@ -793,11 +785,15 @@ export class WriteEntryTar end(cb?: () => void): this end(chunk: Buffer | string, cb?: () => void): this - end(chunk: Buffer | string, encoding?: BufferEncoding, cb?: () => void): this + end( + chunk: Buffer | string, + encoding?: BufferEncoding, + cb?: () => void, + ): this end( chunk?: Buffer | string | (() => void), encoding?: BufferEncoding | (() => void), - cb?: () => void + cb?: () => void, ): this { if (this.blockRemain) { super.write(Buffer.alloc(this.blockRemain)) diff --git a/test/create.js b/test/create.ts similarity index 87% rename from test/create.js rename to test/create.ts index 9292c66d..567f545f 100644 --- a/test/create.js +++ b/test/create.ts @@ -1,9 +1,10 @@ -import t from 'tap' +import t, { Test } from 'tap' import { c, list, Pack, PackSync } from '../dist/esm/index.js' import fs from 'fs' import path from 'path' import { rimraf } from 'rimraf' import { mkdirp } from 'mkdirp' +//@ts-ignore import mutateFS from 'mutate-fs' import { spawn } from 'child_process' import { fileURLToPath } from 'url' @@ -14,9 +15,16 @@ const __dirname = path.dirname(__filename) const dir = path.resolve(__dirname, 'fixtures/create') const tars = path.resolve(__dirname, 'fixtures/tars') -const readtar = (file, cb) => { +const readtar = ( + file: string, + cb: ( + code: number | null, + signal: null | NodeJS.Signals, + output: string, + ) => any, +) => { const child = spawn('tar', ['tf', file]) - const out = [] + const out: Buffer[] = [] child.stdout.on('data', c => out.push(c)) child.on('close', (code, signal) => cb(code, signal, Buffer.concat(out).toString()), @@ -31,7 +39,9 @@ t.before(async () => { }) t.test('no cb if sync or without file', t => { + //@ts-expect-error t.throws(() => c({ sync: true }, ['asdf'], () => {})) + //@ts-expect-error t.throws(() => c(() => {})) t.throws(() => c({}, () => {})) t.throws(() => c({}, ['asdf'], () => {})) @@ -54,7 +64,7 @@ t.test('create file', t => { readtar(file, (code, signal, list) => { t.equal(code, 0) t.equal(signal, null) - t.equal(list.trim(), 'create.js') + t.equal(list.trim(), 'create.ts') t.end() }) }) @@ -74,7 +84,7 @@ t.test('create file', t => { readtar(file, (code, signal, list) => { t.equal(code, 0) t.equal(signal, null) - t.equal(list.trim(), 'create.js') + t.equal(list.trim(), 'create.ts') t.end() }) }, @@ -93,7 +103,7 @@ t.test('create file', t => { readtar(file, (code, signal, list) => { t.equal(code, 0) t.equal(signal, null) - t.equal(list.trim(), 'create.js') + t.equal(list.trim(), 'create.ts') t.end() }) }) @@ -115,7 +125,7 @@ t.test('create file', t => { readtar(file, (code, signal, list) => { t.equal(code, 0) t.equal(signal, null) - t.equal(list.trim(), 'create.js') + t.equal(list.trim(), 'create.ts') t.equal(fs.lstatSync(file).mode & 0o7777, mode) t.end() }) @@ -137,7 +147,7 @@ t.test('create file', t => { readtar(file, (code, signal, list) => { t.equal(code, 0) t.equal(signal, null) - t.equal(list.trim(), 'create.js') + t.equal(list.trim(), 'create.ts') t.equal(fs.lstatSync(file).mode & 0o7777, mode) t.end() }) @@ -151,8 +161,16 @@ t.test('create file', t => { }) t.test('create', t => { - t.type(c({ sync: true }, ['README.md']), PackSync) + const ps = c({ sync: true }, ['README.md']) + t.equal(ps.sync, true) + t.type(ps, PackSync) + const p = c(['README.md']) + //@ts-expect-error + p.then + //@ts-expect-error + p.sync t.type(c(['README.md']), Pack) + t.end() }) @@ -210,7 +228,7 @@ t.test('gzipped tarball that makes some drain/resume stuff', t => { t.test('create tarball out of another tarball', t => { const out = path.resolve(dir, 'out.tar') - const check = t => { + const check = (t: Test) => { const expect = [ 'dir/', 'Ί.txt', @@ -265,3 +283,8 @@ t.test('create tarball out of another tarball', t => { t.end() }) + +t.test('must specify some files', t => { + t.throws(() => c({}), 'no paths specified to add to archive') + t.end() +}) diff --git a/test/extract.js b/test/extract.ts similarity index 73% rename from test/extract.js rename to test/extract.ts index ce2afeb7..37d2939e 100644 --- a/test/extract.js +++ b/test/extract.ts @@ -1,24 +1,25 @@ -import t from 'tap' -import nock from 'nock' -import { extract as x } from '../dist/esm/extract.js' -import path from 'path' import fs from 'fs' -import { fileURLToPath } from 'url' -import { promisify } from 'util' +import http from 'http' import { mkdirp } from 'mkdirp' +import nock from 'nock' +import path from 'path' import { rimraf } from 'rimraf' import { pipeline as PL } from 'stream' +import t, { Test } from 'tap' +import { fileURLToPath } from 'url' +import { promisify } from 'util' +import { extract as x } from '../dist/esm/extract.js' import { Unpack, UnpackSync } from '../dist/esm/unpack.js' const pipeline = promisify(PL) -import http from 'http' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) const extractdir = path.resolve(__dirname, 'fixtures/extract') const tars = path.resolve(__dirname, 'fixtures/tars') +//@ts-ignore import mutateFS from 'mutate-fs' -const tnock = (t, host, opts) => { +const tnock = (t: Test, host: string, opts?: nock.Options) => { nock.disableNetConnect() const server = nock(host, opts) t.teardown(function () { @@ -39,7 +40,7 @@ t.test('basic extracting', t => { await mkdirp(dir) }) - const check = async t => { + const check = async (t: Test) => { fs.lstatSync(dir + '/Ί.txt') fs.lstatSync(dir + '/🌟.txt') t.throws(() => @@ -55,22 +56,53 @@ t.test('basic extracting', t => { const files = ['🌟.txt', 'Ί.txt'] t.test('sync', t => { - x({ file: file, sync: true, C: dir }, files) + x({ file, sync: true, C: dir }, files) return check(t) }) t.test('async promisey', async t => { - await x({ file: file, cwd: dir }, files) + const p = x({ file, cwd: dir }, files) + //@ts-expect-error + p.sync + //@ts-expect-error + p.write + await p return check(t) }) t.test('async cb', async t => { - await x({ file: file, cwd: dir }, files, er => { + const p = x({ file, cwd: dir }, files, er => { if (er) { throw er } return check(t) }) + //@ts-expect-error + p.sync + //@ts-expect-error + p.write + await p + }) + + t.test('stream sync', t => { + const ups = x({ cwd: dir, sync: true }, files) + ups.end(fs.readFileSync(file)) + //@ts-expect-error + ups.then + t.equal(ups.sync, true) + return check(t) + }) + + t.test('stream async', async t => { + const up = x({ cwd: dir }, files) + //@ts-expect-error + up.then + //@ts-expect-error + up.sync + await new Promise<void>(r => + up.end(fs.readFileSync(file)).on('end', r), + ) + return check(t) }) t.end() @@ -87,7 +119,7 @@ t.test('ensure an open stream is not prematurely closed', t => { await mkdirp(dir) }) - const check = async t => { + const check = async (t: Test) => { t.ok(fs.lstatSync(dir + '/long-path')) await rimraf(dir) t.end() @@ -115,7 +147,7 @@ t.test('ensure an open stream is not prematuraly closed http', t => { await mkdirp(dir) }) - const check = async t => { + const check = async (t: Test) => { t.ok(fs.lstatSync(dir + '/long-path')) await rimraf(dir) t.end() @@ -148,7 +180,7 @@ t.test('file list and filter', t => { await mkdirp(dir) }) - const check = async t => { + const check = async (t: Test) => { fs.lstatSync(dir + '/Ί.txt') t.throws(() => fs.lstatSync(dir + '/🌟.txt')) t.throws(() => @@ -162,35 +194,25 @@ t.test('file list and filter', t => { await rimraf(dir) } - const filter = path => path === 'Ί.txt' + const filter = (path: string) => path === 'Ί.txt' - t.test('sync', t => { - x({ filter: filter, file: file, sync: true, C: dir }, [ - '🌟.txt', - 'Ί.txt', - ]) + t.test('sync file', t => { + x({ filter, file, sync: true, C: dir }, ['🌟.txt', 'Ί.txt']) return check(t) }) - t.test('async promisey', async t => { - await x({ filter: filter, file: file, cwd: dir }, [ - '🌟.txt', - 'Ί.txt', - ]) + t.test('async file', async t => { + await x({ filter, file, cwd: dir }, ['🌟.txt', 'Ί.txt']) check(t) }) t.test('async cb', t => { - return x( - { filter: filter, file: file, cwd: dir }, - ['🌟.txt', 'Ί.txt'], - er => { - if (er) { - throw er - } - return check(t) - }, - ) + return x({ filter, file, cwd: dir }, ['🌟.txt', 'Ί.txt'], er => { + if (er) { + throw er + } + return check(t) + }) }) t.end() @@ -205,7 +227,7 @@ t.test('no file list', t => { await mkdirp(dir) }) - const check = async t => { + const check = async (t: Test) => { t.equal( fs.lstatSync(path.resolve(dir, '1024-bytes.txt')).size, 1024, @@ -219,13 +241,13 @@ t.test('no file list', t => { await rimraf(dir) } - t.test('sync', t => { - x({ file: file, sync: true, C: dir }) + t.test('sync file', t => { + x({ file, sync: true, C: dir }) return check(t) }) - t.test('async promisey', async t => { - await x({ file: file, cwd: dir }) + t.test('async promisey file', async t => { + await x({ file, cwd: dir }) return check(t) }) @@ -238,6 +260,27 @@ t.test('no file list', t => { }) }) + t.test('sync stream', t => { + const up = x({ sync: true, C: dir }) + t.equal(up.sync, true) + t.type(up, UnpackSync) + //@ts-expect-error + up.then + up.end(fs.readFileSync(file)) + return check(t) + }) + + t.test('async stream', t => { + const up = x({ C: dir }) + t.type(up, Unpack) + //@ts-expect-error + up.sync + //@ts-expect-error + up.then + up.end(fs.readFileSync(file)) + return new Promise(r => up.on('close', () => r(check(t)))) + }) + t.end() }) @@ -251,7 +294,7 @@ t.test('read in itty bits', t => { await mkdirp(dir) }) - const check = async t => { + const check = async (t: Test) => { t.equal( fs.lstatSync(path.resolve(dir, '1024-bytes.txt')).size, 1024, @@ -291,22 +334,39 @@ t.test('read in itty bits', t => { }) t.test('bad calls', t => { - t.throws(() => x(() => {})) + t.throws(() => x({}, () => {})) + t.throws(() => x({}, [], () => {})) + //@ts-expect-error t.throws(() => x({ sync: true }, () => {})) + //@ts-expect-error t.throws(() => x({ sync: true }, [], () => {})) t.end() }) t.test('no file', t => { - t.type(x(), Unpack) - t.type(x(['asdf']), Unpack) - t.type(x({ sync: true }), UnpackSync) + const up = x() + t.type(up, Unpack) + //@ts-expect-error + up.then + //@ts-expect-error + up.sync + const upf = x(['asdf']) + //@ts-expect-error + upf.then + //@ts-expect-error + upf.sync + t.type(upf, Unpack) + const ups = x({ sync: true }) + //@ts-expect-error + ups.then + t.equal(ups.sync, true) + t.type(ups, UnpackSync) t.end() }) -t.test('nonexistent', t => { +t.test('nonexistent', async t => { t.throws(() => x({ sync: true, file: 'does not exist' })) - x({ file: 'does not exist' }).catch(() => t.end()) + await t.rejects(x({ file: 'does not exist' })) }) t.test('read fail', t => { @@ -334,7 +394,7 @@ t.test('sync gzip error edge case test', async t => { x({ sync: true, file: file, - onwarn: (c, m, er) => { + onwarn: (_c: any, _m: any, er) => { throw er }, }) @@ -420,8 +480,10 @@ t.test('verify long linkname is not a problem', async t => { // See: https://github.com/isaacs/node-tar/issues/312 const file = path.resolve(__dirname, 'fixtures/long-linkname.tar') t.test('sync', t => { - x({ sync: true, strict: true, file, C: t.testdir({}) }) - t.ok(fs.lstatSync(t.testdirName + '/test').isSymbolicLink()) + const cwd = t.testdir({}) + const result = x({ sync: true, strict: true, file, cwd }) + t.equal(result, undefined) + t.ok(fs.lstatSync(cwd + '/test').isSymbolicLink()) t.end() }) t.test('async', async t => { diff --git a/test/list.js b/test/list.ts similarity index 76% rename from test/list.js rename to test/list.ts index 1533dc6d..cc11a491 100644 --- a/test/list.js +++ b/test/list.ts @@ -1,45 +1,52 @@ import fs, { readFileSync } from 'fs' +//@ts-ignore import mutateFS from 'mutate-fs' import { dirname, resolve } from 'path' -import t from 'tap' +import t, { Test } from 'tap' import { fileURLToPath } from 'url' import { list } from '../dist/esm/list.js' +import { Parser } from '../dist/esm/parse.js' +import { ReadEntry } from '../dist/esm/read-entry.js' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) const lp = JSON.parse( readFileSync(__dirname + '/fixtures/parse/long-paths.json', 'utf8'), -) +) as ( + | ['meta', string] + | ['entry', Record<string, any>] + | ['nullBlock' | 'eof' | 'end'] +)[] t.test('basic', t => { const file = resolve(__dirname, 'fixtures/tars/long-paths.tar') - const expect = lp + const expect = (lp as any[]) .filter(e => Array.isArray(e) && e[0] === 'entry') - .map(e => e[1].path) + .map((e: ['entry', Record<string, any>]) => e[1].path as string) - const check = (actual, t) => { + const check = (actual: string[], t: Test) => { t.same(actual, expect) return Promise.resolve(null) } - ;[1000, null].forEach(maxReadSize => { + ;[1000, undefined].forEach(maxReadSize => { t.test('file maxReadSize=' + maxReadSize, t => { t.test('sync', t => { - const actual = [] - const onentry = entry => actual.push(entry.path) + const actual: string[] = [] + const onentry = (entry: ReadEntry) => actual.push(entry.path) list({ file: file, sync: true, - onentry: onentry, - maxReadSize: maxReadSize, + onentry, + maxReadSize, }) return check(actual, t) }) t.test('async promise', async t => { - const actual = [] - const onentry = entry => actual.push(entry.path) + const actual: string[] = [] + const onentry = (entry: ReadEntry) => actual.push(entry.path) return await list({ file, onentry, @@ -48,15 +55,15 @@ t.test('basic', t => { }) t.test('async cb', t => { - const actual = [] - const onentry = entry => actual.push(entry.path) + const actual: string[] = [] + const onentry = (entry: ReadEntry) => actual.push(entry.path) list( { file: file, onentry: onentry, maxReadSize: maxReadSize, }, - er => { + (er?: Error) => { if (er) { throw er } @@ -71,16 +78,16 @@ t.test('basic', t => { t.test('stream', t => { t.test('sync', t => { - const actual = [] - const onentry = entry => actual.push(entry.path) - const l = list({ sync: true, onentry: onentry }) + const actual: string[] = [] + const onentry = (entry: ReadEntry) => actual.push(entry.path) + const l = list({ sync: true, onentry }) l.end(fs.readFileSync(file)) return check(actual, t) }) t.test('async', t => { - const actual = [] - const onentry = entry => actual.push(entry.path) + const actual: string[] = [] + const onentry = (entry: ReadEntry) => actual.push(entry.path) const l = list() l.on('entry', onentry) l.on('end', _ => check(actual, t).then(_ => t.end())) @@ -109,8 +116,8 @@ t.test('basic', t => { ] t.test('no filter function', async t => { - const check = _ => t.same(actual, expect) - const actual = [] + const check = () => t.same(actual, expect) + const actual: string[] = [] return list( { file: file, @@ -121,9 +128,9 @@ t.test('basic', t => { }) t.test('no filter function, stream', t => { - const check = _ => t.same(actual, expect) - const actual = [] - const onentry = entry => actual.push(entry.path) + const check = () => t.same(actual, expect) + const actual: string[] = [] + const onentry = (entry: ReadEntry) => actual.push(entry.path) fs.createReadStream(file).pipe( list(fileList) .on('entry', onentry) @@ -135,8 +142,8 @@ t.test('basic', t => { }) t.test('filter function', async t => { - const check = _ => t.same(actual, expect.slice(0, 1)) - const actual = [] + const check = () => t.same(actual, expect.slice(0, 1)) + const actual: string[] = [] return list( { file: file, @@ -161,11 +168,11 @@ t.test('basic', t => { t.test('bad args', t => { t.throws( - _ => list({ file: __filename, sync: true }, _ => _), + () => list({ file: __filename, sync: true }, () => {}), new TypeError('callback not supported for sync tar functions'), ) t.throws( - _ => list(_ => _), + () => list({}, () => {}), new TypeError('callback only supported with file option'), ) t.end() @@ -176,7 +183,7 @@ t.test('stat fails', t => { t.teardown(mutateFS.statFail(poop)) t.test('sync', t => { t.plan(1) - t.throws(_ => list({ file: __filename, sync: true }), poop) + t.throws(() => list({ file: __filename, sync: true }), poop) }) t.test('cb', t => { t.plan(1) @@ -195,7 +202,7 @@ t.test('read fail', t => { t.teardown(mutateFS.fail('read', poop)) t.plan(1) t.throws( - _ => + () => list({ file: __filename, sync: true, @@ -222,12 +229,12 @@ t.test('read fail', t => { t.test('noResume option', t => { const file = resolve(__dirname, 'fixtures/tars/file.tar') t.test('sync', t => { - let e + let e!: ReadEntry list({ file: file, onentry: entry => { e = entry - process.nextTick(_ => { + process.nextTick(() => { t.notOk(entry.flowing) entry.resume() }) @@ -237,14 +244,14 @@ t.test('noResume option', t => { }) t.ok(e) t.notOk(e.flowing) - e.on('end', _ => t.end()) + e.on('end', () => t.end()) }) t.test('async', t => list({ file: file, onentry: entry => { - process.nextTick(_ => { + process.nextTick(() => { t.notOk(entry.flowing) entry.resume() }) @@ -255,3 +262,11 @@ t.test('noResume option', t => { t.end() }) + +t.test('typechecks', t => { + const p = list() + //@ts-expect-error + p.then + t.type(p, Parser) + t.end() +}) diff --git a/test/make-command.ts b/test/make-command.ts new file mode 100644 index 00000000..822abb7d --- /dev/null +++ b/test/make-command.ts @@ -0,0 +1,74 @@ +import t from 'tap' +import { makeCommand } from '../src/make-command.js' +import { + isAsyncFile, + isAsyncNoFile, + isSyncFile, + isSyncNoFile, +} from '../src/options.js' + +class Sync { + sync: true = true +} +class Async {} + +const cmd = makeCommand<Async, Sync>( + (opt, entries) => { + t.equal(isSyncFile(opt), true) + t.type(entries, Array) + }, + async (opt, entries) => { + t.equal(isAsyncFile(opt), true) + t.type(entries, Array) + }, + (opt, entries) => { + t.equal(isSyncNoFile(opt), true) + t.type(entries, Array) + return new Sync() + }, + (opt, entries) => { + t.equal(isAsyncNoFile(opt), true) + t.type(entries, Array) + return new Async() + }, + (opt, entries) => { + if (entries?.length === 2) throw new Error('should not be len 2') + if (!opt) throw new Error('should get opt') + }, +) + +t.test('validation function is called', t => { + t.throws(() => cmd({}, ['a', 'b'])) + t.throws(() => cmd({ sync: true }, ['a', 'b'])) + t.throws(() => cmd({ sync: true, file: 'x' }, ['a', 'b'])) + t.throws(() => cmd({ file: 'x' }, ['a', 'b'])) + // cases where cb is not allowed + t.throws(() => cmd({}, [], () => {})) + t.throws(() => cmd({}, () => {})) + //@ts-expect-error + t.throws(() => cmd({ sync: true }, [], () => {})) + //@ts-expect-error + t.throws(() => cmd({ sync: true }, () => {})) + t.throws(() => cmd({ sync: true, file: 'x' }, [], () => {})) + t.throws(() => cmd({ sync: true, file: 'x' }, () => {})) + t.end() +}) + +t.test('basic calls', async t => { + t.match(cmd(), Async) + t.match(cmd({}), Async) + t.match(cmd({}, []), Async) + t.match(cmd({ sync: true }), Sync) + t.match(cmd({ sync: true }, []), Sync) + t.equal(cmd({ sync: true, file: 'x' }), undefined) + t.equal(await cmd({ file: 'x' }), undefined) + t.equal(await cmd({ file: 'x' }, []), undefined) + let cbCalled = false + t.equal( + await cmd({ file: 'x' }, [], () => { + cbCalled = true + }), + undefined, + ) + t.equal(cbCalled, true, 'called callback') +}) diff --git a/test/options.js b/test/options.js index 7aa01caf..b5cac1b1 100644 --- a/test/options.js +++ b/test/options.js @@ -4,6 +4,11 @@ import { isSync, isSyncFile, isFile, + isAsyncFile, + isAsyncNoFile, + isSyncNoFile, + isAsync, + isNoFile, } from '../dist/esm/options.js' t.same(dealias(), {}) @@ -62,7 +67,13 @@ t.equal(isSync(dealias({ sync: true, f: 'x' })), true) t.equal(isSync(dealias({ file: 'x' })), false) t.equal(isSync(dealias({ sync: true })), true) t.equal(isSync(dealias({})), false) +t.equal(isAsync(dealias({})), true) t.equal(isFile(dealias({ sync: true, f: 'x' })), true) +t.equal(isNoFile(dealias({ sync: true, f: 'x' })), false) t.equal(isFile(dealias({ file: 'x' })), true) t.equal(isFile(dealias({ sync: true })), false) t.equal(isFile(dealias({})), false) +t.equal(isSyncFile(dealias({})), false) +t.equal(isSyncNoFile(dealias({ sync: true })), true) +t.equal(isAsyncFile(dealias({})), false) +t.equal(isAsyncNoFile(dealias({})), true) diff --git a/test/parse.js b/test/parse.js index 978caacd..d68e2198 100644 --- a/test/parse.js +++ b/test/parse.js @@ -306,7 +306,10 @@ t.test('fixture tests', t => { strict: strict, }) trackEvents(t, expect, p, true) - const first = tardata.subarray(0, Math.floor(tardata.length / 2)) + const first = tardata.subarray( + 0, + Math.floor(tardata.length / 2), + ) p.write(first.toString('hex'), 'hex') process.nextTick(() => p.end(tardata.subarray(Math.floor(tardata.length / 2))), diff --git a/test/replace.js b/test/replace.ts similarity index 89% rename from test/replace.js rename to test/replace.ts index abab2965..5c5c2bef 100644 --- a/test/replace.js +++ b/test/replace.ts @@ -1,7 +1,8 @@ -import t from 'tap' +import t, { Test } from 'tap' import { replace as r } from '../dist/esm/replace.js' import path, { dirname, resolve } from 'path' import fs from 'fs' +//@ts-ignore import mutateFS from 'mutate-fs' import { list } from '../dist/esm/list.js' import { fileURLToPath } from 'url' @@ -33,10 +34,10 @@ const fixtureDef = { } t.test('basic file add to archive (good or truncated)', t => { - const check = (file, t) => { + const check = (file: string, t: Test) => { const c = spawn('tar', ['tf', file], { stdio: [0, 'pipe', 2] }) - const out = [] - c.stdout.on('data', chunk => out.push(chunk)) + const out: Buffer[] = [] + c.stdout?.on('data', (chunk: Buffer) => out.push(chunk)) c.on('close', (code, signal) => { t.equal(code, 0) t.equal(signal, null) @@ -55,18 +56,13 @@ t.test('basic file add to archive (good or truncated)', t => { }) } - const files = [ + const files: (keyof typeof fixtureDef)[] = [ 'body-byte-counts.tar', 'no-null-eof.tar', 'truncated-head.tar', 'truncated-body.tar', ] - const td = files - .map(f => [f, fixtureDef[f]]) - .reduce((s, [k, v]) => { - s[k] = v - return s - }, {}) + const td = Object.fromEntries(files.map(f => [f, fixtureDef[f]])) const fileList = [path.basename(__filename)] t.test('sync', t => { t.plan(files.length) @@ -130,10 +126,10 @@ t.test('basic file add to archive (good or truncated)', t => { }) t.test('add to empty archive', t => { - const check = (file, t) => { + const check = (file: string, t: Test) => { const c = spawn('tar', ['tf', file]) - const out = [] - c.stdout.on('data', chunk => out.push(chunk)) + const out: Buffer[] = [] + c.stdout.on('data', (chunk: Buffer) => out.push(chunk)) c.on('close', (code, signal) => { t.equal(code, 0) t.equal(signal, null) @@ -143,13 +139,9 @@ t.test('add to empty archive', t => { }) } - const files = ['empty.tar', 'zero.tar'] - const td = files - .map(f => [f, fixtureDef[f]]) - .reduce((s, [k, v]) => { - s[k] = v - return s - }, {}) + const files: (keyof typeof fixtureDef)[] = ['empty.tar', 'zero.tar'] + const td = Object.fromEntries(files.map(f => [f, fixtureDef[f]])) + //@ts-ignore files.push('not-existing.tar') t.test('sync', t => { @@ -225,7 +217,7 @@ t.test('cannot append to gzipped archives', async t => { ) t.throws( - _ => + () => r( { file, @@ -238,7 +230,7 @@ t.test('cannot append to gzipped archives', async t => { ) t.throws( - _ => + () => r( { file, @@ -272,7 +264,7 @@ t.test('cannot append to brotli compressed archives', async t => { ) t.throws( - _ => + () => r( { file, @@ -285,7 +277,7 @@ t.test('cannot append to brotli compressed archives', async t => { ) t.throws( - _ => + () => r( { file, @@ -301,10 +293,10 @@ t.test('cannot append to brotli compressed archives', async t => { }) t.test('other throws', t => { - t.throws(_ => r({}, ['asdf']), new TypeError('file is required')) + t.throws(() => r({}, ['asdf']), new TypeError('file is required')) t.throws( - _ => r({ file: 'asdf' }, []), - new TypeError('no files or directories specified'), + () => r({ file: 'asdf' }, []), + new TypeError('no paths specified to add/replace'), ) t.end() }) @@ -316,7 +308,7 @@ t.test('broken open', t => { const file = resolve(dir, 'body-byte-counts.tar') const poop = new Error('poop') t.teardown(mutateFS.fail('open', poop)) - t.throws(_ => r({ sync: true, file }, ['README.md']), poop) + t.throws(() => r({ sync: true, file }, ['README.md']), poop) r({ file }, ['README.md'], er => { t.match(er, poop) t.end() @@ -332,7 +324,7 @@ t.test('broken fstat', t => { const dir = t.testdir(td) const file = resolve(dir, 'body-byte-counts.tar') t.teardown(mutateFS.fail('fstat', poop)) - t.throws(_ => r({ sync: true, file }, ['README.md']), poop) + t.throws(() => r({ sync: true, file }, ['README.md']), poop) t.end() }) t.test('async', t => { @@ -354,7 +346,7 @@ t.test('broken read', t => { const file = resolve(dir, 'body-byte-counts.tar') const poop = new Error('poop') t.teardown(mutateFS.fail('read', poop)) - t.throws(_ => r({ sync: true, file }, ['README.md']), poop) + t.throws(() => r({ sync: true, file }, ['README.md']), poop) r({ file }, ['README.md'], er => { t.match(er, poop) t.end() @@ -366,11 +358,11 @@ t.test('mtime cache', async t => { 'body-byte-counts.tar': fixtureDef['body-byte-counts.tar'], } - let mtimeCache + let mtimeCache: Map<string, Date> - const check = (file, t) => { + const check = (file: string, t: Test) => { const c = spawn('tar', ['tf', file]) - const out = [] + const out: Buffer[] = [] c.stdout.on('data', chunk => out.push(chunk)) c.on('close', (code, signal) => { t.equal(code, 0) @@ -386,9 +378,9 @@ t.test('mtime cache', async t => { 'zero-byte.txt', path.basename(__filename), ]) - const mtc = {} + const mtc: Record<string, string> = {} mtimeCache.forEach( - (_v, k) => (mtc[k] = mtimeCache.get(k).toISOString()), + (_v, k) => (mtc[k] = mtimeCache.get(k)!.toISOString()), ) t.same(mtc, { '1024-bytes.txt': '2017-04-10T16:57:47.000Z', @@ -455,7 +447,7 @@ t.test('create tarball out of another tarball', t => { 'out.tar': fs.readFileSync(path.resolve(tars, 'dir.tar')), } - const check = (out, t) => { + const check = (out: string, t: Test) => { const expect = [ 'dir/', 'Ί.txt', diff --git a/test/update.js b/test/update.js index 48bdd04b..f171539e 100644 --- a/test/update.js +++ b/test/update.js @@ -311,7 +311,7 @@ t.test('other throws', t => { t.throws(_ => u({}, ['asdf']), new TypeError('file is required')) t.throws( _ => u({ file: 'asdf' }, []), - new TypeError('no files or directories specified'), + new TypeError('no paths specified to add/replace'), ) t.end() }) diff --git a/test/writable-assignment-check.ts b/test/writable-assignment-check.ts index 46e81595..a251bc80 100644 --- a/test/writable-assignment-check.ts +++ b/test/writable-assignment-check.ts @@ -1,5 +1,5 @@ -import { Unpack } from "../src/unpack.js"; -import { WriteEntry } from "../src/write-entry.js"; +import { Unpack } from '../src/unpack.js' +import { WriteEntry } from '../src/write-entry.js' import { Parser } from '../src/parse.js' import { fileURLToPath } from 'url' From 83e97f62d8d18dec98f3e0070a9362b8bd457a76 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 29 May 2024 18:28:36 -0700 Subject: [PATCH 81/96] changelog 7.2 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbe69803..b0448c95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 7.2 + +- DRY the command definitions into a single `makeCommand` method, + and update the type signatures to more appropriately infer the + return type from the options and arguments provided. + ## 7.1 - Update minipass to v7.1.0 From ed17f588f202c598bf74d9cdcda0998e706e86a1 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 29 May 2024 18:28:48 -0700 Subject: [PATCH 82/96] 7.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ce6b7785..4b21541e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "7.1.0", + "version": "7.2.0", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From ee87da2b93a675fd91d2db9770769136bd95e129 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Tue, 18 Jun 2024 19:02:34 -0700 Subject: [PATCH 83/96] use a lockfile, add tsconfigs to git --- .gitignore | 3 + .npmrc | 3 - .tshy/build.json | 8 + .tshy/commonjs.json | 14 + .tshy/esm.json | 12 + package-lock.json | 4471 +++++++++++++++++++++++++++++++++++++++++++ package.json | 40 +- tsconfig.json | 18 + 8 files changed, 4565 insertions(+), 4 deletions(-) delete mode 100644 .npmrc create mode 100644 .tshy/build.json create mode 100644 .tshy/commonjs.json create mode 100644 .tshy/esm.json create mode 100644 package-lock.json create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 44be827b..70c32c65 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,9 @@ # keep these !**/.gitignore !/src +!/.tshy !/.commitlintrc.js +!/tsconfig.json !/.eslintrc.js !/.eslintrc.local.* !/.github/ @@ -21,6 +23,7 @@ !/LICENSE* !/map.js !/package.json +!/package-lock.json !/README* !/release-please-config.json !/scripts/ diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 529f93e7..00000000 --- a/.npmrc +++ /dev/null @@ -1,3 +0,0 @@ -; This file is automatically added by @npmcli/template-oss. Do not edit. - -package-lock=false diff --git a/.tshy/build.json b/.tshy/build.json new file mode 100644 index 00000000..aea1a9e9 --- /dev/null +++ b/.tshy/build.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDir": "../src", + "module": "nodenext", + "moduleResolution": "nodenext" + } +} diff --git a/.tshy/commonjs.json b/.tshy/commonjs.json new file mode 100644 index 00000000..5ace94d0 --- /dev/null +++ b/.tshy/commonjs.json @@ -0,0 +1,14 @@ +{ + "extends": "./build.json", + "include": [ + "../src/**/*.ts", + "../src/**/*.cts", + "../src/**/*.tsx" + ], + "exclude": [ + "../src/**/*.mts" + ], + "compilerOptions": { + "outDir": "../.tshy-build/commonjs" + } +} diff --git a/.tshy/esm.json b/.tshy/esm.json new file mode 100644 index 00000000..ff5264e6 --- /dev/null +++ b/.tshy/esm.json @@ -0,0 +1,12 @@ +{ + "extends": "./build.json", + "include": [ + "../src/**/*.ts", + "../src/**/*.mts", + "../src/**/*.tsx" + ], + "exclude": [], + "compilerOptions": { + "outDir": "../.tshy-build/esm" + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..611c7d2c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4471 @@ +{ + "name": "tar", + "version": "7.2.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tar", + "version": "7.2.0", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "devDependencies": { + "chmodr": "^1.2.0", + "end-of-stream": "^1.4.3", + "events-to-array": "^2.0.3", + "mutate-fs": "^2.1.1", + "nock": "^13.5.4", + "prettier": "^3.2.5", + "rimraf": "^5.0.5", + "tap": "^18.7.2", + "tshy": "^1.13.1", + "typedoc": "^0.25.13" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@alcalzone/ansi-tokenize": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.1.3.tgz", + "integrity": "sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=14.13.1" + } + }, + "node_modules/@alcalzone/ansi-tokenize/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@base2/pretty-print-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", + "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", + "dev": true + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@isaacs/ts-node-temp-fork-for-pr-2009": { + "version": "10.9.7", + "resolved": "https://registry.npmjs.org/@isaacs/ts-node-temp-fork-for-pr-2009/-/ts-node-temp-fork-for-pr-2009-10.9.7.tgz", + "integrity": "sha512-9f0bhUr9TnwwpgUhEpr3FjxSaH/OHaARkE2F9fM0lS4nIs2GNerrvGwQz493dk0JKlTaGYVrKbq36vA/whZ34g==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node14": "*", + "@tsconfig/node16": "*", + "@tsconfig/node18": "*", + "@tsconfig/node20": "*", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=4.2" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/@isaacs/ts-node-temp-fork-for-pr-2009/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", + "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.7.tgz", + "integrity": "sha512-WaOVvto604d5IpdCRV2KjQu8PzkfE96d50CQGKgywXh2GxXmDeUO5EWcBC4V57uFyrNqx83+MewuJh3WTR3xPA==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^4.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", + "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.0.tgz", + "integrity": "sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^4.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", + "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", + "dev": true, + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/redact": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-1.1.0.tgz", + "integrity": "sha512-PfnWuOkQgu7gCbnSsAisaX7hKOdZ4wSAhAzH3/ph5dSGau52kCRrMMGbiSQLwyTZpgldkZ49b0brkOr1AzGBHQ==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", + "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sigstore/bundle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", + "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", + "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.2.tgz", + "integrity": "sha512-c6B0ehIWxMI8wiS/bj6rHMPqeFvngFV7cDU/MY+B16P9Z3Mp9k8L93eYZ7BYzSickzuqAQqAq0V956b3Ju6mLw==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", + "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "make-fetch-happen": "^13.0.1", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", + "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2", + "tuf-js": "^2.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", + "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.1.0", + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tapjs/after": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/@tapjs/after/-/after-1.1.22.tgz", + "integrity": "sha512-8Ui8dfTFgDS3ENfzKpsWGJw+v4LHXvifaSB79chQbucuggW+nM2zzWu7grw7mDUBBR3Mknk+qL4Nb1KrnZvfWQ==", + "dev": true, + "dependencies": { + "is-actual-promise": "^1.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/after-each": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/@tapjs/after-each/-/after-each-1.1.22.tgz", + "integrity": "sha512-KKbCnMlOFspW6YoaFfzbU3kwwolF9DfP7ikGGMZItex/EB+OcLxoFV++DCWIDIl12mzQfYZMJ0wJXtHFc0ux0Q==", + "dev": true, + "dependencies": { + "function-loop": "^4.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/asserts": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tapjs/asserts/-/asserts-1.2.0.tgz", + "integrity": "sha512-QTs1kALeJKrlX9Yns3f8/hfsWgf4mdFYPN3lQKxZ/3C/DkGnjlrpVd4I2fnTC7cgJ116kwEgwhxVJUpw9QPp9A==", + "dev": true, + "dependencies": { + "@tapjs/stack": "1.2.8", + "is-actual-promise": "^1.0.1", + "tcompare": "6.4.6", + "trivial-deferred": "^2.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/before": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/@tapjs/before/-/before-1.1.22.tgz", + "integrity": "sha512-Uv2odGCtOgY/EevyDZv2rHbIbe9WGrouC6HI+lJv4whGUKgiIYTOjrssl4YxvqvnNWx289/6Tp4Kpu7EeXT7yA==", + "dev": true, + "dependencies": { + "is-actual-promise": "^1.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/before-each": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/@tapjs/before-each/-/before-each-1.1.22.tgz", + "integrity": "sha512-uKKllHDvQgTXjAm+F+29Iqcb9Bzh5U6LH45m6v/zfKPm8UNnNpJ/XxFbbsFqi0EQX2czYH0ivHfyQwiO40R8lw==", + "dev": true, + "dependencies": { + "function-loop": "^4.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/config": { + "version": "2.4.19", + "resolved": "https://registry.npmjs.org/@tapjs/config/-/config-2.4.19.tgz", + "integrity": "sha512-8fkUnf2d3g9wbnfSirXI92bx4ZO5X37nqYVb5fua9VDC2MsTLAmd4JyDSNG1ngn8/nO5o8aFNEeUaePswGId4A==", + "dev": true, + "dependencies": { + "@tapjs/core": "1.5.4", + "@tapjs/test": "1.4.4", + "chalk": "^5.2.0", + "jackspeak": "^2.3.6", + "polite-json": "^4.0.1", + "tap-yaml": "2.2.2", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4", + "@tapjs/test": "1.4.4" + } + }, + "node_modules/@tapjs/config/node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/@tapjs/core": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@tapjs/core/-/core-1.5.4.tgz", + "integrity": "sha512-kDgRxTkSRxfLbX5orDmizxuyFBLLC3Mu4mQ2dMzw/UMYkrN8jZbkKZqIR0BdXgxE+GqvVFqkYvFJImXJBygBKQ==", + "dev": true, + "dependencies": { + "@tapjs/processinfo": "^3.1.7", + "@tapjs/stack": "1.2.8", + "@tapjs/test": "1.4.4", + "async-hook-domain": "^4.0.1", + "diff": "^5.2.0", + "is-actual-promise": "^1.0.1", + "minipass": "^7.0.4", + "signal-exit": "4.1", + "tap-parser": "15.3.2", + "tap-yaml": "2.2.2", + "tcompare": "6.4.6", + "trivial-deferred": "^2.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/@tapjs/error-serdes": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@tapjs/error-serdes/-/error-serdes-1.2.2.tgz", + "integrity": "sha512-RW2aU50JR7SSAlvoTyuwouXETLM9lP+7oZ5Z+dyKhNp8mkbbz4mXKcgd9SDHY5qTh6zvVN7OFK7ev7dYWXbrWw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/filter": { + "version": "1.2.22", + "resolved": "https://registry.npmjs.org/@tapjs/filter/-/filter-1.2.22.tgz", + "integrity": "sha512-qVWbsFem2R1htQVh0+4xWMPsDPpQ2NhA/6mnlg4ApzAFvaTr5T/zK72VpR+AqPaMcMgrp4a/m5DQ03dLFqckZQ==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/fixture": { + "version": "1.2.22", + "resolved": "https://registry.npmjs.org/@tapjs/fixture/-/fixture-1.2.22.tgz", + "integrity": "sha512-ZYjkRzLSwW+cOg2CbL3GrgjatKVXcEGLQa7vjfmYVxDrPHkK7tiu3lf1KU6pFxTyqTlMMRUfMehHQrH+JjDC7Q==", + "dev": true, + "dependencies": { + "mkdirp": "^3.0.0", + "rimraf": "^5.0.5" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/intercept": { + "version": "1.2.22", + "resolved": "https://registry.npmjs.org/@tapjs/intercept/-/intercept-1.2.22.tgz", + "integrity": "sha512-OiayUlV+0fxwGM3B7JyRSwryq2kRpuWiF+4wQCiufSbbF20H4uEIlkRq1YrfUlla4zWVvHeQOQlUoqb6fSEcSQ==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.22", + "@tapjs/stack": "1.2.8" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/mock": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@tapjs/mock/-/mock-1.3.4.tgz", + "integrity": "sha512-tEz5hIdJdAGzl+KxjZol4DD7cWAdYMmvLU/QCZ5BThAOJ+FUAOxtBFA31nd7IWkMseIqcbeeqLmeMtan6QlPKA==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.22", + "@tapjs/stack": "1.2.8", + "resolve-import": "^1.4.5", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/node-serialize": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@tapjs/node-serialize/-/node-serialize-1.3.4.tgz", + "integrity": "sha512-OwnSWdNnukgIGBsgnPy1ZpBDxp274GwLx2Ag+CulhsQ+IF9rOCq5P0EQ2kbxhxRet1386kbNzgXgaEeXmDXlLQ==", + "dev": true, + "dependencies": { + "@tapjs/error-serdes": "1.2.2", + "@tapjs/stack": "1.2.8", + "tap-parser": "15.3.2" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/processinfo": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@tapjs/processinfo/-/processinfo-3.1.8.tgz", + "integrity": "sha512-FIriEB+qqArPhmVYc1PZwRHD99myRdl7C9Oe/uts04Q2LOxQ5MEmqP9XOP8vVYzpDOYwmL8OmL6eOYt9eZlQKQ==", + "dev": true, + "dependencies": { + "pirates": "^4.0.5", + "process-on-spawn": "^1.0.0", + "signal-exit": "^4.0.2", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=16.17" + } + }, + "node_modules/@tapjs/reporter": { + "version": "1.3.20", + "resolved": "https://registry.npmjs.org/@tapjs/reporter/-/reporter-1.3.20.tgz", + "integrity": "sha512-OTZeTC1/dr69mtZlRulynFH7+b7/C45MwLdLqaeTTeW2saAtojDMt7K2J8c74JlOO5+EKl71rBxrdKS6VBFqLw==", + "dev": true, + "dependencies": { + "@tapjs/config": "2.4.19", + "@tapjs/stack": "1.2.8", + "chalk": "^5.2.0", + "ink": "^4.4.1", + "minipass": "^7.0.4", + "ms": "^2.1.3", + "patch-console": "^2.0.0", + "prismjs-terminal": "^1.2.3", + "react": "^18.2.0", + "string-length": "^6.0.0", + "tap-parser": "15.3.2", + "tap-yaml": "2.2.2", + "tcompare": "6.4.6" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/reporter/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@tapjs/run": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@tapjs/run/-/run-1.5.4.tgz", + "integrity": "sha512-mwzU/KalqYOGZTTf7lPyfBdRDCoIgec69NXrq/+Le7PXYWKrRoYvIUoBGwgZYyjfiYshhnzb+ayZdtd76Lj0Kw==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.22", + "@tapjs/before": "1.1.22", + "@tapjs/config": "2.4.19", + "@tapjs/processinfo": "^3.1.7", + "@tapjs/reporter": "1.3.20", + "@tapjs/spawn": "1.1.22", + "@tapjs/stdin": "1.1.22", + "@tapjs/test": "1.4.4", + "c8": "^8.0.1", + "chalk": "^5.3.0", + "chokidar": "^3.6.0", + "foreground-child": "^3.1.1", + "glob": "^10.3.10", + "minipass": "^7.0.4", + "mkdirp": "^3.0.1", + "opener": "^1.5.2", + "pacote": "^17.0.6", + "resolve-import": "^1.4.5", + "rimraf": "^5.0.5", + "semver": "^7.6.0", + "signal-exit": "^4.1.0", + "tap-parser": "15.3.2", + "tap-yaml": "2.2.2", + "tcompare": "6.4.6", + "trivial-deferred": "^2.0.0", + "which": "^4.0.0" + }, + "bin": { + "tap-run": "dist/esm/index.js" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/run/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@tapjs/run/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tapjs/snapshot": { + "version": "1.2.22", + "resolved": "https://registry.npmjs.org/@tapjs/snapshot/-/snapshot-1.2.22.tgz", + "integrity": "sha512-6nhNY6uFPnQEVQ8vuxV3rKiC7NXDY5k/Bv1bPatfo//6z1T41INfQbnfwQXoufaHveLPpGBTLwpOWjtFsUHgdg==", + "dev": true, + "dependencies": { + "is-actual-promise": "^1.0.1", + "tcompare": "6.4.6", + "trivial-deferred": "^2.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/spawn": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/@tapjs/spawn/-/spawn-1.1.22.tgz", + "integrity": "sha512-/MbFSmSpvLA0N2rKd8rI0vMLYM+0E3OB+doj+YUZe5m3G0YCHTBzZrnFGLw7Am1VsaREy4fSgchNEdn1NyikcQ==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/stack": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@tapjs/stack/-/stack-1.2.8.tgz", + "integrity": "sha512-VC8h6U62ScerTKN+MYpRPiwH2bCL65S6v1wcj1hukE2hojLcRvVdET7S3ZtRfSj/eNWW/5OVfzTpHiGjEYD6Xg==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/stdin": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/@tapjs/stdin/-/stdin-1.1.22.tgz", + "integrity": "sha512-JUyzZHG01iM6uDfplVGRiK+OdNalwl5Okv+eljHBdZOA8kO3hHI6N9bkZa472/st4NBj0lcMMGb2IKGgIBBUQg==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/test": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@tapjs/test/-/test-1.4.4.tgz", + "integrity": "sha512-I0mzxs8+RUULd9g0R6+LXsLzkeqhu5jJPpA7w5BzTxA++jQ0ACjyHs1BBy1IhhP9DeZ5N2LPg+WxLs7Dijs9Uw==", + "dev": true, + "dependencies": { + "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.5", + "@tapjs/after": "1.1.22", + "@tapjs/after-each": "1.1.22", + "@tapjs/asserts": "1.2.0", + "@tapjs/before": "1.1.22", + "@tapjs/before-each": "1.1.22", + "@tapjs/filter": "1.2.22", + "@tapjs/fixture": "1.2.22", + "@tapjs/intercept": "1.2.22", + "@tapjs/mock": "1.3.4", + "@tapjs/node-serialize": "1.3.4", + "@tapjs/snapshot": "1.2.22", + "@tapjs/spawn": "1.1.22", + "@tapjs/stdin": "1.1.22", + "@tapjs/typescript": "1.4.4", + "@tapjs/worker": "1.1.22", + "glob": "^10.3.10", + "jackspeak": "^2.3.6", + "mkdirp": "^3.0.0", + "resolve-import": "^1.4.5", + "rimraf": "^5.0.5", + "sync-content": "^1.0.1", + "tap-parser": "15.3.2", + "tshy": "^1.12.0", + "typescript": "5.2" + }, + "bin": { + "generate-tap-test-class": "scripts/build.mjs" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/test/node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/@tapjs/test/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@tapjs/typescript": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@tapjs/typescript/-/typescript-1.4.4.tgz", + "integrity": "sha512-Mf2vIK1yk5ipQRmuIznFtC8Iboti0p0D90ENDZdEx678h60vAVPh9vebVX+oQ0LccAHGyu/CiOSFL4Za8b5/Rg==", + "dev": true, + "dependencies": { + "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.5" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tapjs/worker": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/@tapjs/worker/-/worker-1.1.22.tgz", + "integrity": "sha512-1PO9Qstfevr4Wdh318eC3O1mytSyXT3q/K6EeivBhnuPeyHsy3QCAd1bfVD7gqzWNbJ/UzeGN3knfIi5qXifmA==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "1.5.4" + } + }, + "node_modules/@tsconfig/node14": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-14.1.2.tgz", + "integrity": "sha512-1vncsbfCZ3TBLPxesRYz02Rn7SNJfbLoDVkcZ7F/ixOV6nwxwgdhD1mdPcc5YQ413qBJ8CvMxXMFfJ7oawjo7Q==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-16.1.3.tgz", + "integrity": "sha512-9nTOUBn+EMKO6rtSZJk+DcqsfgtlERGT9XPJ5PRj/HNENPCBY1yu/JEj5wT6GLtbCLBO2k46SeXDaY0pjMqypw==", + "dev": true + }, + "node_modules/@tsconfig/node18": { + "version": "18.2.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.4.tgz", + "integrity": "sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ==", + "dev": true + }, + "node_modules/@tsconfig/node20": { + "version": "20.1.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.4.tgz", + "integrity": "sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==", + "dev": true + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", + "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", + "dev": true, + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.5.tgz", + "integrity": "sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==", + "dev": true, + "peer": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/acorn": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aggregate-error/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", + "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", + "dev": true + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/async-hook-domain": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-4.0.1.tgz", + "integrity": "sha512-bSktexGodAjfHWIrSrrqxqWzf1hWBZBpmPNZv+TYUMyWa2eoefFc6q6H1+KtdHYSz35lrhWdmXt/XK9wNEZvww==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/auto-bind": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-5.0.1.tgz", + "integrity": "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/c8": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/c8/-/c8-8.0.1.tgz", + "integrity": "sha512-EINpopxZNH1mETuI0DzRA4MZpAUH+IFiRhnmFD3vFr3vdrgxqi3VfE3KL0AIL+zDq8rC9bZqwM/VDmmoe04y7w==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/c8/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/c8/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/c8/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/c8/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/c8/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/c8/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/cacache": { + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", + "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chmodr": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/chmodr/-/chmodr-1.2.0.tgz", + "integrity": "sha512-Y5uI7Iq/Az6HgJEL6pdw7THVd7jbVOTPwsmcPOBjQL8e3N+pz872kzK5QxYGEy21iRys+iHWV0UZQXDFJo1hyA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "engines": { + "node": ">=18" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/code-excerpt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", + "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", + "dev": true, + "dependencies": { + "convert-to-spaces": "^2.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/convert-to-spaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", + "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/events-to-array": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-2.0.3.tgz", + "integrity": "sha512-f/qE2gImHRa4Cp2y1stEOSgw8wTFyUdVJX7G//bMwbaV9JqISFxg99NbmVQeP7YLnDUZ2un851jlaDrlpmGehQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-loop": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-4.0.0.tgz", + "integrity": "sha512-f34iQBedYF3XcI93uewZZOnyscDragxgTK/eTvVB74k3fCD0ZorOi5BV9GS4M8rz/JoNi0Kl3qX5Y9MH3S/CLQ==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.2.tgz", + "integrity": "sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", + "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ink": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/ink/-/ink-4.4.1.tgz", + "integrity": "sha512-rXckvqPBB0Krifk5rn/5LvQGmyXwCUpBfmTwbkQNBY9JY8RSl3b8OftBNEYxg4+SWUhEKcPifgope28uL9inlA==", + "dev": true, + "dependencies": { + "@alcalzone/ansi-tokenize": "^0.1.3", + "ansi-escapes": "^6.0.0", + "auto-bind": "^5.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "cli-cursor": "^4.0.0", + "cli-truncate": "^3.1.0", + "code-excerpt": "^4.0.0", + "indent-string": "^5.0.0", + "is-ci": "^3.0.1", + "is-lower-case": "^2.0.2", + "is-upper-case": "^2.0.2", + "lodash": "^4.17.21", + "patch-console": "^2.0.0", + "react-reconciler": "^0.29.0", + "scheduler": "^0.23.0", + "signal-exit": "^3.0.7", + "slice-ansi": "^6.0.0", + "stack-utils": "^2.0.6", + "string-width": "^5.1.2", + "type-fest": "^0.12.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0", + "ws": "^8.12.0", + "yoga-wasm-web": "~0.3.3" + }, + "engines": { + "node": ">=14.16" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "react": ">=18.0.0", + "react-devtools-core": "^4.19.1" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-devtools-core": { + "optional": true + } + } + }, + "node_modules/ink/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-actual-promise": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-actual-promise/-/is-actual-promise-1.0.2.tgz", + "integrity": "sha512-xsFiO1of0CLsQnPZ1iXHNTyR9YszOeWKYv+q6n8oSFW3ipooFJ1j1lbRMgiMCr+pp2gLruESI4zb5Ak6eK5OnQ==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz", + "integrity": "sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-2.0.2.tgz", + "integrity": "sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", + "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minizlib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.1.tgz", + "integrity": "sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==", + "dependencies": { + "minipass": "^7.0.4", + "rimraf": "^5.0.5" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mutate-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mutate-fs/-/mutate-fs-2.1.1.tgz", + "integrity": "sha512-WI5pPPUNiWqaK2XdK94AVpxIc8GmZEXYlLfFbWuc4gUtBGHTK92jdPqFdx/lilxgb5Ep7tQ15NqCcJEOeq6wdA==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nock": { + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.4.tgz", + "integrity": "sha512-yAyTfdeNJGGBFxWdzSKCBYxs5FxLbCg5X5Q4ets974hcQzG1+qCxvIyOo4j2Ry6MUlhWVMX4OoYDefAIIwupjw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, + "node_modules/node-gyp": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", + "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/node-gyp/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.1.tgz", + "integrity": "sha512-6rvCfeRW+OEZagAB4lMLSNuTNYZWLVtKccK79VSTf//yTY5VOCgcpH80O+bZK8Neps7pUnd5G+QlMg1yV/2iZQ==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", + "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", + "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.1.tgz", + "integrity": "sha512-Udm1f0l2nXb3wxDpKjfohwgdFUSV50UVwzEIpDXVsbDMXVIEF81a/i0UhuQbhrPMMmdiq3+YMFLFIRVLs3hxQw==", + "dev": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.2.1.tgz", + "integrity": "sha512-8l+7jxhim55S85fjiDGJ1rZXBWGtRLi1OSb4Z3BPLObPuIaeKRlPRiYMSHU4/81ck3t71Z+UwDDl47gcpmfQQA==", + "dev": true, + "dependencies": { + "@npmcli/redact": "^1.1.0", + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm-registry-fetch/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-registry-fetch/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + }, + "node_modules/pacote": { + "version": "17.0.7", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.7.tgz", + "integrity": "sha512-sgvnoUMlkv9xHwDUKjKQFXVyUi8dtJGKp3vg6sYy+TxbDic5RjZCHF3ygv0EJgNRZ2GfRONjlKPUfokJ9lDpwQ==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^4.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/patch-console": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", + "integrity": "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/polite-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/polite-json/-/polite-json-4.0.1.tgz", + "integrity": "sha512-8LI5ZeCPBEb4uBbcYKNVwk4jgqNx1yHReWoW4H4uUihWlSqZsUDfSITrRhjliuPgxsNPFhNSudGO2Zu4cbWinQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/prismjs-terminal": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prismjs-terminal/-/prismjs-terminal-1.2.3.tgz", + "integrity": "sha512-xc0zuJ5FMqvW+DpiRkvxURlz98DdfDsZcFHdO699+oL+ykbFfgI7O4VDEgUyc07BSL2NHl3zdb8m/tZ/aaqUrw==", + "dev": true, + "dependencies": { + "chalk": "^5.2.0", + "prismjs": "^1.29.0", + "string-length": "^6.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dev": true, + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-element-to-jsx-string": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", + "integrity": "sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==", + "dev": true, + "dependencies": { + "@base2/pretty-print-object": "1.0.1", + "is-plain-object": "5.0.0", + "react-is": "18.1.0" + }, + "peerDependencies": { + "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", + "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0" + } + }, + "node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/react-reconciler": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.2.tgz", + "integrity": "sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/read-package-json": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.1.tgz", + "integrity": "sha512-8PcDiZ8DXUjLf687Ol4BR8Bpm2umR7vhoZOzNRt+uxD9GpBh/K+CAAALVIiYFknmvlmyg7hM7BSNUXPaCCqd0Q==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", + "dev": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-import": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.5.tgz", + "integrity": "sha512-HXb4YqODuuXT7Icq1Z++0g2JmhgbUHSs3VT2xR83gqvAPUikYT2Xk+562KHQgiaNkbBOlPddYrDLsC44qQggzw==", + "dev": true, + "dependencies": { + "glob": "^10.3.3", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz", + "integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==", + "dev": true, + "dependencies": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sigstore": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", + "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "@sigstore/sign": "^2.3.2", + "@sigstore/tuf": "^2.3.4", + "@sigstore/verify": "^1.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/slice-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-6.0.0.tgz", + "integrity": "sha512-6bn4hRfkTvDfUoEQYkERg0BVF1D0vrX9HEkMl08uDiNWvVvjylLHvZFZWkDo6wjT8tUctbYl1nCOuE66ZTaUtA==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "node_modules/ssri": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-6.0.0.tgz", + "integrity": "sha512-1U361pxZHEQ+FeSjzqRpV+cu2vTzYeWeafXFLykiFlv4Vc0n3njgU8HrMbyik5uwm77naWMuVG8fhEF+Ovb1Kg==", + "dev": true, + "dependencies": { + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sync-content": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/sync-content/-/sync-content-1.0.2.tgz", + "integrity": "sha512-znd3rYiiSxU3WteWyS9a6FXkTA/Wjk8WQsOyzHbineeL837dLn3DA4MRhsIX3qGcxDMH6+uuFV4axztssk7wEQ==", + "dev": true, + "dependencies": { + "glob": "^10.2.6", + "mkdirp": "^3.0.1", + "path-scurry": "^1.9.2", + "rimraf": "^5.0.1" + }, + "bin": { + "sync-content": "dist/mjs/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tap": { + "version": "18.8.0", + "resolved": "https://registry.npmjs.org/tap/-/tap-18.8.0.tgz", + "integrity": "sha512-tX02yXmzBcemYfNGKtTJFf3cn7e8VgBvxKswaew8YnrE+1cUZtxyN0GhMzPQ5cWznVz47DfgcuYR1QtCr+4LOw==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.22", + "@tapjs/after-each": "1.1.22", + "@tapjs/asserts": "1.2.0", + "@tapjs/before": "1.1.22", + "@tapjs/before-each": "1.1.22", + "@tapjs/core": "1.5.4", + "@tapjs/filter": "1.2.22", + "@tapjs/fixture": "1.2.22", + "@tapjs/intercept": "1.2.22", + "@tapjs/mock": "1.3.4", + "@tapjs/node-serialize": "1.3.4", + "@tapjs/run": "1.5.4", + "@tapjs/snapshot": "1.2.22", + "@tapjs/spawn": "1.1.22", + "@tapjs/stdin": "1.1.22", + "@tapjs/test": "1.4.4", + "@tapjs/typescript": "1.4.4", + "@tapjs/worker": "1.1.22", + "resolve-import": "^1.4.5" + }, + "bin": { + "tap": "dist/esm/run.mjs" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tap-parser": { + "version": "15.3.2", + "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-15.3.2.tgz", + "integrity": "sha512-uvauHuQqAMwfeFVxNpFXhvnWLVL0sthnHk4TxRM3cUy6+dejO9fatoKR7YejbMu4+2/1nR6UQE9+eUcX3PUmsA==", + "dev": true, + "dependencies": { + "events-to-array": "^2.0.3", + "tap-yaml": "2.2.2" + }, + "bin": { + "tap-parser": "bin/cmd.cjs" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/tap-yaml": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-2.2.2.tgz", + "integrity": "sha512-MWG4OpAKtNoNVjCz/BqlDJiwTM99tiHRhHPS4iGOe1ZS0CgM4jSFH92lthSFvvy4EdDjQZDV7uYqUFlU9JuNhw==", + "dev": true, + "dependencies": { + "yaml": "^2.4.1", + "yaml-types": "^0.3.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/tcompare": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-6.4.6.tgz", + "integrity": "sha512-sxvgCgO2GAIWHibnK4zLvvi9GHd/ZlR9DOUJ4ufwvNtkdKE2I9MNwJUwzYvOmGrJXMcfhhw0CDBb+6j0ia+I7A==", + "dev": true, + "dependencies": { + "diff": "^5.2.0", + "react-element-to-jsx-string": "^15.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trivial-deferred": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-2.0.0.tgz", + "integrity": "sha512-iGbM7X2slv9ORDVj2y2FFUq3cP/ypbtu2nQ8S38ufjL0glBABvmR9pTdsib1XtS2LUhhLMbelaBUaf/s5J3dSw==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tshy": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.15.1.tgz", + "integrity": "sha512-7p30vmXaNX7OL1yLy/MYUtO0SJOm9fQSnzk3DXaM+LmQosooCB4elVeHAGIIZdABhL2E8dx5t/5msR5lh0xnaQ==", + "dev": true, + "dependencies": { + "chalk": "^5.3.0", + "chokidar": "^3.6.0", + "foreground-child": "^3.1.1", + "minimatch": "^9.0.4", + "mkdirp": "^3.0.1", + "polite-json": "^4.0.1", + "resolve-import": "^1.4.5", + "rimraf": "^5.0.1", + "sync-content": "^1.0.2", + "typescript": "^5.4.5", + "walk-up-path": "^3.0.1" + }, + "bin": { + "tshy": "dist/esm/index.js" + }, + "engines": { + "node": "16 >=16.17 || 18 >=18.15.0 || >=20.6.1" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/tuf-js": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", + "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", + "dev": true, + "dependencies": { + "@tufjs/models": "2.0.1", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/type-fest": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", + "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedoc": { + "version": "0.25.13", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.13.tgz", + "integrity": "sha512-pQqiwiJ+Z4pigfOnnysObszLiU3mVLWAExSPf+Mu06G/qsc3wzbuM56SZQvONhHLncLUhYzOVkjFFpFfL5AzhQ==", + "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.3.0", + "minimatch": "^9.0.3", + "shiki": "^0.14.7" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "peer": true + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, + "node_modules/walk-up-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", + "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "engines": { + "node": ">=18" + } + }, + "node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yaml-types": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yaml-types/-/yaml-types-0.3.0.tgz", + "integrity": "sha512-i9RxAO/LZBiE0NJUy9pbN5jFz5EasYDImzRkj8Y81kkInTi1laia3P3K/wlMKzOxFQutZip8TejvQP/DwgbU7A==", + "dev": true, + "engines": { + "node": ">= 16", + "npm": ">= 7" + }, + "peerDependencies": { + "yaml": "^2.3.0" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoga-wasm-web": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz", + "integrity": "sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==", + "dev": true + } + } +} diff --git a/package.json b/package.json index 4b21541e..6cd378d2 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", - "minipass": "^7.1.0", + "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" @@ -92,190 +92,228 @@ "./package.json": "./package.json", ".": { "import": { + "source": "./src/index.ts", "types": "./dist/esm/index.d.ts", "default": "./dist/esm/index.js" }, "require": { + "source": "./src/index.ts", "types": "./dist/commonjs/index.d.ts", "default": "./dist/commonjs/index.js" } }, "./c": { "import": { + "source": "./src/create.ts", "types": "./dist/esm/create.d.ts", "default": "./dist/esm/create.js" }, "require": { + "source": "./src/create.ts", "types": "./dist/commonjs/create.d.ts", "default": "./dist/commonjs/create.js" } }, "./create": { "import": { + "source": "./src/create.ts", "types": "./dist/esm/create.d.ts", "default": "./dist/esm/create.js" }, "require": { + "source": "./src/create.ts", "types": "./dist/commonjs/create.d.ts", "default": "./dist/commonjs/create.js" } }, "./replace": { "import": { + "source": "./src/create.ts", "types": "./dist/esm/create.d.ts", "default": "./dist/esm/create.js" }, "require": { + "source": "./src/create.ts", "types": "./dist/commonjs/create.d.ts", "default": "./dist/commonjs/create.js" } }, "./r": { "import": { + "source": "./src/create.ts", "types": "./dist/esm/create.d.ts", "default": "./dist/esm/create.js" }, "require": { + "source": "./src/create.ts", "types": "./dist/commonjs/create.d.ts", "default": "./dist/commonjs/create.js" } }, "./list": { "import": { + "source": "./src/list.ts", "types": "./dist/esm/list.d.ts", "default": "./dist/esm/list.js" }, "require": { + "source": "./src/list.ts", "types": "./dist/commonjs/list.d.ts", "default": "./dist/commonjs/list.js" } }, "./t": { "import": { + "source": "./src/list.ts", "types": "./dist/esm/list.d.ts", "default": "./dist/esm/list.js" }, "require": { + "source": "./src/list.ts", "types": "./dist/commonjs/list.d.ts", "default": "./dist/commonjs/list.js" } }, "./update": { "import": { + "source": "./src/update.ts", "types": "./dist/esm/update.d.ts", "default": "./dist/esm/update.js" }, "require": { + "source": "./src/update.ts", "types": "./dist/commonjs/update.d.ts", "default": "./dist/commonjs/update.js" } }, "./u": { "import": { + "source": "./src/update.ts", "types": "./dist/esm/update.d.ts", "default": "./dist/esm/update.js" }, "require": { + "source": "./src/update.ts", "types": "./dist/commonjs/update.d.ts", "default": "./dist/commonjs/update.js" } }, "./extract": { "import": { + "source": "./src/extract.ts", "types": "./dist/esm/extract.d.ts", "default": "./dist/esm/extract.js" }, "require": { + "source": "./src/extract.ts", "types": "./dist/commonjs/extract.d.ts", "default": "./dist/commonjs/extract.js" } }, "./x": { "import": { + "source": "./src/extract.ts", "types": "./dist/esm/extract.d.ts", "default": "./dist/esm/extract.js" }, "require": { + "source": "./src/extract.ts", "types": "./dist/commonjs/extract.d.ts", "default": "./dist/commonjs/extract.js" } }, "./pack": { "import": { + "source": "./src/pack.ts", "types": "./dist/esm/pack.d.ts", "default": "./dist/esm/pack.js" }, "require": { + "source": "./src/pack.ts", "types": "./dist/commonjs/pack.d.ts", "default": "./dist/commonjs/pack.js" } }, "./unpack": { "import": { + "source": "./src/unpack.ts", "types": "./dist/esm/unpack.d.ts", "default": "./dist/esm/unpack.js" }, "require": { + "source": "./src/unpack.ts", "types": "./dist/commonjs/unpack.d.ts", "default": "./dist/commonjs/unpack.js" } }, "./parse": { "import": { + "source": "./src/parse.ts", "types": "./dist/esm/parse.d.ts", "default": "./dist/esm/parse.js" }, "require": { + "source": "./src/parse.ts", "types": "./dist/commonjs/parse.d.ts", "default": "./dist/commonjs/parse.js" } }, "./read-entry": { "import": { + "source": "./src/read-entry.ts", "types": "./dist/esm/read-entry.d.ts", "default": "./dist/esm/read-entry.js" }, "require": { + "source": "./src/read-entry.ts", "types": "./dist/commonjs/read-entry.d.ts", "default": "./dist/commonjs/read-entry.js" } }, "./write-entry": { "import": { + "source": "./src/write-entry.ts", "types": "./dist/esm/write-entry.d.ts", "default": "./dist/esm/write-entry.js" }, "require": { + "source": "./src/write-entry.ts", "types": "./dist/commonjs/write-entry.d.ts", "default": "./dist/commonjs/write-entry.js" } }, "./header": { "import": { + "source": "./src/header.ts", "types": "./dist/esm/header.d.ts", "default": "./dist/esm/header.js" }, "require": { + "source": "./src/header.ts", "types": "./dist/commonjs/header.d.ts", "default": "./dist/commonjs/header.js" } }, "./pax": { "import": { + "source": "./src/pax.ts", "types": "./dist/esm/pax.d.ts", "default": "./dist/esm/pax.js" }, "require": { + "source": "./src/pax.ts", "types": "./dist/commonjs/pax.d.ts", "default": "./dist/commonjs/pax.js" } }, "./types": { "import": { + "source": "./src/types.ts", "types": "./dist/esm/types.d.ts", "default": "./dist/esm/types.js" }, "require": { + "source": "./src/types.ts", "types": "./dist/commonjs/types.d.ts", "default": "./dist/commonjs/types.js" } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..7f39495d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "inlineSources": true, + "jsx": "react", + "module": "nodenext", + "moduleResolution": "nodenext", + "noUncheckedIndexedAccess": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "target": "es2022" + } +} From 61b97894c9fa1168cd7f9b2d5c23bfe85343f770 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Tue, 18 Jun 2024 19:26:19 -0700 Subject: [PATCH 84/96] add onWriteEntry method fix: https://github.com/isaacs/node-tar/issues/316 --- src/options.ts | 11 +++++++++++ src/pack.ts | 9 ++++++--- test/pack.js | 4 +++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/options.ts b/src/options.ts index 5dab6724..80967555 100644 --- a/src/options.ts +++ b/src/options.ts @@ -4,6 +4,7 @@ import { type GzipOptions, type ZlibOptions } from 'minizlib' import { type Stats } from 'node:fs' import { type ReadEntry } from './read-entry.js' import { type WarnData } from './warn-method.js' +import { WriteEntry } from './write-entry.js' const argmap = new Map<keyof TarOptionsWithAliases, keyof TarOptions>( [ @@ -275,6 +276,16 @@ export interface TarOptions { */ noResume?: boolean + /** + * When creating, updating, or replacing within archives, this method will + * be called with each WriteEntry that is created. + * + * It's not called 'onentry' because that's already taken for the ReadEntry + * when reading archives, and it's just easier to only have one type of + * options object that this whole library can pass around without issue. + */ + onWriteEntry?: (entry: WriteEntry) => any + /** * When extracting or listing archives, this method will be called with * each entry that is not excluded by a `filter`. diff --git a/src/pack.ts b/src/pack.ts index 075d4282..ce095884 100644 --- a/src/pack.ts +++ b/src/pack.ts @@ -92,6 +92,7 @@ export class Pack jobs: number; [WRITEENTRYCLASS]: typeof WriteEntry | typeof WriteEntrySync; + onWriteEntry?: (entry: WriteEntry) => void [QUEUE]: Yallist<PackJob>; [JOBS]: number = 0; [PROCESSING]: boolean = false; @@ -110,6 +111,7 @@ export class Pack this.linkCache = opt.linkCache || new Map() this.statCache = opt.statCache || new Map() this.readdirCache = opt.readdirCache || new Map() + this.onWriteEntry = opt.onWriteEntry this[WRITEENTRYCLASS] = WriteEntry if (typeof opt.onwarn === 'function') { @@ -154,7 +156,7 @@ export class Pack if (opt.mtime) this.mtime = opt.mtime this.filter = - typeof opt.filter === 'function' ? opt.filter : _ => true + typeof opt.filter === 'function' ? opt.filter : () => true this[QUEUE] = new Yallist<PackJob>() this[JOBS] = 0 @@ -385,8 +387,9 @@ export class Pack [ENTRY](job: PackJob) { this[JOBS] += 1 try { - return new this[WRITEENTRYCLASS](job.path, this[ENTRYOPT](job)) - .on('end', () => this[JOBDONE](job)) + const e = new this[WRITEENTRYCLASS](job.path, this[ENTRYOPT](job)) + this.onWriteEntry?.(e) + return e.on('end', () => this[JOBDONE](job)) .on('error', er => this.emit('error', er)) } catch (er) { this.emit('error', er) diff --git a/test/pack.js b/test/pack.js index c64a92b2..02276b9c 100644 --- a/test/pack.js +++ b/test/pack.js @@ -56,7 +56,8 @@ t.test('set up', t => { t.test('pack a file', t => { const out = [] - new Pack({ cwd: files }) + const seen = [] + new Pack({ cwd: files, onWriteEntry: e => seen.push(e) }) .end('one-byte.txt') .on('data', c => out.push(c)) .on('end', _ => { @@ -98,6 +99,7 @@ t.test('pack a file', t => { ) const hs = new Header(sync) t.match(hs, expect) + t.strictSame(seen.map(e => e.path), ['one-byte.txt']) t.end() }) }) From 556a13c7c6733cab8baf29f8d382a3bef3f6fb07 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Tue, 18 Jun 2024 19:26:34 -0700 Subject: [PATCH 85/96] 7.3.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 611c7d2c..27284fd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "tar", - "version": "7.2.0", + "version": "7.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tar", - "version": "7.2.0", + "version": "7.3.0", "license": "ISC", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", diff --git a/package.json b/package.json index 6cd378d2..35f9198f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "7.2.0", + "version": "7.3.0", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From 5c1113b851a1499838188a74b6ab35665fd8b245 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Tue, 18 Jun 2024 19:36:30 -0700 Subject: [PATCH 86/96] s/onentry/onReadEntry/g for clarity, deprecate old name --- CHANGELOG.md | 8 ++++++++ README.md | 43 +++++++++++++++++++++++++++---------------- src/create.ts | 4 ++-- src/list.ts | 12 ++++++------ src/options.ts | 16 ++++++++++------ src/parse.ts | 4 ++-- src/replace.ts | 4 ++-- test/create.ts | 2 +- test/list.ts | 34 +++++++++++++++++----------------- test/parse.js | 8 ++++---- test/replace.ts | 2 +- test/unpack.js | 8 ++++---- test/write-entry.js | 4 ++-- 13 files changed, 86 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0448c95..0ee7b913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 7.4 + +- Deprecate `onentry` in favor of `onReadEntry` for clarity. + +## 7.3 + +- Add `onWriteEntry` option + ## 7.2 - DRY the command definitions into a single `makeCommand` method, diff --git a/README.md b/README.md index 3471a4a5..feb225cc 100644 --- a/README.md +++ b/README.md @@ -214,7 +214,7 @@ To replicate `tar tf my-tarball.tgz`, do this: ```js tar.t({ file: 'my-tarball.tgz', - onentry: entry => { .. do whatever with it .. } + onReadEntry: entry => { .. do whatever with it .. } }) ``` @@ -225,7 +225,7 @@ const getEntryFilenames = async tarballFilename => { const filenames = [] await tar.t({ file: tarballFilename, - onentry: entry => filenames.push(entry.path), + onReadEntry: entry => filenames.push(entry.path), }) return filenames } @@ -250,7 +250,7 @@ const getEntryFilenamesSync = tarballFilename => { const filenames = [] tar.t({ file: tarballFilename, - onentry: entry => filenames.push(entry.path), + onReadEntry: entry => filenames.push(entry.path), sync: true, }) return filenames @@ -335,6 +335,9 @@ The following options are supported: [Alias: `m`, `no-mtime`] - `mtime` Set to a `Date` object to force a specific `mtime` for everything added to the archive. Overridden by `noMtime`. +- `onWriteEntry` Called with each `WriteEntry` or + `WriteEntrySync` that is created in the course of writing the + archive. The following options are mostly internal, but can be modified in some advanced use cases, such as re-using caches between runs. @@ -427,7 +430,7 @@ The following options are supported: the archive entry. If a falsey value is provided, then the entry is written to disk as normal. (To exclude items from extraction, use the `filter` option described above.) -- `onentry` A function that gets called with `(entry)` for each entry +- `onReadEntry` A function that gets called with `(entry)` for each entry that passes the filter. - `onwarn` A function that will get called with `(code, message, data)` for any warnings encountered. (See "Warnings and Errors") @@ -478,7 +481,7 @@ entries, use the `tar.Parse` class instead.) If a `file` option _is_ provided, then the return value will be a promise that resolves when the file has been fully traversed in async mode, or -`undefined` if `sync: true` is set. Thus, you _must_ specify an `onentry` +`undefined` if `sync: true` is set. Thus, you _must_ specify an `onReadEntry` method in order to do anything useful with the data it parses. The following options are supported: @@ -493,13 +496,13 @@ The following options are supported: - `filter` A function that gets called with `(path, entry)` for each entry being listed. Return `true` to emit the entry from the archive, or `false` to skip it. -- `onentry` A function that gets called with `(entry)` for each entry +- `onReadEntry` A function that gets called with `(entry)` for each entry that passes the filter. This is important for when `file` is set, because there is no other way to do anything useful with this method. - `maxReadSize` The maximum buffer size for `fs.read()` operations. Defaults to 16 MB. - `noResume` By default, `entry` streams are resumed immediately after - the call to `onentry`. Set `noResume: true` to suppress this + the call to `onReadEntry`. Set `noResume: true` to suppress this behavior. Note that by opting into this, the stream will never complete until the entry data is consumed. - `onwarn` A function that will get called with `(code, message, data)` for @@ -556,6 +559,9 @@ The following options are supported: [Alias: `m`, `no-mtime`] - `mtime` Set to a `Date` object to force a specific `mtime` for everything added to the archive. Overridden by `noMtime`. +- `onWriteEntry` Called with each `WriteEntry` or + `WriteEntrySync` that is created in the course of writing the + archive. ### tar.r(options, fileList, callback) [alias: tar.replace] @@ -608,10 +614,13 @@ The following options are supported: [Alias: `m`, `no-mtime`] - `mtime` Set to a `Date` object to force a specific `mtime` for everything added to the archive. Overridden by `noMtime`. +- `onWriteEntry` Called with each `WriteEntry` or + `WriteEntrySync` that is created in the course of writing the + archive. ## Low-Level API -### class tar.Pack +### class Pack A readable tar stream. @@ -640,7 +649,6 @@ The following options are supported: default" for most unix systems, based on a `umask` value of `0o22`. - `preservePaths` Allow absolute paths. By default, `/` is stripped from absolute paths. - - `linkCache` A Map object containing the device and inode value for any file whose nlink is > 1, to identify hard links. - `statCache` A Map object that caches calls `lstat`. @@ -661,6 +669,9 @@ The following options are supported: `tar.update` or the `keepNewer` option with the resulting tar archive. - `mtime` Set to a `Date` object to force a specific `mtime` for everything added to the archive. Overridden by `noMtime`. +- `onWriteEntry` Called with each `WriteEntry` or + `WriteEntrySync` that is created in the course of writing the + archive. #### add(path) @@ -674,11 +685,11 @@ Adds an entry to the archive. Returns true if flushed. Finishes the archive. -### class tar.Pack.Sync +### class PackSync -Synchronous version of `tar.Pack`. +Synchronous version of `Pack`. -### class tar.Unpack +### class Unpack A writable stream that unpacks a tar archive onto the file system. @@ -757,7 +768,7 @@ Most unpack errors will cause a `warn` event to be emitted. If the written to disk as normal. (To exclude items from extraction, use the `filter` option described above.) - `strict` Treat warnings as crash-worthy errors. Default false. -- `onentry` A function that gets called with `(entry)` for each entry +- `onReadEntry` A function that gets called with `(entry)` for each entry that passes the filter. - `onwarn` A function that will get called with `(code, message, data)` for any warnings encountered. (See "Warnings and Errors") @@ -775,9 +786,9 @@ Most unpack errors will cause a `warn` event to be emitted. If the warning and skip the entry. Set to `Infinity` to remove the limitation. -### class tar.Unpack.Sync +### class UnpackSync -Synchronous version of `tar.Unpack`. +Synchronous version of `Unpack`. Note that using an asynchronous stream type with the `transform` option will cause undefined behavior in sync unpack streams. @@ -810,7 +821,7 @@ The following options are supported: - `filter` A function that gets called with `(path, entry)` for each entry being listed. Return `true` to emit the entry from the archive, or `false` to skip it. -- `onentry` A function that gets called with `(entry)` for each entry +- `onReadEntry` A function that gets called with `(entry)` for each entry that passes the filter. - `onwarn` A function that will get called with `(code, message, data)` for any warnings encountered. (See "Warnings and Errors") diff --git a/src/create.ts b/src/create.ts index b3fc260e..13d79852 100644 --- a/src/create.ts +++ b/src/create.ts @@ -45,7 +45,7 @@ const addFilesSync = (p: PackSync, files: string[]) => { file: path.resolve(p.cwd, file.slice(1)), sync: true, noResume: true, - onentry: entry => p.add(entry), + onReadEntry: entry => p.add(entry), }) } else { p.add(file) @@ -64,7 +64,7 @@ const addFilesAsync = async ( await list({ file: path.resolve(String(p.cwd), file.slice(1)), noResume: true, - onentry: entry => { + onReadEntry: entry => { p.add(entry) }, }) diff --git a/src/list.ts b/src/list.ts index 3cdfbb14..eab4b78c 100644 --- a/src/list.ts +++ b/src/list.ts @@ -11,12 +11,12 @@ import { import { Parser } from './parse.js' import { stripTrailingSlashes } from './strip-trailing-slashes.js' -const onentryFunction = (opt: TarOptions) => { - const onentry = opt.onentry - opt.onentry = - onentry ? +const onReadEntryFunction = (opt: TarOptions) => { + const onReadEntry = opt.onReadEntry + opt.onReadEntry = + onReadEntry ? e => { - onentry(e) + onReadEntry(e) e.resume() } : e => e.resume() @@ -119,6 +119,6 @@ export const list = makeCommand( opt => new Parser(opt), (opt, files) => { if (files?.length) filesFilter(opt, files) - if (!opt.noResume) onentryFunction(opt) + if (!opt.noResume) onReadEntryFunction(opt) }, ) diff --git a/src/options.ts b/src/options.ts index 80967555..c0d8aac1 100644 --- a/src/options.ts +++ b/src/options.ts @@ -27,6 +27,7 @@ const argmap = new Map<keyof TarOptionsWithAliases, keyof TarOptions>( ['p', 'preserveOwner'], ['L', 'follow'], ['h', 'follow'], + ['onentry', 'onReadEntry'], ], ) @@ -265,7 +266,7 @@ export interface TarOptions { /** * When parsing/listing archives, `entry` streams are by default resumed - * (set into "flowing" mode) immediately after the call to `onentry()`. + * (set into "flowing" mode) immediately after the call to `onReadEntry()`. * Set `noResume: true` to suppress this behavior. * * Note that when this is set, the stream will never complete until the @@ -279,10 +280,6 @@ export interface TarOptions { /** * When creating, updating, or replacing within archives, this method will * be called with each WriteEntry that is created. - * - * It's not called 'onentry' because that's already taken for the ReadEntry - * when reading archives, and it's just easier to only have one type of - * options object that this whole library can pass around without issue. */ onWriteEntry?: (entry: WriteEntry) => any @@ -293,7 +290,7 @@ export interface TarOptions { * Important when listing archives synchronously from a file, because there * is otherwise no way to interact with the data! */ - onentry?: (entry: ReadEntry) => any + onReadEntry?: (entry: ReadEntry) => any /** * Pack the targets of symbolic links rather than the link itself. @@ -477,6 +474,13 @@ export interface TarOptions { * Forcibly trigger a chown on every entry, no matter what. */ forceChown?: boolean + + /** + * ambiguous deprecated name for {@link onReadEntry} + * + * @deprecated + */ + onentry?: (entry: ReadEntry) => any } export type TarOptionsSync = TarOptions & { sync: true } diff --git a/src/parse.ts b/src/parse.ts index a4afeee0..b4db277d 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -147,8 +147,8 @@ export class Parser extends EE implements Warner { if (typeof opt.onwarn === 'function') { this.on('warn', opt.onwarn) } - if (typeof opt.onentry === 'function') { - this.on('entry', opt.onentry) + if (typeof opt.onReadEntry === 'function') { + this.on('entry', opt.onReadEntry) } } diff --git a/src/replace.ts b/src/replace.ts index 1d43fbb4..9fe2ed79 100644 --- a/src/replace.ts +++ b/src/replace.ts @@ -239,7 +239,7 @@ const addFilesSync = (p: Pack, files: string[]) => { file: path.resolve(p.cwd, file.slice(1)), sync: true, noResume: true, - onentry: entry => p.add(entry), + onReadEntry: entry => p.add(entry), }) } else { p.add(file) @@ -258,7 +258,7 @@ const addFilesAsync = async ( await list({ file: path.resolve(String(p.cwd), file.slice(1)), noResume: true, - onentry: entry => p.add(entry), + onReadEntry: entry => p.add(entry), }) } else { p.add(file) diff --git a/test/create.ts b/test/create.ts index 567f545f..0ff86486 100644 --- a/test/create.ts +++ b/test/create.ts @@ -241,7 +241,7 @@ t.test('create tarball out of another tarball', t => { list({ f: out, sync: true, - onentry: entry => { + onReadEntry: entry => { if (entry.path === 'hardlink-2') { t.equal(entry.type, 'Link') } else if (entry.path === 'symlink') { diff --git a/test/list.ts b/test/list.ts index cc11a491..a424c0eb 100644 --- a/test/list.ts +++ b/test/list.ts @@ -34,11 +34,11 @@ t.test('basic', t => { t.test('file maxReadSize=' + maxReadSize, t => { t.test('sync', t => { const actual: string[] = [] - const onentry = (entry: ReadEntry) => actual.push(entry.path) + const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) list({ file: file, sync: true, - onentry, + onReadEntry, maxReadSize, }) return check(actual, t) @@ -46,21 +46,21 @@ t.test('basic', t => { t.test('async promise', async t => { const actual: string[] = [] - const onentry = (entry: ReadEntry) => actual.push(entry.path) + const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) return await list({ file, - onentry, + onReadEntry, maxReadSize, }).then(() => check(actual, t)) }) t.test('async cb', t => { const actual: string[] = [] - const onentry = (entry: ReadEntry) => actual.push(entry.path) + const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) list( { file: file, - onentry: onentry, + onReadEntry: onReadEntry, maxReadSize: maxReadSize, }, (er?: Error) => { @@ -79,24 +79,24 @@ t.test('basic', t => { t.test('stream', t => { t.test('sync', t => { const actual: string[] = [] - const onentry = (entry: ReadEntry) => actual.push(entry.path) - const l = list({ sync: true, onentry }) + const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) + const l = list({ sync: true, onReadEntry }) l.end(fs.readFileSync(file)) return check(actual, t) }) t.test('async', t => { const actual: string[] = [] - const onentry = (entry: ReadEntry) => actual.push(entry.path) + const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) const l = list() - l.on('entry', onentry) + l.on('entry', onReadEntry) l.on('end', _ => check(actual, t).then(_ => t.end())) fs.createReadStream(file).pipe(l) }) t.end() }) - t.test('no onentry function', () => list({ file: file })) + t.test('no onReadEntry function', () => list({ file: file })) t.test('limit to specific files', t => { const fileList = [ @@ -121,7 +121,7 @@ t.test('basic', t => { return list( { file: file, - onentry: entry => actual.push(entry.path), + onReadEntry: entry => actual.push(entry.path), }, fileList, ).then(check) @@ -130,10 +130,10 @@ t.test('basic', t => { t.test('no filter function, stream', t => { const check = () => t.same(actual, expect) const actual: string[] = [] - const onentry = (entry: ReadEntry) => actual.push(entry.path) + const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) fs.createReadStream(file).pipe( list(fileList) - .on('entry', onentry) + .on('entry', onReadEntry) .on('end', _ => { check() t.end() @@ -148,7 +148,7 @@ t.test('basic', t => { { file: file, filter: path => path === expect[0], - onentry: entry => actual.push(entry.path), + onReadEntry: entry => actual.push(entry.path), }, fileList, ).then(check) @@ -232,7 +232,7 @@ t.test('noResume option', t => { let e!: ReadEntry list({ file: file, - onentry: entry => { + onReadEntry: entry => { e = entry process.nextTick(() => { t.notOk(entry.flowing) @@ -250,7 +250,7 @@ t.test('noResume option', t => { t.test('async', t => list({ file: file, - onentry: entry => { + onReadEntry: entry => { process.nextTick(() => { t.notOk(entry.flowing) entry.resume() diff --git a/test/parse.js b/test/parse.js index d68e2198..7fd21153 100644 --- a/test/parse.js +++ b/test/parse.js @@ -355,10 +355,10 @@ t.test('onwarn gets added to the warn event', t => { p.warn('TAR_TEST', 'this is fine') }) -t.test('onentry gets added to entry event', t => { +t.test('onReadEntry gets added to entry event', t => { t.plan(1) const p = new Parser({ - onentry: entry => t.equal(entry, 'yes hello this is dog'), + onReadEntry: entry => t.equal(entry, 'yes hello this is dog'), }) p.emit('entry', 'yes hello this is dog') }) @@ -536,7 +536,7 @@ t.test('drain event timings', t => { const autoPipe = true const p = new Parser({ ondone, - onentry: entry => { + onReadEntry: entry => { t.equal(entry.path, expect.shift()) currentEntry = entry if (autoPipe) { @@ -824,7 +824,7 @@ t.test('end while consuming', t => { const mp = new Minipass() const p = new Parser({ - onentry: entry => { + onReadEntry: entry => { actual.push(entry.path) entry.resume() }, diff --git a/test/replace.ts b/test/replace.ts index 5c5c2bef..1b475aff 100644 --- a/test/replace.ts +++ b/test/replace.ts @@ -457,7 +457,7 @@ t.test('create tarball out of another tarball', t => { list({ f: out, sync: true, - onentry: entry => { + onReadEntry: entry => { t.equal(entry.path, expect.shift()) }, }) diff --git a/test/unpack.js b/test/unpack.js index d003f5a0..ed575deb 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -2676,9 +2676,9 @@ t.test('futimes/fchown failures', t => { t.end() }) -t.test('onentry option is preserved', t => { +t.test('onReadEntry option is preserved', t => { let oecalls = 0 - const onentry = _entry => oecalls++ + const onReadEntry = _entry => oecalls++ const data = makeTar([ { path: 'd/i', @@ -2710,7 +2710,7 @@ t.test('onentry option is preserved', t => { t.test('sync', t => { const dir = t.testdir({}) - const unpack = new UnpackSync({ cwd: dir, onentry }) + const unpack = new UnpackSync({ cwd: dir, onReadEntry }) unpack.end(data) check(t) }) @@ -2718,7 +2718,7 @@ t.test('onentry option is preserved', t => { t.test('async', t => { const dir = t.testdir({}) mkdirp.sync(dir) - const unpack = new Unpack({ cwd: dir, onentry }) + const unpack = new Unpack({ cwd: dir, onReadEntry }) unpack.on('finish', () => check(t)) unpack.end(data) }) diff --git a/test/write-entry.js b/test/write-entry.js index 7bd8aae6..3cc6e7fa 100644 --- a/test/write-entry.js +++ b/test/write-entry.js @@ -1554,7 +1554,7 @@ t.test('prefix and hard links from tar entries', t => { const out = [] const parser = new Parser({ strict: true, - onentry: readEntry => { + onReadEntry: readEntry => { const p = new WriteEntryTar(readEntry, opt) p.on('data', d => out.push(d)) }, @@ -1799,7 +1799,7 @@ t.test('hard links from tar entries and no prefix', t => { } const out = [] const parser = new Parser({ - onentry: readEntry => { + onReadEntry: readEntry => { const p = new WriteEntryTar(readEntry, opt) p.on('data', d => out.push(d)) }, From 02b26879b880df80271cfb1ac98b7153becf9fb0 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Tue, 18 Jun 2024 19:36:44 -0700 Subject: [PATCH 87/96] 7.4.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 27284fd7..454bbb5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "tar", - "version": "7.3.0", + "version": "7.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tar", - "version": "7.3.0", + "version": "7.4.0", "license": "ISC", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", diff --git a/package.json b/package.json index 35f9198f..c9ade8e3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "7.3.0", + "version": "7.4.0", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From cc7ce8eea73484b0707eaae1e837b4b2289801b5 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Mon, 22 Jul 2024 08:59:12 -0700 Subject: [PATCH 88/96] github didn't write this, I did --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c9ade8e3..01022525 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "author": "GitHub Inc.", + "author": "Isaac Z. Schlueter", "name": "tar", "description": "tar for node", "version": "7.4.0", From e434c7b5b462473148061cb52615389f663e85d2 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Mon, 22 Jul 2024 09:02:01 -0700 Subject: [PATCH 89/96] some cleanup/formatting around onWriteEntry --- src/pack.ts | 12 ++++++++---- test/list.ts | 18 ++++++++++++------ test/pack.js | 5 ++++- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/pack.ts b/src/pack.ts index ce095884..306189fe 100644 --- a/src/pack.ts +++ b/src/pack.ts @@ -91,8 +91,8 @@ export class Pack filter: Exclude<TarOptions['filter'], undefined> jobs: number; - [WRITEENTRYCLASS]: typeof WriteEntry | typeof WriteEntrySync; - onWriteEntry?: (entry: WriteEntry) => void + [WRITEENTRYCLASS]: typeof WriteEntry | typeof WriteEntrySync + onWriteEntry?: (entry: WriteEntry) => void; [QUEUE]: Yallist<PackJob>; [JOBS]: number = 0; [PROCESSING]: boolean = false; @@ -387,9 +387,13 @@ export class Pack [ENTRY](job: PackJob) { this[JOBS] += 1 try { - const e = new this[WRITEENTRYCLASS](job.path, this[ENTRYOPT](job)) + const e = new this[WRITEENTRYCLASS]( + job.path, + this[ENTRYOPT](job), + ) this.onWriteEntry?.(e) - return e.on('end', () => this[JOBDONE](job)) + return e + .on('end', () => this[JOBDONE](job)) .on('error', er => this.emit('error', er)) } catch (er) { this.emit('error', er) diff --git a/test/list.ts b/test/list.ts index a424c0eb..9a28d0f7 100644 --- a/test/list.ts +++ b/test/list.ts @@ -34,7 +34,8 @@ t.test('basic', t => { t.test('file maxReadSize=' + maxReadSize, t => { t.test('sync', t => { const actual: string[] = [] - const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) + const onReadEntry = (entry: ReadEntry) => + actual.push(entry.path) list({ file: file, sync: true, @@ -46,7 +47,8 @@ t.test('basic', t => { t.test('async promise', async t => { const actual: string[] = [] - const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) + const onReadEntry = (entry: ReadEntry) => + actual.push(entry.path) return await list({ file, onReadEntry, @@ -56,7 +58,8 @@ t.test('basic', t => { t.test('async cb', t => { const actual: string[] = [] - const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) + const onReadEntry = (entry: ReadEntry) => + actual.push(entry.path) list( { file: file, @@ -79,7 +82,8 @@ t.test('basic', t => { t.test('stream', t => { t.test('sync', t => { const actual: string[] = [] - const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) + const onReadEntry = (entry: ReadEntry) => + actual.push(entry.path) const l = list({ sync: true, onReadEntry }) l.end(fs.readFileSync(file)) return check(actual, t) @@ -87,7 +91,8 @@ t.test('basic', t => { t.test('async', t => { const actual: string[] = [] - const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) + const onReadEntry = (entry: ReadEntry) => + actual.push(entry.path) const l = list() l.on('entry', onReadEntry) l.on('end', _ => check(actual, t).then(_ => t.end())) @@ -130,7 +135,8 @@ t.test('basic', t => { t.test('no filter function, stream', t => { const check = () => t.same(actual, expect) const actual: string[] = [] - const onReadEntry = (entry: ReadEntry) => actual.push(entry.path) + const onReadEntry = (entry: ReadEntry) => + actual.push(entry.path) fs.createReadStream(file).pipe( list(fileList) .on('entry', onReadEntry) diff --git a/test/pack.js b/test/pack.js index 02276b9c..8026dcc5 100644 --- a/test/pack.js +++ b/test/pack.js @@ -99,7 +99,10 @@ t.test('pack a file', t => { ) const hs = new Header(sync) t.match(hs, expect) - t.strictSame(seen.map(e => e.path), ['one-byte.txt']) + t.strictSame( + seen.map(e => e.path), + ['one-byte.txt'], + ) t.end() }) }) From f1d7a4d39bba883cbe31687a1497a728876479e7 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Mon, 22 Jul 2024 09:02:21 -0700 Subject: [PATCH 90/96] 7.4.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 454bbb5f..00ad7a3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "tar", - "version": "7.4.0", + "version": "7.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tar", - "version": "7.4.0", + "version": "7.4.1", "license": "ISC", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", diff --git a/package.json b/package.json index 01022525..d4145d63 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Isaac Z. Schlueter", "name": "tar", "description": "tar for node", - "version": "7.4.0", + "version": "7.4.1", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From 35d8d9964e56addc3becfccdd3cc5f6ef7d8b2e8 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 24 Jul 2024 16:57:09 -0700 Subject: [PATCH 91/96] kludge around TS pedantry fix: https://github.com/isaacs/node-tar/issues/421 --- src/pack.ts | 39 ++++++++++++++++++++++++++++++--------- src/warn-method.ts | 2 +- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/pack.ts b/src/pack.ts index 306189fe..04132292 100644 --- a/src/pack.ts +++ b/src/pack.ts @@ -31,7 +31,6 @@ export class PackJob { import { Minipass } from 'minipass' import * as zlib from 'minizlib' -//@ts-ignore import { Yallist } from 'yallist' import { ReadEntry } from './read-entry.js' import { @@ -68,7 +67,7 @@ import { normalizeWindowsPath } from './normalize-windows-path.js' import { TarOptions } from './options.js' export class Pack - extends Minipass<Minipass.ContiguousData, Buffer, WarnEvent> + extends Minipass<Buffer, ReadEntry | string, WarnEvent<Buffer>> implements Warner { opt: TarOptions @@ -99,6 +98,7 @@ export class Pack [ENDED]: boolean = false constructor(opt: TarOptions = {}) { + //@ts-ignore super() this.opt = opt this.file = opt.file || '' @@ -142,7 +142,7 @@ export class Pack /* c8 ignore next */ if (!this.zip) throw new Error('impossible') const zip = this.zip - zip.on('data', chunk => super.write(chunk)) + zip.on('data', chunk => super.write(chunk as unknown as string)) zip.on('end', () => super.end()) zip.on('drain', () => this[ONDRAIN]()) this.on('resume', () => zip.resume()) @@ -166,7 +166,7 @@ export class Pack } [WRITE](chunk: Buffer) { - return super.write(chunk) + return super.write(chunk as unknown as string) } add(path: string | ReadEntry) { @@ -174,17 +174,38 @@ export class Pack return this } - //@ts-ignore - end(path?: string | ReadEntry) { + end(cb?: () => void): this + end(path: string | ReadEntry, cb?: () => void): this + end( + path: string | ReadEntry, + encoding?: Minipass.Encoding, + cb?: () => void, + ): this + end( + path?: string | ReadEntry | (() => void), + encoding?: Minipass.Encoding | (() => void), + cb?: () => void, + ) { + /* c8 ignore start */ + if (typeof path === 'function') { + cb = path + path = undefined + } + if (typeof encoding === 'function') { + cb = encoding + encoding = undefined + } + /* c8 ignore stop */ if (path) { this.add(path) } this[ENDED] = true this[PROCESS]() + /* c8 ignore next */ + if (cb) cb() return this } - //@ts-ignore write(path: string | ReadEntry) { if (this[ENDED]) { throw new Error('write after end') @@ -293,7 +314,7 @@ export class Pack if (this.zip) { this.zip.end(EOF) } else { - super.write(EOF) + super.write(EOF as unknown as string) super.end() } } @@ -432,7 +453,7 @@ export class Pack }) } else { source.on('data', chunk => { - if (!super.write(chunk)) { + if (!super.write(chunk as unknown as string)) { source.pause() } }) diff --git a/src/warn-method.ts b/src/warn-method.ts index d308edb0..65ca99f0 100644 --- a/src/warn-method.ts +++ b/src/warn-method.ts @@ -16,7 +16,7 @@ export type Warner = { emit(event: 'error', error: TarError): void } -export type WarnEvent = Minipass.Events & { +export type WarnEvent<T = Buffer> = Minipass.Events<T> & { warn: [code: string, message: string, data: WarnData] } From 68a685b30eadddad71cec56bc136bd276fa7e7f6 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 24 Jul 2024 16:57:43 -0700 Subject: [PATCH 92/96] 7.4.2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 00ad7a3b..2b7fc552 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "tar", - "version": "7.4.1", + "version": "7.4.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tar", - "version": "7.4.1", + "version": "7.4.2", "license": "ISC", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", diff --git a/package.json b/package.json index d4145d63..3072e6b5 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Isaac Z. Schlueter", "name": "tar", "description": "tar for node", - "version": "7.4.1", + "version": "7.4.2", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From bf13718dc6b6636a234327122e8df05df52674d3 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Thu, 25 Jul 2024 21:32:21 -0700 Subject: [PATCH 93/96] move onWriteEntry to where it can do some good Fix: https://github.com/isaacs/node-tar/issues/271 --- src/pack.ts | 2 +- src/write-entry.ts | 7 ++++++- test/create.ts | 28 ++++++++++++++++++++++++---- test/write-entry.js | 22 ++++++++++++++++++++-- 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/pack.ts b/src/pack.ts index 04132292..cb721476 100644 --- a/src/pack.ts +++ b/src/pack.ts @@ -402,6 +402,7 @@ export class Pack noMtime: this.noMtime, mtime: this.mtime, prefix: this.prefix, + onWriteEntry: this.onWriteEntry, } } @@ -412,7 +413,6 @@ export class Pack job.path, this[ENTRYOPT](job), ) - this.onWriteEntry?.(e) return e .on('end', () => this[JOBDONE](job)) .on('error', er => this.emit('error', er)) diff --git a/src/write-entry.ts b/src/write-entry.ts index 4a7b2c65..fabead4d 100644 --- a/src/write-entry.ts +++ b/src/write-entry.ts @@ -88,7 +88,7 @@ export class WriteEntry type?: EntryTypeName | 'Unsupported' linkpath?: string stat?: Stats - /* c8 ignore start */ + onWriteEntry?: (entry: WriteEntry) => any #hadError: boolean = false @@ -109,6 +109,7 @@ export class WriteEntry this.mtime = opt.mtime this.prefix = opt.prefix ? normalizeWindowsPath(opt.prefix) : undefined + this.onWriteEntry = opt.onWriteEntry if (typeof opt.onwarn === 'function') { this.on('warn', opt.onwarn) @@ -222,6 +223,7 @@ export class WriteEntry this.noMtime = true } + this.onWriteEntry?.(this) this.header = new Header({ path: this[PREFIX](this.path), // only apply the prefix to hard links. @@ -618,6 +620,7 @@ export class WriteEntryTar ctime?: Date linkpath?: string size: number + onWriteEntry?: (entry: WriteEntry) => any warn(code: string, message: string | Error, data: WarnData = {}) { return warnMethod(this, code, message, data) @@ -634,6 +637,7 @@ export class WriteEntryTar this.strict = !!opt.strict this.noPax = !!opt.noPax this.noMtime = !!opt.noMtime + this.onWriteEntry = opt.onWriteEntry this.readEntry = readEntry const { type } = readEntry @@ -684,6 +688,7 @@ export class WriteEntryTar this.remain = readEntry.size this.blockRemain = readEntry.startBlockSize + this.onWriteEntry?.(this as unknown as WriteEntry) this.header = new Header({ path: this[PREFIX](this.path), linkpath: diff --git a/test/create.ts b/test/create.ts index 0ff86486..e0c4a0e8 100644 --- a/test/create.ts +++ b/test/create.ts @@ -1,12 +1,12 @@ -import t, { Test } from 'tap' -import { c, list, Pack, PackSync } from '../dist/esm/index.js' import fs from 'fs' +import { mkdirp } from 'mkdirp' import path from 'path' import { rimraf } from 'rimraf' -import { mkdirp } from 'mkdirp' +import t, { Test } from 'tap' +import { c, list, Pack, PackSync } from '../dist/esm/index.js' +import { spawn } from 'child_process' //@ts-ignore import mutateFS from 'mutate-fs' -import { spawn } from 'child_process' import { fileURLToPath } from 'url' const isWindows = process.platform === 'win32' @@ -288,3 +288,23 @@ t.test('must specify some files', t => { t.throws(() => c({}), 'no paths specified to add to archive') t.end() }) + +t.test('transform a filename', async t => { + const cwd = t.testdir({ + 'README.md': 'hello, world', + }) + const data = await c( + { + cwd, + onWriteEntry: entry => { + entry.path = 'bloorg.md' + }, + sync: true, + }, + ['README.md'], + ).concat() + t.equal( + data.subarray(0, 'bloorg.md'.length).toString(), + 'bloorg.md', + ) +}) diff --git a/test/write-entry.js b/test/write-entry.js index 3cc6e7fa..5e23b629 100644 --- a/test/write-entry.js +++ b/test/write-entry.js @@ -59,16 +59,23 @@ t.test('100 byte filename', t => { const runTest = t => { const f = '100-byte-filename-cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' + let entryInOWE = undefined const ws = new WriteEntry(f, { cwd: files, linkCache: linkCache, statCache: statCache, + onWriteEntry: self => { + entryInOWE = self + t.equal(self.path, f) + t.equal(self.header, undefined) + }, }) let out = [] ws.on('data', c => out.push(c)) ws.on('end', _ => { out = Buffer.concat(out) + t.equal(entryInOWE, ws) t.match(ws, { header: { cksumValid: true, @@ -1103,11 +1110,22 @@ t.test('write entry from read entry', t => { '', ]) const fileEntry = new ReadEntry(new Header(data)) - const wetFile = new WriteEntryTar(fileEntry, { portable: true }) + let entryInOWE = undefined + const wetFile = new WriteEntryTar(fileEntry, { + portable: true, + onWriteEntry: self => { + entryInOWE = self + t.equal(self.path, '$') + t.equal(self.header, undefined) + }, + }) const out = [] let wetFileEnded = false wetFile.on('data', c => out.push(c)) - wetFile.on('end', _ => (wetFileEnded = true)) + wetFile.on('end', () => { + wetFileEnded = true + t.equal(entryInOWE, wetFile) + }) fileEntry.end() t.equal(wetFileEnded, true) const result = Buffer.concat(out) From 206fcf91b01fae95ae859b8f3254bfd88744602a Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Thu, 25 Jul 2024 21:33:27 -0700 Subject: [PATCH 94/96] 7.4.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2b7fc552..fc866c54 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "tar", - "version": "7.4.2", + "version": "7.4.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tar", - "version": "7.4.2", + "version": "7.4.3", "license": "ISC", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", diff --git a/package.json b/package.json index 3072e6b5..0283103e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Isaac Z. Schlueter", "name": "tar", "description": "tar for node", - "version": "7.4.2", + "version": "7.4.3", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" From 02f883aa4d3336c023fb826d4ba11dde01c7f338 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 14 Aug 2024 09:03:40 -0700 Subject: [PATCH 95/96] docs on how to use onWriteEntry --- README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/README.md b/README.md index feb225cc..a08edba9 100644 --- a/README.md +++ b/README.md @@ -351,6 +351,54 @@ advanced use cases, such as re-using caches between runs. - `maxReadSize` The maximum buffer size for `fs.read()` operations. Defaults to 16 MB. +#### Using `onWriteMethod` to alter entries + +The `onWriteMethod` function, if provided, will get a reference +to each `entry` object on its way into the archive. + +If any fields on this entry are changed, then these changes will +be reflected in the entry that is written to the archive. + +The return value of the method is ignored. All that matters is +the final state of the entry object. This can also be used to +track the files added to an archive, for example. + +For example: + +```js +import * as tar from 'tar' +const filesAdded = [] +tar.c({ + sync: true, + file: 'lowercase-executable.tar', + onWriteEntry(entry) { + // initially, it's uppercase and 0o644 + console.log('adding', entry.path, entry.stat.mode.toString(8)) + // make all the paths lowercase + entry.path = entry.path.toLowerCase() + // make the entry executable + entry.stat.mode = 0o755 + // in the archive, it's lowercase and 0o755 + filesAdded.push([entry.path, entry.stat.mode.toString(8)]) + }, +}, ['./bin']) +console.log('added', filesAdded) +``` + +Then, if the `./bin` directory contained `SOME-BIN`, it would +show up in the archive as: + +``` +$ node create-lowercase-executable.js +adding ./bin/SOME-BIN 644 +added [[ './bin/some-bin', '755' ]] + +$ tar cvf lowercase-executable.tar +-rwxr-xr-x 0 isaacs 20 47731 Aug 14 08:56 ./bin/some-bin +``` + +with a lowercase name and a mode of `0o755`. + ### tar.x(options, fileList, callback) [alias: tar.extract] Extract a tarball archive. From d3cd4392d4a35a8f1e10287a07e57da6ae079e78 Mon Sep 17 00:00:00 2001 From: isaacs <i@izs.me> Date: Wed, 14 Aug 2024 09:04:53 -0700 Subject: [PATCH 96/96] remove extraneous 'for example' --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index a08edba9..7d69067e 100644 --- a/README.md +++ b/README.md @@ -363,8 +363,6 @@ The return value of the method is ignored. All that matters is the final state of the entry object. This can also be used to track the files added to an archive, for example. -For example: - ```js import * as tar from 'tar' const filesAdded = []