diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..64d3d6a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 14bd3e3..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "extends": "airbnb", - "rules": { - "space-in-parens": ["error", "always", { "exceptions": ["{}"] }], - "comma-style": ["error", "first", { "exceptions": { "ArrayExpression": true, "ObjectExpression": true } }], - "comma-dangle": ["error", "only-multiline"], - "space-before-function-paren": ["error", "never"], - "func-names": 0, - "no-param-reassign": 0, - "one-var-declaration-per-line": ["error", "initializations"], - "no-underscore-dangle": 0, - - // es6 - "object-shorthand": 0, - "one-var": ["error", "always"], - "no-var": 0, - "prefer-template": 0, - "prefer-arrow-callback": 0, - "prefer-rest-params": 0 - }, - "env": { - "mocha": true - }, - "globals": { - "expect": true - } -} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..f7278b4 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,48 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + branches: ['**'] + +jobs: + test: + runs-on: ubuntu-latest + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10.20.0 + run_install: false + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22.14.0 + cache: pnpm + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y poppler-utils antiword unrtf tesseract-ocr tesseract-ocr-chi-sim + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Lint + run: pnpm lint + + - name: Type check + run: pnpm typecheck + + - name: Build + run: pnpm build + + - name: Run tests + run: pnpm test diff --git a/.gitignore b/.gitignore index d8cdf8c..eeaeea7 100644 --- a/.gitignore +++ b/.gitignore @@ -14,8 +14,8 @@ results npm-debug.log node_modules -package-lock.json .DS_Store -ignore \ No newline at end of file +dist +tsconfig.tsbuildinfo diff --git a/.npmignore b/.npmignore index f502c52..76efb07 100644 --- a/.npmignore +++ b/.npmignore @@ -1,3 +1,2 @@ node_modules -test -.vscode \ No newline at end of file +.vscode diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..848218b --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +//npm.pkg.github.com/:_authToken=${NPM_TOKEN} +@speechifyinc:registry=https://npm.pkg.github.com diff --git a/README.md b/README.md index 9cc156a..2693026 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,29 @@ -textract -======== - -A fork of text extraction node module with additional fixes. - -[![NPM](https://nodei.co/npm/textract.png?compact=true)](https://nodei.co/npm/textract/) -[![NPM](https://nodei.co/npm-dl/textract.png)](https://nodei.co/npm/textract/) +# textract ## Currently Extracts... -* HTML, HTM -* ATOM, RSS -* Markdown -* EPUB -* XML, XSL -* PDF -* DOC, DOCX -* ODT, OTT (experimental, feedback needed!) -* RTF -* XLS, XLSX, XLSB, XLSM, XLTX -* CSV -* ODS, OTS -* PPTX, POTX -* ODP, OTP -* ODG, OTG -* PNG, JPG, GIF -* DXF -* `application/javascript` -* All `text/*` mime-types. - -In almost all cases above, what textract cares about is the mime type. So `.html` and `.htm`, both possessing the same mime type, will be extracted. Other extensions that share mime types with those above should also extract successfully. For example, `application/vnd.ms-excel` is the mime type for `.xls`, but also for 5 other file types. - -_Does textract not extract from files of the type you need?_ Add an issue or submit a pull request. It many cases textract is already capable, it is just not paying attention to the mime type you may be interested in. +- HTML, HTM +- ATOM, RSS +- Markdown +- EPUB +- XML, XSL +- PDF +- DOC, DOCX +- ODT, OTT (experimental) +- RTF +- XLS, XLSX, XLSB, XLSM, XLTX +- CSV +- ODS, OTS +- PPTX, POTX +- ODP, OTP +- ODG, OTG +- PNG, JPG, GIF +- `application/javascript` +- All `text/*` mime-types. + +In almost all cases above, what textract cares about is the mime type. So `.html` and `.htm`, both possessing the same mime type, will be extracted. Other extensions that share mime types with those above should also extract successfully. For example, `application/vnd.ms-excel` is the mime type for `.xls`, but also for 5 other file types. + +_Does textract not extract from files of the type you need?_ Add an issue or submit a pull request. It many cases textract is already capable, it is just not paying attention to the mime type you may be interested in. ## Install @@ -40,27 +33,26 @@ npm install textract ## Extraction Requirements -Note, if any of the requirements below are missing, textract will run and extract all files for types it is capable. Not having these items installed does not prevent you from using textract, it just prevents you from extracting those specific files. +Note, if any of the requirements below are missing, textract will run and extract all files for types it is capable. Not having these items installed does not prevent you from using textract, it just prevents you from extracting those specific files. -* `PDF` extraction requires `pdftotext` be installed, [link](http://www.foolabs.com/xpdf/download.html) -* `DOC` extraction requires `antiword` be installed, [link](http://www.winfield.demon.nl/), unless on OSX in which case textutil (installed by default) is used. -* `RTF` extraction requires `unrtf` be installed, [link](https://www.gnu.org/software/unrtf/), unless on OSX in which case textutil (installed by default) is used. -* `PNG`, `JPG` and `GIF` require `tesseract` to be available, [link](http://code.google.com/p/tesseract-ocr/). Images need to be pretty clear, high DPI and made almost entirely of just text for `tesseract` to be able to accurately extract the text. -* `DXF` extraction requires `drawingtotext` be available, [link](https://github.com/davidworkman9/drawingtotext) +- `PDF` extraction requires `pdftotext` be installed, [link](http://www.foolabs.com/xpdf/download.html) +- `DOC` extraction requires `antiword` be installed, [link](http://www.winfield.demon.nl/), unless on OSX in which case textutil (installed by default) is used. +- `RTF` extraction requires `unrtf` be installed, [link](https://www.gnu.org/software/unrtf/), unless on OSX in which case textutil (installed by default) is used. +- `PNG`, `JPG` and `GIF` require `tesseract` to be available, [link](http://code.google.com/p/tesseract-ocr/). Images need to be pretty clear, high DPI and made almost entirely of just text for `tesseract` to be able to accurately extract the text. ## Configuration -Configuration can be passed into textract. The following configuration options are available +Configuration can be passed into textract. The following configuration options are available -* `preserveLineBreaks`: When using the command line this is set to `true` to preserve stdout readability. When using the library via node this is set to `false`. Pass this in as `true` and textract will not strip any line breaks. -* `preserveOnlyMultipleLineBreaks`: Some extractors, like PDF, insert line breaks at the end of every line, even if the middle of a sentence. If this option (default `false`) is set to `true`, then any instances of a single line break are removed but multiple line breaks are preserved. Check your output with this option, though, this doesn't preserve paragraphs unless there are multiple breaks. -* `exec`: Some extractors (dxf) use node's `exec` functionality. This setting allows for providing [config to `exec` execution](http://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback). One reason you might want to provide this config is if you are dealing with very large files. You might want to increase the `exec` `maxBuffer` setting. -* `[ext].exec`: Each extractor can take specific exec config. Keep in mind many extractors are responsible for extracting multiple types, so, for instance, the `odt` extractor is what you would configure for `odt` and `odg`/`odt` etc. Check [the extractors](https://github.com/dbashford/textract/tree/master/lib/extractors) to see which you want to specifically configure. At the bottom of each is a list of `types` for which the extractor is responsible. -* `tesseract.lang`: A pass-through to tesseract allowing for setting of language for extraction. ex: `{ tesseract: { lang:"chi_sim" } }` -* `tesseract.cmd`: `tesseract.lang` allows a quick means to provide the most popular tesseract option, but if you need to configure more options, you can simply pass `cmd`. `cmd` is the string that matches the command-line options you want to pass to tesseract. For instance, to provide language and `psm`, you would pass `{ tesseract: { cmd:"-l chi_sim -psm 10" } }` -* `pdftotextOptions`: This is a proxy options object to the library textract uses for pdf extraction: [pdf-text-extract](https://github.com/nisaacson/pdf-text-extract). Options include `ownerPassword`, `userPassword` if you are extracting text from password protected PDFs. IMPORTANT: textract modifies the pdf-text-extract `layout` default so that, instead of `layout: layout`, it uses `layout:raw`. It is not suggested you modify this without understanding what trouble that might get you in. See [this GH issue](https://github.com/dbashford/textract/issues/75) for why textract overrides that library's default. -* `typeOverride`: Used with `fromUrl`, if set, rather than using the `content-type` from the URL request, will use the provided `typeOverride`. -* `includeAltText`: When extracting HTML, whether or not to include `alt` text with the extracted text. By default this is `false`. +- `preserveLineBreaks`: When using the command line this is set to `true` to preserve stdout readability. When using the library via node this is set to `false`. Pass this in as `true` and textract will not strip any line breaks. +- `preserveOnlyMultipleLineBreaks`: Some extractors, like PDF, insert line breaks at the end of every line, even if the middle of a sentence. If this option (default `false`) is set to `true`, then any instances of a single line break are removed but multiple line breaks are preserved. Check your output with this option, though, this doesn't preserve paragraphs unless there are multiple breaks. +- `exec`: Some extractors (doc) use node's `exec` functionality. This setting allows for providing [config to `exec` execution](http://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback). One reason you might want to provide this config is if you are dealing with very large files. You might want to increase the `exec` `maxBuffer` setting. +- `[ext].exec`: Each extractor can take specific exec config. Keep in mind many extractors are responsible for extracting multiple types, so, for instance, the `odt` extractor is what you would configure for `odt` and `odg`/`odt` etc. Check [the extractors](https://github.com/dbashford/textract/tree/master/lib/extractors) to see which you want to specifically configure. At the bottom of each is a list of `types` for which the extractor is responsible. +- `tesseract.lang`: A pass-through to tesseract allowing for setting of language for extraction. ex: `{ tesseract: { lang:"chi_sim" } }` +- `tesseract.cmd`: `tesseract.lang` allows a quick means to provide the most popular tesseract option, but if you need to configure more options, you can simply pass `cmd`. `cmd` is the string that matches the command-line options you want to pass to tesseract. For instance, to provide language and `psm`, you would pass `{ tesseract: { cmd:"-l chi_sim --psm 10" } }` +- `pdftotextOptions`: This is a proxy options object to the library textract uses for pdf extraction: [pdf-text-extract](https://github.com/nisaacson/pdf-text-extract). Options include `ownerPassword`, `userPassword` if you are extracting text from password protected PDFs. IMPORTANT: textract modifies the pdf-text-extract `layout` default so that, instead of `layout: layout`, it uses `layout:raw`. It is not suggested you modify this without understanding what trouble that might get you in. See [this GH issue](https://github.com/dbashford/textract/issues/75) for why textract overrides that library's default. +- `typeOverride`: Used with `fromUrl`, if set, rather than using the `content-type` from the URL request, will use the provided `typeOverride`. +- `includeAltText`: When extracting HTML, whether or not to include `alt` text with the extracted text. By default this is `false`. To use this configuration at the command line, prefix each open with a `--`. @@ -68,103 +60,20 @@ Ex: `textract image.png --tesseract.lang=deu` ## Usage -### Commmand Line - -If textract is installed gloablly, via `npm install -g textract`, then the following command will write the extracted text to the console for a file on the file system. - -``` -$ textract pathToFile -``` - -#### Flags - -Configuration flags can be passed into textract via the command line. - -``` -textract pathToFile --preserveLineBreaks false -``` - -Parameters like `exec.maxBuffer` can be passed as you'd expect. - -``` -textract pathToFile --exec.maxBuffer 500000 -``` - -And multiple flags can be used together. - -``` -textract pathToFile --preserveLineBreaks false --exec.maxBuffer 500000 -``` - -### Node - -#### Import - ```javascript -var textract = require('textract'); -``` - -#### APIs +import {extract} from 'textract'; -There are several ways to extract text. For all methods, the extracted text and an error object are passed to a callback. +extractFromBuffer(contentBuffer, mimeType, options?); -`error` will contain informative text about why the extraction failed. If textract does not currently extract files of the type provided, a `typeNotFound` flag will be tossed on the error object. +// or -##### File - -```javascript -textract.fromFileWithPath(filePath, function( error, text ) {}) -``` - -```javascript -textract.fromFileWithPath(filePath, config, function( error, text ) {}) +extractFromFile("/path/to/file.docx", mimeType?, options?); ``` -##### File + mime type -```javascript -textract.fromFileWithMimeAndPath(type, filePath, function( error, text ) {}) -``` - -```javascript -textract.fromFileWithMimeAndPath(type, filePath, config, function( error, text ) {}) -``` - -##### Buffer + mime type - -```javascript -textract.fromBufferWithMime(type, buffer, function( error, text ) {}) -``` - -```javascript -textract.fromBufferWithMime(type, buffer, config, function( error, text ) {}) -``` - -##### Buffer + file name/path - -```javascript -textract.fromBufferWithName(name, buffer, function( error, text ) {}) -``` - -```javascript -textract.fromBufferWithName(name, buffer, config, function( error, text ) {}) -``` - -##### URL - -When passing a URL, the URL can either be a string, or a [node.js URL object](https://nodejs.org/api/url.html). Using the URL object allows fine grained control over the URL being used. +## Testing Notes -```javascript -textract.fromUrl(url, function( error, text ) {}) -``` +### Running on a Mac -```javascript -textract.fromUrl(url, config, function( error, text ) {}) -``` - -## Testing Notes +- `brew install tesseract tesseract-lang` -### Running Tests on a Mac? -- `sudo port install tesseract-chi-sim` -- `sudo port install tesseract-eng` -- You will also want to disable textract's usage of textutil as the tests are based on output from antiword. - - Go into `/lib/extractors/{doc|doc-osx|rtf}` and modify the code under `if ( os.platform() === 'darwin' ) {`. Uncommented the commented lines in these sections. \ No newline at end of file +NOTE! The Word processing results are inconsistent between OSX and Linux (different utils are used), so the test themselves are relaxed to accomodate for both cases. diff --git a/bin/textract b/bin/textract deleted file mode 100755 index 8f0afd7..0000000 --- a/bin/textract +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -var path = require( 'path' ) - , fs = require( 'fs' ) - , meow = require( 'meow' ) - , help = 'Usage:\n' + - ' textract pathToFile\n\n' + - 'Flags:\n' + - ' preserveLineBreaks: true/false (default: true)\n' + - ' preserveOnlyMultipleLineBreaks: true/false (default: false)\n' + - ' exec.?: allows for passing in node exec parameters, http://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback\n' + - ' [ext].exec.?: allows for passing in node exec parameters for just a single extension\n' + - ' tesseract.lang: A pass-through to tesseract allowing for setting of language for extraction\n\n' + - ' tesseract.cmd: tesseract.lang allows a quick means to provide the most popular tesseract option, but if you need to configure more options, you can simply pass cmd. cmd is the string that matches the command-line options you want to pass to tesseract. For instance, to provide language and psm, you would pass { tesseract: { cmd:"-l chi_sim -psm 10" } }\n' + - ' pdftotextOptions: This is a proxy options object to the library textract uses for pdf extraction\n' + - ' typeOverride: Used with fromUrl, if set, rather than using the content-type from the URL request, will use the provided typeOverride.' + - 'Example:\n' + - ' textract test/files/huge.docx --exec.maxBuffer 500000 --preserveLineBreaks false\n' - -var cli = meow({ - help: help, - pkg: '../package.json' -}); - -if ( !cli.input || cli.input.length === 0 ) { - console.log( '\n' + help ); -} else { - var lib = path.join( path.dirname( fs.realpathSync( __filename ) ), '..', 'lib', 'cli.js' ); - var textract = require( lib ); - textract( cli.input[0], cli.flags ); -} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..e107839 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,22 @@ +import typescriptPreset from '@speechifyinc/platform-code-conformity-kit/eslint/presets/typescript-node.js'; +import prettierConfig from '@speechifyinc/platform-code-conformity-kit/eslint/configs/prettier.js'; +// import vitest from "@speechifyinc/platform-code-conformity-kit/eslint/configs/vitest.js"; + +export default [ + ...typescriptPreset, + { + languageOptions: { + parserOptions: { + project: ['./tsconfig.json'], + }, + }, + }, + ...prettierConfig, + { + files: ['**/*.test.ts'], + rules: { + 'n/no-unpublished-import': 'off', + }, + }, + { ignores: ['dist/**', 'test/files/**'] }, +]; diff --git a/lib/cli.js b/lib/cli.js deleted file mode 100644 index 2aa81ac..0000000 --- a/lib/cli.js +++ /dev/null @@ -1,22 +0,0 @@ -var path = require( 'path' ) - , textract = require( './index' ); - -module.exports = function( filePath, flags ) { - filePath = path.resolve( process.cwd(), filePath ); - - if ( flags.preserveLineBreaks === 'false' ) { - flags.preserveLineBreaks = false; - } else { - flags.preserveLineBreaks = true; - } - - textract.fromFileWithPath( filePath, flags, function( error, text ) { - if ( error ) { - // eslint-disable-next-line no-console - console.error( error ); - } else { - // eslint-disable-next-line no-console - console.log( text ); - } - }); -}; diff --git a/lib/extract.js b/lib/extract.js deleted file mode 100644 index c555d77..0000000 --- a/lib/extract.js +++ /dev/null @@ -1,164 +0,0 @@ -var fs = require( 'fs' ) - , path = require( 'path' ) - , XmlEntities = require( 'html-entities' ).XmlEntities - , util = require( './util' ) - , extractorPath = path.join( __dirname, 'extractors' ) - , entities = new XmlEntities() - , typeExtractors = {} - , regexExtractors = [] - , failedExtractorTypes = {} - , totalExtractors = 0 - , satisfiedExtractors = 0 - , hasInitialized = false - , STRIP_ONLY_SINGLE_LINEBREAKS = /(^|[^\n])\n(?!\n)/g - , WHITELIST_PRESERVE_LINEBREAKS = /[^A-Za-z\x80-\xFF\x24\u20AC\xA3\xA5 0-9 \u2015\u2116\u2018\u2019\u201C|\u201D\u2026 \uFF0C \u2013 \u2014 \u00C0-\u1FFF \u2C00-\uD7FF \uFB50–\uFDFF \uFE70–\uFEFF \uFF01-\uFFE6 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~'-\w\n\r]*/g // eslint-disable-line max-len - , WHITELIST_STRIP_LINEBREAKS = /[^A-Za-z\x80-\xFF\x24\u20AC\xA3\xA5 0-9 \u2015\u2116\u2018\u2019\u201C|\u201D\u2026 \uFF0C \u2013 \u2014 \u00C0-\u1FFF \u2C00-\uD7FF \uFB50–\uFDFF \uFE70–\uFEFF \uFF01-\uFFE6 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~'-\w]*/g // eslint-disable-line max-len - ; - -function registerExtractor( extractor ) { - if ( extractor.types ) { - extractor.types.forEach( function( type ) { - if ( typeof type === 'string' ) { - type = type.toLowerCase(); - typeExtractors[type] = extractor.extract; - } else { - if ( type instanceof RegExp ) { - regexExtractors.push({ reg: type, extractor: extractor.extract }); - } - } - }); - } -} - -function registerFailedExtractor( extractor, failedMessage ) { - if ( extractor.types ) { - extractor.types.forEach( function( type ) { - failedExtractorTypes[type.toLowerCase()] = failedMessage; - }); - } -} - -function testExtractor( extractor, options ) { - extractor.test( options, function( passedTest, failedMessage ) { - satisfiedExtractors++; - if ( passedTest ) { - registerExtractor( extractor ); - } else { - registerFailedExtractor( extractor, failedMessage ); - } - }); -} - -// global, all file type, content cleansing -function cleanseText( options, cb ) { - return function( error, text ) { - if ( !error ) { - // clean up text - text = util.replaceBadCharacters( text ); - - if ( options.preserveLineBreaks || options.preserveOnlyMultipleLineBreaks ) { - if ( options.preserveOnlyMultipleLineBreaks ) { - text = text.replace( STRIP_ONLY_SINGLE_LINEBREAKS, '$1 ' ).trim(); - } - text = text.replace( WHITELIST_PRESERVE_LINEBREAKS, ' ' ); - } else { - text = text.replace( WHITELIST_STRIP_LINEBREAKS, ' ' ); - } - - // multiple spaces, tabs, vertical tabs, non-breaking space] - text = text.replace( / (?! )/g, '' ) - .replace( /[ \t\v\u00A0]{2,}/g, ' ' ); - - text = entities.decode( text ); - } - cb( error, text ); - }; -} - -function initializeExtractors( options ) { - var extractors; - - hasInitialized = true; - - // discover available extractors - extractors = fs.readdirSync( extractorPath ).map( function( item ) { - var fullExtractorPath = path.join( extractorPath, item ); - // get the extractor - // eslint-disable-next-line global-require - return require( fullExtractorPath ); - }); - - // perform any binary tests to ensure extractor is possible - // given execution environment - extractors.forEach( function( extractor ) { - if ( extractor.test ) { - testExtractor( extractor, options ); - } else { - satisfiedExtractors++; - registerExtractor( extractor ); - } - }); - - // need to keep track of how many extractors we have in total - totalExtractors = extractors.length; -} - -function findExtractor( type ) { - var i - , iLen = regexExtractors.length - , extractor - , regexExtractor - ; - - type = type.toLowerCase(); - if ( typeExtractors[type] ) { - extractor = typeExtractors[type]; - } else { - for ( i = 0; i < iLen; i++ ) { - regexExtractor = regexExtractors[i]; - if ( type.match( regexExtractor.reg ) ) { - extractor = regexExtractor.extractor; - } - } - } - return extractor; -} - -function extract( type, filePath, options, cb ) { - var error, msg, theExtractor; - - if ( !hasInitialized ) { - initializeExtractors( options ); - } - - // registration of extractors complete? - if ( totalExtractors === satisfiedExtractors ) { - theExtractor = findExtractor( type ); - - if ( theExtractor ) { - cb = cleanseText( options, cb ); - theExtractor( filePath, options, cb ); - } else { - // cannot extract this file type - msg = 'Error for type: [[ ' + type + ' ]], file: [[ ' + filePath + ' ]]'; - - // update error message if type is supported but just not configured/installed properly - if ( failedExtractorTypes[type] ) { - msg += ', extractor for type exists, but failed to initialize.' + - ' Message: ' + failedExtractorTypes[type]; - } - - error = new Error( msg ); - error.typeNotFound = true; - cb( error, null ); - } - } else { - // async registration has not wrapped up - // try again later - setTimeout( function() { - extract( type, filePath, options, cb ); - }, 100 ); - } -} - -module.exports = extract; diff --git a/lib/extract.ts b/lib/extract.ts new file mode 100644 index 0000000..d4d739e --- /dev/null +++ b/lib/extract.ts @@ -0,0 +1,190 @@ +import { decode } from 'html-entities'; +import extractors, { type Extractor } from './extractors/index.js'; +import type { Input, Options } from './types.js'; +import { + getBufferInput, + getFilePathInput, + replaceBadCharacters, +} from './util.js'; + +const STRIP_ONLY_SINGLE_LINEBREAKS = /(^|[^\n])\n(?!\n)/g; +const WHITELIST_PRESERVE_LINEBREAKS = + /[^A-Za-z\x80-\xFF\x24\u20AC\xA3\xA5 0-9 \u2015\u2116\u2018\u2019\u201C|\u201D\u2026 \uFF0C \u2013 \u2014 \u00C0-\u1FFF \u2C00-\uD7FF \uFB50–\uFDFF \uFE70–\uFEFF \uFF01-\uFFE6 .,?""!@#$%^&*()-_=+;:<>/\\|}{[\]`~'-\w\n\r]*/g; +const WHITELIST_STRIP_LINEBREAKS = + /[^A-Za-z\x80-\xFF\x24\u20AC\xA3\xA5 0-9 \u2015\u2116\u2018\u2019\u201C|\u201D\u2026 \uFF0C \u2013 \u2014 \u00C0-\u1FFF \u2C00-\uD7FF \uFB50–\uFDFF \uFE70–\uFEFF \uFF01-\uFFE6 .,?""!@#$%^&*()-_=+;:<>/\\|}{[\]`~'-\w]*/g; + +const registeredExtractors = new Map(); +const failedExtractors = new Map(); +const initializedExtractors = new Set(); + +/** + * Check if a type or regex matches a mime type + * @param type type + * @param mimeType mime type + * @returns true if the type matches the mime type, false otherwise + */ +function matches(type: string | RegExp, mimeType: string): boolean { + if (typeof type === 'string') { + return mimeType.toLowerCase() === type.toLowerCase(); + } + return mimeType.match(type) !== null; +} + +/** + * Find an extractor by mime type + * @param mimeType mime type + * @param options options + * @returns extractor + */ +async function findExtractor( + mimeType: string, + options: Options, +): Promise { + console.debug(`findExtractor for mime type: [[ ${mimeType} ]]`); + + if (registeredExtractors.has(mimeType)) { + console.debug( + `findExtractor for mime type: [[ ${mimeType} ]] found in registeredExtractors`, + ); + return registeredExtractors.get(mimeType); + } + + const matchingExtractor = extractors.find((extractor) => + extractor.types.some((type) => matches(type, mimeType)), + ); + if (!matchingExtractor) { + console.debug( + `findExtractor for mime type: [[ ${mimeType} ]] not found in extractors`, + ); + return undefined; + } + if (failedExtractors.has(matchingExtractor)) { + console.debug( + `findExtractor for mime type: [[ ${mimeType} ]] failed to initialize earlier`, + ); + throw new Error( + `Extractor for type: [[ ${mimeType} ]] failed to initialize. Message: ${failedExtractors.get(matchingExtractor)}`, + ); + } + + let initialized: boolean; + if (initializedExtractors.has(matchingExtractor)) { + console.debug( + `findExtractor for mime type: [[ ${mimeType} ]] already initialized for a different mime type`, + ); + registeredExtractors.set(mimeType, matchingExtractor); + return matchingExtractor; + } + + try { + console.debug( + `findExtractor for mime type: [[ ${mimeType} ]] initializing`, + ); + if (matchingExtractor.test) { + initialized = await matchingExtractor.test(options); + } else { + initialized = true; + } + } catch (error) { + console.debug( + `findExtractor for mime type: [[ ${mimeType} ]] failed to initialize`, + ); + failedExtractors.set( + matchingExtractor, + error instanceof Error ? error.message : 'Unknown error', + ); + throw new Error( + `Extractor for type: [[ ${mimeType} ]] failed to initialize. Message: ${error instanceof Error ? error.message : 'Unknown error'}`, + ); + } + + if (!initialized) { + console.debug( + `findExtractor for mime type: [[ ${mimeType} ]] failed to initialize`, + ); + failedExtractors.set(matchingExtractor, 'Extractor failed to initialize'); + throw new Error( + `Extractor for type: [[ ${mimeType} ]] failed to initialize. Message: ${failedExtractors.get(matchingExtractor)}`, + ); + } + + console.debug(`findExtractor for mime type: [[ ${mimeType} ]] initialized`); + initializedExtractors.add(matchingExtractor); + registeredExtractors.set(mimeType, matchingExtractor); + return matchingExtractor; +} + +// global, all file type, content cleansing +/** + * Clean up text + * @param inputText input text + * @param options options + * @returns cleaned text + */ +function cleanText(inputText: string, options: Options): string { + // clean up text + let text = replaceBadCharacters(inputText); + + if (options.preserveLineBreaks || options.preserveOnlyMultipleLineBreaks) { + if (options.preserveOnlyMultipleLineBreaks) { + text = text.replace(STRIP_ONLY_SINGLE_LINEBREAKS, '$1 ').trim(); + } + text = text.replace(WHITELIST_PRESERVE_LINEBREAKS, ' '); + } else { + text = text.replace(WHITELIST_STRIP_LINEBREAKS, ' '); + } + + // multiple spaces, tabs, vertical tabs, non-breaking space] + text = text.replace(/ (?! )/g, '').replace(/[ \t\v\u00A0]{2,}/g, ' '); + + return decode(text); +} + +/** + * Extract text from a file + * @param mimeType mime type + * @param input input + * @param options options + * @returns extracted text + */ +export default async function extract( + mimeType: string, + input: Input, + options: Options, +): Promise { + let extractor: Extractor | undefined; + + try { + extractor = await findExtractor(mimeType, options); + } catch (error) { + if ( + error instanceof Error && + (error as Error & { typeNotFound: boolean }).typeNotFound + ) { + throw error; + } + (error as Error & { typeNotFound: boolean }).typeNotFound = true; + throw error; + } + + if (!extractor) { + // cannot extract this file type + const msg = `Error for type: [[ ${mimeType} ]], extractor not found`; + const error = new Error(msg); + (error as Error & { typeNotFound: boolean }).typeNotFound = true; + throw error; + } + + let text: string; + + if (extractor.inputKind === 'filePath') { + const { filePath, cleanup } = await getFilePathInput(input); + text = await extractor.extract(filePath, options); + await cleanup(); + } else { + const buffer = await getBufferInput(input); + text = await extractor.extract(buffer, options); + } + + return cleanText(text, options); +} diff --git a/lib/extractors/doc-osx.js b/lib/extractors/doc-osx.js deleted file mode 100644 index 09df8a4..0000000 --- a/lib/extractors/doc-osx.js +++ /dev/null @@ -1,67 +0,0 @@ -var spawn = require( 'child_process' ).spawn - , exec = require( 'child_process' ).exec - , os = require( 'os' ) - , path = require( 'path' ) - , types - ; - -// textutil -convert txt -stdout foo.doc -function extractText( filePath, options, cb ) { - var result = '' - , error = null - , textutil = spawn( 'textutil', ['-convert', 'txt', '-stdout', filePath] ) - ; - - textutil.stdout.on( 'data', function( buffer ) { - result += buffer.toString(); - }); - - textutil.stderr.on( 'error', function( buffer ) { - if ( !error ) { - error = ''; - } - error += buffer.toString(); - }); - - textutil.on( 'close', function( /* code */ ) { - if ( error ) { - error = new Error( 'textutil read of file named [[ ' + - path.basename( filePath ) + ' ]] failed: ' + error ); - cb( error, null ); - return; - } - cb( null, result.trim() ); - }); -} - -function testForBinary( options, cb ) { - // just osx extractor, so don't bother checking on osx - if ( os.platform() !== 'darwin' ) { - cb( true ); - return; - } - - exec( 'textutil ' + __filename, - function( error /* , stdout, stderr */ ) { - var msg; - if ( error !== null ) { - msg = 'INFO: \'textutil\' does not appear to be installed, ' + - 'so textract will be unable to extract DOCs.'; - } - cb( error === null, msg ); - } - ); -} - -if ( os.platform() === 'darwin' ) { - types = ['application/msword', 'application/rtf', 'text/rtf']; - // types = []; -} else { - types = []; -} - -module.exports = { - types: types, - extract: extractText, - test: testForBinary -}; diff --git a/lib/extractors/doc-osx.ts b/lib/extractors/doc-osx.ts new file mode 100644 index 0000000..3bdb9fb --- /dev/null +++ b/lib/extractors/doc-osx.ts @@ -0,0 +1,87 @@ +import { spawn, exec } from 'node:child_process'; +import os from 'node:os'; +import path from 'node:path'; +import type { Options } from '../types.ts'; + +// textutil -convert txt -stdout foo.doc +/** + * Extract text from a DOC file using textutil + * @param filePath path to file + * @param _options options (not used) + * @returns text from file + */ +async function extractText( + filePath: string, + _options: Options, +): Promise { + let result = ''; + let error = ''; + + return new Promise((resolve, reject) => { + const textutil = spawn('textutil', [ + '-convert', + 'txt', + '-stdout', + filePath, + ]); + + textutil.stdout.on('data', (buffer: Buffer) => { + result += buffer.toString(); + }); + + textutil.stderr.on('error', (buffer) => { + error += buffer.toString(); + }); + + textutil.on('close', (/* code */) => { + if (error) { + reject( + new Error( + `textutil read of file named [[ ${path.basename(filePath)} ]] failed: ${ + error + }`, + ), + ); + return; + } + resolve(result.trim()); + }); + }); +} + +/** + * Test if textutil is installed + * @param _options options (not used) + * @returns true if textutil is installed + */ +async function testForBinary(_options: Options): Promise { + // just osx extractor, so don't bother checking on osx + if (os.platform() !== 'darwin') { + return true; + } + + return new Promise((resolve, reject) => { + exec(`textutil ${__filename}`, (error /* , stdout, stderr */) => { + if (error !== null) { + reject( + new Error( + `INFO: 'textutil' does not appear to be installed, so textract will be unable to extract DOCs.`, + ), + ); + return; + } + + resolve(true); + }); + }); +} + +export default { + inputKind: 'filePath' as const, + types: + os.platform() === 'darwin' + ? ['application/msword', 'application/rtf', 'text/rtf'] + : [], + extract: extractText, + test: testForBinary, +}; diff --git a/lib/extractors/doc.js b/lib/extractors/doc.js deleted file mode 100644 index 6c3375c..0000000 --- a/lib/extractors/doc.js +++ /dev/null @@ -1,71 +0,0 @@ -var exec = require( 'child_process' ).exec - , os = require( 'os' ) - , path = require( 'path' ) - , util = require( '../util' ) - , types - ; - -function extractText( filePath, options, cb ) { - var execOptions = util.createExecOptions( 'doc', options ); - - exec( 'antiword -m UTF-8.txt "' + filePath + '"', - execOptions, - function( error, stdout /* , stderr */ ) { - var err; - if ( error ) { - if ( error.toString().indexOf( 'is not a Word Document' ) > 0 ) { - err = new Error( 'file named [[ ' + path.basename( filePath ) + - ' ]] does not appear to really be a .doc file' ); - } else { - err = new Error( 'antiword read of file named [[ ' + - path.basename( filePath ) + ' ]] failed: ' + error ); - } - cb( err, null ); - } else { - cb( null, stdout.trim().replace( /\[pic\]/g, '' ) ); - } - } - ); -} - -function testForBinary( options, cb ) { - var execOptions; - - // just non-osx extractor - if ( os.platform() === 'darwin' ) { - cb( true ); - return; - } - - execOptions = util.createExecOptions( 'doc', options ); - - exec( 'antiword -m UTF-8.txt ' + __filename, - execOptions, - function( error /* , stdout, stderr */ ) { - var msg; - if ( error !== null && error.message && - error.message.indexOf( 'not found' ) !== -1 ) { - msg = 'INFO: \'antiword\' does not appear to be installed, ' + - 'so textract will be unable to extract DOCs.'; - cb( false, msg ); - } else { - cb( true ); - } - } - ); -} - -if ( os.platform() === 'darwin' ) { - // for local testing - // let textutil handle .doc on osx - types = []; - // types = ['application/msword']; -} else { - types = ['application/msword']; -} - -module.exports = { - types: types, - extract: extractText, - test: testForBinary -}; diff --git a/lib/extractors/doc.ts b/lib/extractors/doc.ts new file mode 100644 index 0000000..9e9889b --- /dev/null +++ b/lib/extractors/doc.ts @@ -0,0 +1,90 @@ +import { exec } from 'node:child_process'; +import os from 'node:os'; +import path from 'node:path'; +import type { Options } from '../types.js'; +import { createExecOptions } from '../util.js'; + +/** + * Extract text from a DOC file using antiword + * @param filePath path to file + * @param options options + * @returns text from file + */ +async function extractText( + filePath: string, + options: Options, +): Promise { + const execOptions = createExecOptions('doc', options); + + return new Promise((resolve, reject) => { + exec( + `antiword -m UTF-8.txt "${filePath}"`, + execOptions, + (error, stdout /* , stderr */) => { + if (!error) { + const stdoutString = stdout.toString(); + resolve(stdoutString.trim().replaceAll('[pic]', '')); + return; + } + + if (error.toString().indexOf('is not a Word Document') > 0) { + reject( + new Error( + `file named [[ ${path.basename( + filePath, + )} ]] does not appear to really be a .doc file`, + ), + ); + return; + } + + reject( + new Error( + `antiword read of file named [[ ${path.basename( + filePath, + )} ]] failed: ${error.message}`, + ), + ); + }, + ); + }); +} + +/** + * Test if antiword is installed + * @param options options + * @returns true if antiword is installed + */ +async function testForBinary(options: Options): Promise { + // just non-osx extractor + if (os.platform() === 'darwin') { + return true; + } + + const execOptions = createExecOptions('doc', options); + + return new Promise((resolve, reject) => { + exec(`antiword -h`, execOptions, (error /* , stdout, stderr */) => { + let msg = ''; + if (error?.message?.includes('not found')) { + msg = + "INFO: 'antiword' does not appear to be installed, so textract will be unable to extract DOCs."; + } else if (error) { + msg = error.message; + } + if (msg) { + reject(new Error(msg)); + return; + } + resolve(true); + }); + }); +} + +export default { + inputKind: 'filePath' as const, + // let textutil handle .doc on osx + types: os.platform() === 'darwin' ? [] : ['application/msword'], + extract: extractText, + test: testForBinary, +}; diff --git a/lib/extractors/docx.js b/lib/extractors/docx.js deleted file mode 100644 index 049886e..0000000 --- a/lib/extractors/docx.js +++ /dev/null @@ -1,92 +0,0 @@ -var xpath = require( 'xpath' ) - , Dom = require( 'xmldom' ).DOMParser - , yauzl = require( 'yauzl' ) - , util = require( '../util' ) - , includeRegex = /.xml$/ - , excludeRegex = /^(word\/media\/|word\/_rels\/)/ - ; - -function _calculateExtractedText( inText, preserveLineBreaks ) { - var doc = new Dom().parseFromString( inText ) - , ps = xpath.select( "//*[local-name()='p']", doc ) - , text = '' - ; - - ps.forEach( function( paragraph ) { - var ts - , localText = '' - ; - - paragraph = new Dom().parseFromString( paragraph.toString() ); - ts = xpath.select( - "//*[local-name()='t' or local-name()='tab' or local-name()='br']", paragraph ); - ts.forEach( function( t ) { - if ( t.localName === 't' && t.childNodes.length > 0 ) { - localText += t.childNodes[0].data; - } else { - if ( t.localName === 'tab' ) { - localText += ' '; - } else if ( t.localName === 'br' ) { - if ( preserveLineBreaks !== true ) { - localText += ' '; - } else { - localText += '\n'; - } - } - } - }); - text += localText + '\n'; - }); - - return text; -} - -function extractText( filePath, options, cb ) { - var result = ''; - - yauzl.open( filePath, function( err, zipfile ) { - var processEnd - , processedEntries = 0 - ; - - if ( err ) { - util.yauzlError( err, cb ); - return; - } - - processEnd = function() { - var text; - if ( zipfile.entryCount === ++processedEntries ) { - if ( result.length ) { - text = _calculateExtractedText( result, options.preserveLineBreaks ); - cb( null, text ); - } else { - cb( new Error( - 'Extraction could not find content in file, are you' + - ' sure it is the mime type it says it is?' ), - null ); - } - } - }; - - zipfile.on( 'entry', function( entry ) { - if ( includeRegex.test( entry.fileName ) && !excludeRegex.test( entry.fileName ) ) { - util.getTextFromZipFile( zipfile, entry, function( err2, text ) { - result += text + '\n'; - processEnd(); - }); - } else { - processEnd(); - } - }); - - zipfile.on( 'error', function( err3 ) { - cb( err3 ); - }); - }); -} - -module.exports = { - types: ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'], - extract: extractText -}; diff --git a/lib/extractors/docx.ts b/lib/extractors/docx.ts new file mode 100644 index 0000000..12a08f2 --- /dev/null +++ b/lib/extractors/docx.ts @@ -0,0 +1,38 @@ +import mammoth from 'mammoth'; +import type { Options } from '../types.js'; +import htmlExtract from './html.js'; + +/** + * Extract text from a DOCX file + * @param filePath path to file + * @param options options + * @returns text from file + */ +async function extractText( + filePath: string, + options: Options, +): Promise { + try { + const { value } = await mammoth.convertToHtml({ path: filePath }); + return htmlExtract.extractFromString(value, options).trim(); + } catch (error) { + if ( + error instanceof Error && + error.message.includes("Can't find end of central directory") + ) { + throw new Error( + `File not correctly recognized as zip file, ${error.message}`, + ); + } + + throw error; + } +} + +export default { + inputKind: 'filePath' as const, + types: [ + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + ], + extract: extractText, +}; diff --git a/lib/extractors/dxf.js b/lib/extractors/dxf.js deleted file mode 100644 index 683ed7e..0000000 --- a/lib/extractors/dxf.js +++ /dev/null @@ -1,57 +0,0 @@ -var exec = require( 'child_process' ).exec - , path = require( 'path' ) - , util = require( '../util' ) - ; - -function extractText( filePath, options, cb ) { - var execOptions = util.createExecOptions( 'dxf', options ) - , escapedPath = filePath.replace( /\s/g, '\\ ' ) - ; - - exec( 'drawingtotext ' + escapedPath, - execOptions, - function( error, stdout, stderr ) { - if ( stderr !== '' ) { - error = new Error( 'error extracting DXF text ' + - path.basename( filePath ) + ': ' + stderr ); - cb( error, null ); - return; - } - - cb( null, stdout ); - } - ); -} - -function testForBinary( options, cb ) { - exec( 'drawingtotext notalegalfile', - function( error, stdout, stderr ) { - var msg - , errorRegex = /I couldn't make sense of your input/ - ; - - if ( !( stderr && errorRegex.test( stderr ) ) ) { - msg = 'INFO: \'drawingtotext\' does not appear to be installed, ' + - 'so textract will be unable to extract DXFs.'; - cb( false, msg ); - } else { - cb( true ); - } - } - ); -} - -module.exports = { - types: [ - 'application/dxf', - 'application/x-autocad', - 'application/x-dxf', - 'drawing/x-dxf', - 'image/vnd.dxf', - 'image/x-autocad', - 'image/x-dxf', - 'zz-application/zz-winassoc-dxf' - ], - extract: extractText, - test: testForBinary -}; diff --git a/lib/extractors/epub.js b/lib/extractors/epub.js deleted file mode 100644 index 0e6c820..0000000 --- a/lib/extractors/epub.js +++ /dev/null @@ -1,48 +0,0 @@ -var EPub = require( 'epub2/node' ) - , htmlExtract = require( './html' ) - ; - -function extractText( filePath, options, cb ) { - var epub = new EPub( filePath ) - , allText = '' - , hasError = false - , chapterCount = 0 - ; - - epub.on( 'end', function() { - // Iterate over each chapter... - epub.flow.forEach( function( chapter ) { - // if already error, don't do anything - if ( !hasError ) { - // Get the chapter text - epub.getChapterRaw( chapter.id, function( rawChaperError, text ) { - if ( rawChaperError ) { - hasError = true; - cb( rawChaperError, null ); - } else { - // Extract the raw text from the chapter text (it's html) - htmlExtract.extractFromText( text, options, function( htmlExtractError, outText ) { - if ( htmlExtractError ) { - hasError = true; - cb( htmlExtractError, null ); - } else { - allText += outText; - chapterCount++; - if ( chapterCount === epub.flow.length ) { - cb( null, allText ); - } - } - }); - } - }); - } - }); - }); - - epub.parse(); -} - -module.exports = { - types: ['application/epub+zip'], - extract: extractText -}; diff --git a/lib/extractors/epub.ts b/lib/extractors/epub.ts new file mode 100644 index 0000000..bf0ae21 --- /dev/null +++ b/lib/extractors/epub.ts @@ -0,0 +1,37 @@ +import { EPub } from 'epub2'; +import type { Options } from '../types.js'; +import htmlExtract from './html.js'; + +EPub.libPromise = Promise; + +/** + * Extract text from an EPUB file + * @param filePath path to file + * @param options options + * @returns text from file + */ +async function extractText( + filePath: string, + options: Options, +): Promise { + const epub = (await EPub.createAsync(filePath)) as EPub; + + let allText = ''; + + for (const chapter of epub.flow) { + if (!chapter.id) { + continue; + } + const html = String(await epub.getChapterRawAsync(chapter.id)); + const text = htmlExtract.extractFromString(html, options); + allText += text; + } + + return allText; +} + +export default { + inputKind: 'filePath' as const, + types: ['application/epub+zip'], + extract: extractText, +}; diff --git a/lib/extractors/html.js b/lib/extractors/html.js deleted file mode 100644 index 3606af9..0000000 --- a/lib/extractors/html.js +++ /dev/null @@ -1,99 +0,0 @@ -/* eslint-disable max-len */ - -var cheerio = require( 'cheerio' ) - , fs = require( 'fs' ) - ; - -function getTextWithAlt( $, $element ) { - if ( !$element ) { - return ''; - } - - if ( $element.is( 'img' ) ) { - return ' ' + $element.attr( 'alt' ) + ' '; - } - - if ( $element.is( 'input' ) ) { - return $element.attr( 'value' ); - } - - return $element.contents().map( function( i, domElement ) { - let returnText; - if ( domElement.nodeType === 3 ) { - returnText = domElement.data; - } else if ( domElement.nodeType === 1 ) { - $element = $( domElement ); - if ( $element.is( 'img, input' ) || $element.find( 'img[alt], input[value]' ).length > 0 ) { - returnText = getTextWithAlt( $, $element ); - } else { - returnText = $element.text(); - } - } - return returnText; - }) - .get() - .join( '' ); -} - -function extractFromText( data, options, cb ) { - var $, text; - - text = data.toString() - .replace( /< *(br|p|div|section|aside|button|header|footer|li|article|blockquote|cite|code|h1|h2|h3|h4|h5|h6|legend|nav)((.*?)>)/g, '<$1$2|||||' ) - .replace( /< *\/(td|a|option) *>/g, ' ' ) // spacing some things out so text doesn't get smashed together - .replace( /< *(a|td|option)/g, ' <$1' ) // spacing out links - .replace( /< *(br|hr) +\/>/g, '|||||<$1\\>' ) - .replace( /<\/ +?(p|div|section|aside|button|header|footer|li|article|blockquote|cite|code|h1|h2|h3|h4|h5|h6|legend|nav)>/g, '|||||' ); - - text = '' + text + ''; - - try { - $ = cheerio.load( text ); - $( 'script' ).remove(); - $( 'style' ).remove(); - $( 'noscript' ).remove(); - - const $docElement = $( 'textractwrapper' ); - - if ( options.includeAltText ) { - text = getTextWithAlt( $, $docElement ); - } else { - text = $docElement.text(); - } - - text = text.replace( /\|\|\|\|\|/g, '\n' ) - .replace( /(\n\u00A0|\u00A0\n|\n | \n)+/g, '\n' ) - .replace( /(\r\u00A0|\u00A0\r|\r | \r)+/g, '\n' ) - .replace( /(\v\u00A0|\u00A0\v|\v | \v)+/g, '\n' ) - .replace( /(\t\u00A0|\u00A0\t|\t | \t)+/g, '\n' ) - .replace( /[\n\r\t\v]+/g, '\n' ) - ; - } catch ( err ) { - cb( err, null ); - return; - } - - cb( null, text ); -} - -function extractText( filePath, options, cb ) { - fs.readFile( filePath, function( error, data ) { - if ( error ) { - cb( error, null ); - return; - } - extractFromText( data, options, cb ); - }); -} - -module.exports = { - types: [ - 'text/html', - 'text/xml', - 'application/xml', - 'application/rss+xml', - 'application/atom+xml' - ], - extract: extractText, - extractFromText: extractFromText -}; diff --git a/lib/extractors/html.ts b/lib/extractors/html.ts new file mode 100644 index 0000000..43db6bd --- /dev/null +++ b/lib/extractors/html.ts @@ -0,0 +1,122 @@ +import { load, type CheerioAPI, type Cheerio } from 'cheerio'; +// eslint-disable-next-line n/no-unpublished-import +import type { AnyNode } from 'domhandler'; +import type { Options } from '../types.js'; + +/** + * Get text with alt text + * @param $ cheerio API + * @param $element cheerio element + * @returns text with alt text + */ +function getTextWithAlt( + $: CheerioAPI, + $element: Cheerio, +): string { + if (!$element) { + return ''; + } + + if ($element.is('img')) { + return ` ${$element.attr('alt')} `; + } + + if ($element.is('input')) { + return $element.attr('value') ?? ''; + } + + return $element + .contents() + .map((_i, domElement) => { + if (domElement.nodeType === 3) { + return domElement.data; + } + + if (domElement.nodeType === 1) { + const $innerElement = $(domElement); + if ( + $innerElement.is('img, input') || + $innerElement.find('img[alt], input[value]').length > 0 + ) { + return getTextWithAlt($, $innerElement); + } else { + return $innerElement.text(); + } + } + + return ''; + }) + .get() + .join(''); +} + +/** + * Extract text from HTML + * @param data HTML data + * @param options options + * @returns extracted text + */ +export function extractFromString(data: string, options: Options): string { + const text = data + .replace( + /< *(br|p|div|section|aside|button|header|footer|li|article|blockquote|cite|code|h1|h2|h3|h4|h5|h6|legend|nav)((.*?)>)/g, + '<$1$2|||||', + ) + .replace(/< *\/(td|a|option) *>/g, ' ') // spacing some things out so text doesn't get smashed together + .replace(/< *(a|td|option)/g, ' <$1') // spacing out links + .replace(/< *(br|hr) +\/>/g, '|||||<$1\\>') + .replace( + /<\/ +?(p|div|section|aside|button|header|footer|li|article|blockquote|cite|code|h1|h2|h3|h4|h5|h6|legend|nav)>/g, + '|||||', + ); + + const wrappedText = `${text}`; + + const $ = load(wrappedText); + $('script').remove(); + $('style').remove(); + $('noscript').remove(); + + const $docElement = $('textractwrapper'); + + let extractedText: string; + + if (options.includeAltText) { + extractedText = getTextWithAlt($, $docElement); + } else { + extractedText = $docElement.text(); + } + + extractedText = extractedText + .replace(/\|\|\|\|\|/g, '\n') + .replace(/(\n\u00A0|\u00A0\n|\n | \n)+/g, '\n') + .replace(/(\r\u00A0|\u00A0\r|\r | \r)+/g, '\n') + .replace(/(\v\u00A0|\u00A0\v|\v | \v)+/g, '\n') + .replace(/(\t\u00A0|\u00A0\t|\t | \t)+/g, '\n') + .replace(/[\n\r\t\v]+/g, '\n'); + + return extractedText; +} + +/** + * Extract text from HTML file + * @param buffer buffer + * @param options options + * @returns extracted text + */ +function extractText(buffer: Buffer, options: Options): string { + return extractFromString(buffer.toString(), options); +} + +export default { + inputKind: 'buffer' as const, + types: [ + 'text/html', + 'text/xml', + 'application/xml', + 'application/rss+xml', + 'application/atom+xml', + ], + extract: extractText, + extractFromString, +}; diff --git a/lib/extractors/images.js b/lib/extractors/images.js deleted file mode 100644 index 333b6ae..0000000 --- a/lib/extractors/images.js +++ /dev/null @@ -1,46 +0,0 @@ -var exec = require( 'child_process' ).exec - , util = require( '../util' ) - ; - -function tesseractExtractionCommand( options, inputFile, outputFile ) { - var cmd = 'tesseract ' + inputFile + ' ' + outputFile; - if ( options.tesseract ) { - if ( options.tesseract.lang ) { - cmd += ' -l ' + options.tesseract.lang; - } else if ( options.tesseract.cmd ) { - cmd += ' ' + options.tesseract.cmd; - } - } - cmd += ' quiet'; - return cmd; -} - -function extractText( filePath, options, cb ) { - var execOptions = util.createExecOptions( 'images', options ); - util.runExecIntoFile( 'tesseract', filePath, options, - execOptions, tesseractExtractionCommand, cb ); -} - -function testForBinary( options, cb ) { - exec( 'tesseract', - function( error, stdout, stderr ) { - var msg; - // checking for content of help text - if ( ( error && error.toString().indexOf( 'Usage:' ) > -1 ) || - ( stderr && stderr.toString().indexOf( 'Usage:' ) > -1 ) || - ( stdout && stdout.toString().indexOf( 'Usage:' ) > -1 ) ) { - cb( true ); - } else { - msg = 'INFO: \'tesseract\' does not appear to be installed, ' + - 'so textract will be unable to extract images.'; - cb( false, msg ); - } - } - ); -} - -module.exports = { - types: ['image/png', 'image/jpeg', 'image/gif'], - extract: extractText, - test: testForBinary -}; diff --git a/lib/extractors/images.ts b/lib/extractors/images.ts new file mode 100644 index 0000000..31a15ce --- /dev/null +++ b/lib/extractors/images.ts @@ -0,0 +1,79 @@ +import { exec } from 'node:child_process'; +import type { Options } from '../types.js'; +import { createExecOptions, runExecIntoFile } from '../util.js'; + +/** + * Generate tesseract extraction command + * @param inputFile input file + * @param outputFile output file + * @param options options + * @returns tesseract extraction command + */ +function tesseractExtractionCommand( + inputFile: string, + outputFile: string, + options: Options, +): string { + let cmd = `tesseract ${inputFile} ${outputFile}`; + const tesseractOptions = options.tesseract; + if (tesseractOptions) { + if ('lang' in tesseractOptions && tesseractOptions.lang) { + cmd += ` -l ${tesseractOptions.lang}`; + } else if ('cmd' in tesseractOptions && tesseractOptions.cmd) { + cmd += ` ${tesseractOptions.cmd}`; + } + } + cmd += ' quiet'; + return cmd; +} + +/** + * Extract text from an image + * @param filePath path to image + * @param options options + * @returns extracted text + */ +async function extractText( + filePath: string, + options: Options, +): Promise { + const execOptions = createExecOptions('images', options); + return runExecIntoFile( + 'tesseract', + filePath, + options, + execOptions, + tesseractExtractionCommand, + ); +} + +/** + * Test if tesseract is installed + * @param _options options (not used) + * @returns true if tesseract is installed + */ +async function testForBinary(_options: Options): Promise { + return new Promise((resolve, reject) => { + exec('tesseract', (error, stdout, stderr) => { + // checking for content of help text + if ( + error?.toString().includes('Usage:') || + stderr.includes('Usage:') || + stdout.includes('Usage:') + ) { + resolve(true); + return; + } + const msg = + "INFO: 'tesseract' does not appear to be installed, so textract will be unable to extract images."; + reject(new Error(msg)); + }); + }); +} + +export default { + inputKind: 'filePath' as const, + types: ['image/png', 'image/jpeg', 'image/gif'], + extract: extractText, + test: testForBinary, +}; diff --git a/lib/extractors/index.ts b/lib/extractors/index.ts new file mode 100644 index 0000000..02ecef2 --- /dev/null +++ b/lib/extractors/index.ts @@ -0,0 +1,46 @@ +import type { Options } from '../types.js'; +import docOSX from './doc-osx.js'; +import doc from './doc.js'; +import docx from './docx.js'; +import epub from './epub.js'; +import html from './html.js'; +import images from './images.js'; +import md from './md.js'; +import odt from './odt.js'; +import pdf from './pdf.js'; +import pptx from './pptx.js'; +import rtf from './rtf.js'; +import text from './text.js'; +import xls from './xls.js'; + +export type Extractor = + | { + inputKind: 'filePath'; + types: (string | RegExp)[]; + extract: (filePath: string, options: Options) => string | Promise; + test?: (options: Options) => Promise; + } + | { + inputKind: 'buffer'; + types: (string | RegExp)[]; + extract: (buffer: Buffer, options: Options) => string | Promise; + test?: (options: Options) => Promise; + }; + +const extractors: Extractor[] = [ + docOSX, + doc, + docx, + epub, + html, + images, + md, + odt, + pdf, + pptx, + rtf, + text, + xls, +]; + +export default extractors; diff --git a/lib/extractors/md.js b/lib/extractors/md.js deleted file mode 100644 index 216339c..0000000 --- a/lib/extractors/md.js +++ /dev/null @@ -1,26 +0,0 @@ -var fs = require( 'fs' ) - , marked = require( 'marked' ) - , htmlExtract = require( './html' ) - ; - -function extractText( filePath, options, cb ) { - fs.readFile( filePath, function( error, data ) { - if ( error ) { - cb( error, null ); - return; - } - - marked( data.toString(), function( err, content ) { - if ( err ) { - cb( err, null ); - } else { - htmlExtract.extractFromText( content, options, cb ); - } - }); - }); -} - -module.exports = { - types: ['text/x-markdown', 'text/markdown'], - extract: extractText -}; diff --git a/lib/extractors/md.ts b/lib/extractors/md.ts new file mode 100644 index 0000000..a957378 --- /dev/null +++ b/lib/extractors/md.ts @@ -0,0 +1,20 @@ +import { marked } from 'marked'; +import type { Options } from '../types.js'; +import htmlExtract from './html.js'; + +/** + * Extract text from a Markdown file + * @param buffer buffer + * @param options options + * @returns extracted text + */ +async function extractText(buffer: Buffer, options: Options): Promise { + const parsed = await marked(buffer.toString()); + return htmlExtract.extractFromString(parsed, options); +} + +export default { + inputKind: 'buffer' as const, + types: ['text/x-markdown', 'text/markdown'], + extract: extractText, +}; diff --git a/lib/extractors/odt.js b/lib/extractors/odt.js deleted file mode 100644 index ab6e192..0000000 --- a/lib/extractors/odt.js +++ /dev/null @@ -1,69 +0,0 @@ -var cheerio = require( 'cheerio' ) - , yauzl = require( 'yauzl' ) - , util = require( '../util' ) - ; - -function extractText( filePath, options, cb ) { - yauzl.open( filePath, function( err, zipfile ) { - var textOnTheWay = false; - - if ( err ) { - util.yauzlError( err, cb ); - return; - } - - zipfile.on( 'end', function() { - if ( !textOnTheWay ) { - cb( - new Error( 'Extraction could not find content.xml in file, ' + - 'are you sure it is the mime type it says it is?' ), - null ); - } - }); - - zipfile.on( 'entry', function( entry ) { - if ( entry.fileName === 'content.xml' ) { - textOnTheWay = true; - util.getTextFromZipFile( zipfile, entry, function( err2, text ) { - var output = text - .replace( 'inflating: content.xml', '' ) - .replace( /^(.Archive).*/, '' ) - .replace( /text:p/g, 'textractTextNode' ) - .replace( /text:h/g, 'textractTextNode' ) - // remove empty nodes - .replace( //g, '' ) - // remove empty nodes that have styles - .replace( /]*\/>/g, '' ) - .trim() - , $ = cheerio.load( '' + output + '' ) - , nodes = $( 'textractTextNode' ) - , nodeTexts = [] - , i - ; - - for ( i = 0; i < nodes.length; i++ ) { - nodeTexts.push( $( nodes[i] ).text() ); - } - - cb( null, nodeTexts.join( '\n' ) ); - }); - } - }); - - zipfile.on( 'error', function( err3 ) { - cb( err3 ); - }); - }); -} - -module.exports = { - types: [ - 'application/vnd.oasis.opendocument.text', - 'application/vnd.oasis.opendocument.text-template', - 'application/vnd.oasis.opendocument.graphics', - 'application/vnd.oasis.opendocument.graphics-template', - 'application/vnd.oasis.opendocument.presentation', - 'application/vnd.oasis.opendocument.presentation-template' - ], - extract: extractText -}; diff --git a/lib/extractors/odt.ts b/lib/extractors/odt.ts new file mode 100644 index 0000000..03a9550 --- /dev/null +++ b/lib/extractors/odt.ts @@ -0,0 +1,72 @@ +import fs from 'node:fs/promises'; +import * as cheerio from 'cheerio'; +import JSZip from 'jszip'; +import type { Options } from '../types.js'; + +/** + * Extract text from a ODT file + * @param filePath path to file + * @param _options options (not used) + * @returns extracted text + */ +async function extractText( + filePath: string, + _options: Options, +): Promise { + const buffer = await fs.readFile(filePath); + let zip: JSZip; + try { + zip = await JSZip.loadAsync(buffer); + } catch (unknownError) { + if (unknownError instanceof Error) { + if (unknownError.message?.includes('End of central directory')) { + throw new Error( + `File not correctly recognized as zip file, ${unknownError.message}`, + ); + } + throw unknownError; + } + throw new Error('Unknown error while reading ODT file'); + } + + const content = zip.file('content.xml'); + if (!content) { + throw new Error( + 'Extraction could not find content.xml in file, are you sure it is the mime type it says it is?', + ); + } + + const text = await content.async('string'); + const output = text + .replace('inflating: content.xml', '') + .replace(/^(.Archive).*/, '') + .replace(/text:p/g, 'textractTextNode') + .replace(/text:h/g, 'textractTextNode') + // remove empty nodes + .replace(//g, '') + // remove empty nodes that have styles + .replace(/]*\/>/g, '') + .trim(); + + const $ = cheerio.load(`${output}`); + const nodes = $('textractTextNode'); + const nodeTexts: string[] = []; + for (const node of nodes) { + nodeTexts.push($(node).text()); + } + + return nodeTexts.join('\n'); +} + +export default { + inputKind: 'filePath' as const, + types: [ + 'application/vnd.oasis.opendocument.text', + 'application/vnd.oasis.opendocument.text-template', + 'application/vnd.oasis.opendocument.graphics', + 'application/vnd.oasis.opendocument.graphics-template', + 'application/vnd.oasis.opendocument.presentation', + 'application/vnd.oasis.opendocument.presentation-template', + ], + extract: extractText, +}; diff --git a/lib/extractors/pdf.js b/lib/extractors/pdf.js deleted file mode 100644 index 656729d..0000000 --- a/lib/extractors/pdf.js +++ /dev/null @@ -1,43 +0,0 @@ -var path = require( 'path' ) - , exec = require( 'child_process' ).exec - , extract = require( 'pdf-text-extract' ) - ; - -function extractText( filePath, options, cb ) { - // See https://github.com/dbashford/textract/issues/75 for description of - // what is happening here - var pdftotextOptions = options.pdftotextOptions || { layout: 'raw' }; - - extract( filePath, pdftotextOptions, function( error, pages ) { - var fullText; - if ( error ) { - error = new Error( 'Error extracting PDF text for file at [[ ' + - path.basename( filePath ) + ' ]], error: ' + error.message ); - cb( error, null ); - return; - } - fullText = pages.join( ' ' ).trim(); - cb( null, fullText ); - }); -} - -function testForBinary( options, cb ) { - exec( 'pdftotext -v', - function( error, stdout, stderr ) { - var msg; - if ( stderr && stderr.indexOf( 'pdftotext version' ) > -1 ) { - cb( true ); - } else { - msg = 'INFO: \'pdftotext\' does not appear to be installed, ' + - 'so textract will be unable to extract PDFs.'; - cb( false, msg ); - } - } - ); -} - -module.exports = { - types: ['application/pdf'], - extract: extractText, - test: testForBinary -}; diff --git a/lib/extractors/pdf.ts b/lib/extractors/pdf.ts new file mode 100644 index 0000000..b97fe6a --- /dev/null +++ b/lib/extractors/pdf.ts @@ -0,0 +1,64 @@ +import { exec } from 'node:child_process'; +import path from 'node:path'; +import { pdfTextExtract } from '../pdf-text-extract/index.js'; +import type { Options } from '../types.js'; + +/** + * Extract text from a PDF file + * @param filePath path to file + * @param options options + * @returns extracted text + */ +async function extractText( + filePath: string, + options: Options, +): Promise { + // See https://github.com/dbashford/textract/issues/75 for description of + // what is happening here + const pdftotextOptions = options.pdftotextOptions ?? { layout: 'raw' }; + + try { + const pages = await pdfTextExtract(filePath, pdftotextOptions); + return pages.join(' ').trim(); + } catch (error) { + throw new Error( + `Error extracting PDF text for file at [[ ${path.basename( + filePath, + )} ]], error: ${error instanceof Error ? error.message : 'Unknown error'}`, + ); + } +} + +/** + * Test if pdftotext is installed + * @param _options options (not used) + * @returns true if pdftotext is installed + */ +async function testForBinary(_options: Options): Promise { + return new Promise((resolve, reject) => { + exec('pdftotext -v', (error, _stdout, stderr) => { + if (error) { + reject(error); + return; + } + + if (stderr?.includes('pdftotext version')) { + resolve(true); + return; + } + + reject( + new Error( + "INFO: 'pdftotext' does not appear to be installed, so textract will be unable to extract PDFs.", + ), + ); + }); + }); +} + +export default { + inputKind: 'filePath' as const, + types: ['application/pdf'], + extract: extractText, + test: testForBinary, +}; diff --git a/lib/extractors/ppt.js b/lib/extractors/ppt.js deleted file mode 100644 index 458d550..0000000 --- a/lib/extractors/ppt.js +++ /dev/null @@ -1,25 +0,0 @@ -/* eslint-disable */ - -var fs = require( 'fs' ); - //, ppt = require( 'ppt' ); - -var extractText = function( filePath, options, cb ) { - /* - var captured = ppt.readFile(filePath); - console.log('CAPTURED!!!!') - console.log(captured) - console.log('CAPTURED!!!!') - cb( null, null ); - if ( error ) { - cb( error, null ); - return; - } - cb( null, data.toString() ); - */ -}; - -module.exports = { - // types: ['application/vnd.ms-powerpoint'], - types:[], - extract: extractText -}; diff --git a/lib/extractors/pptx.js b/lib/extractors/pptx.js deleted file mode 100644 index 907669e..0000000 --- a/lib/extractors/pptx.js +++ /dev/null @@ -1,94 +0,0 @@ -var xpath = require( 'xpath' ) - , Dom = require( 'xmldom' ).DOMParser - , yauzl = require( 'yauzl' ) - , util = require( '../util' ) - , slideMatch = /^ppt\/slides\/slide/ - , noteMatch = /^ppt\/notesSlides\/notesSlide/ - ; - -function _compareSlides( a, b ) { - if ( a.slide < b.slide ) { - return -1; - } - if ( a.slide > b.slide ) { - return 1; - } - return 0; -} - -function _calculateExtractedText( slideText ) { - var doc = new Dom().parseFromString( slideText ) - , ps = xpath.select( "//*[local-name()='p']", doc ) - , text = '' - ; - - ps.forEach( function( paragraph ) { - var ts - , localText = '' - ; - - paragraph = new Dom().parseFromString( paragraph.toString() ); - ts = xpath.select( "//*[local-name()='t' or local-name()='tab' or local-name()='br']", - paragraph ); - ts.forEach( function( t ) { - if ( t.localName === 't' && t.childNodes.length > 0 ) { - localText += t.childNodes[0].data; - } else { - if ( t.localName === 'tab' || t.localName === 'br' ) { - localText += ''; - } - } - }); - text += localText + '\n'; - }); - - return text; -} - -function extractText( filePath, options, cb ) { - var slides = []; - - yauzl.open( filePath, function( err, zipfile ) { - if ( err ) { - util.yauzlError( err, cb ); - return; - } - - zipfile.on( 'end', function() { - var slidesText, text; - if ( slides.length ) { - slides.sort( _compareSlides ); - slidesText = slides.map( function( slide ) { - return slide.text; - }).join( '\n' ); - text = _calculateExtractedText( slidesText ); - cb( null, text ); - } else { - cb( - new Error( 'Extraction could not find slides in file, are you' + - ' sure it is the mime type it says it is?' ), - null ); - } - }); - - zipfile.on( 'entry', function( entry ) { - if ( slideMatch.test( entry.fileName ) || noteMatch.test( entry.fileName ) ) { - util.getTextFromZipFile( zipfile, entry, function( err2, text ) { - var slide = +entry.fileName.replace( 'ppt/slides/slide', '' ).replace( '.xml', '' ); - slides.push({ slide: slide, text: text }); - }); - } - }); - - zipfile.on( 'error', function( err3 ) { - cb( err3 ); - }); - }); -} - -module.exports = { - types: [ - 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'application/vnd.openxmlformats-officedocument.presentationml.template'], - extract: extractText -}; diff --git a/lib/extractors/pptx.ts b/lib/extractors/pptx.ts new file mode 100644 index 0000000..e95b07b --- /dev/null +++ b/lib/extractors/pptx.ts @@ -0,0 +1,219 @@ +import { XMLParser } from 'fast-xml-parser'; +import JSZip from 'jszip'; +import type { Options } from '../types.js'; + +const xmlParser = new XMLParser({ ignoreAttributes: false, trimValues: false }); + +/** + * Compare two numbers + * @param a first number + * @param b second number + * @returns -1 if a is less than b, 1 if a is greater than b, 0 if a is equal to b + */ +function compareNumbers(a: number, b: number) { + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + +/** + * Check if a key is a paragraph key + * @param key key to check + * @returns true if the key is a paragraph key, false otherwise + */ +function isParagraphKey(key: string): boolean { + return key === 'p' || key.endsWith(':p'); +} + +/** + * Check if a key is a text key + * @param key key to check + * @returns true if the key is a text key, false otherwise + */ +function isTextKey(key: string): boolean { + return key === 't' || key.endsWith(':t'); +} + +/** + * Check if a key is a break or tab key + * @param key key to check + * @returns true if the key is a break or tab key, false otherwise + */ +function isBreakOrTabKey(key: string): boolean { + return ( + key.endsWith(':br') || key.endsWith(':tab') || key === 'br' || key === 'tab' + ); +} + +/** + * Convert a paragraph node to text + * @param pNode paragraph node + * @returns text of the paragraph + */ +function paragraphToText(pNode: unknown): string { + const texts: string[] = []; + + const collectTexts = (node: unknown) => { + if (node == null) return; + if (Array.isArray(node)) { + for (const child of node) collectTexts(child); + return; + } + if (typeof node === 'object') { + for (const [key, value] of Object.entries( + node as Record, + )) { + if (isTextKey(key)) { + if (typeof value === 'string') { + texts.push(value); + } + // if value is object, ignore; parser typically yields string for text + } else if (isBreakOrTabKey(key)) { + // ignore; legacy extractor treated br/tab as no-op inside paragraph + } else { + collectTexts(value); + } + } + } + }; + + collectTexts(pNode); + return texts.join(''); +} + +/** + * Extract paragraphs from an object + * @param obj object to extract paragraphs from + * @param out array to store the paragraphs + * @param includeBlank whether to include blank paragraphs + */ +function extractParagraphs(obj: unknown, out: string[], includeBlank: boolean) { + if (obj == null) return; + if (Array.isArray(obj)) { + for (const item of obj) extractParagraphs(item, out, includeBlank); + return; + } + if (typeof obj === 'object') { + for (const [key, value] of Object.entries(obj as Record)) { + if (isParagraphKey(key)) { + if (Array.isArray(value)) { + for (const p of value) { + const t = paragraphToText(p); + // eslint-disable-next-line max-depth + if (t.length > 0 || includeBlank) { + out.push(t); + } + } + } else { + const t = paragraphToText(value); + if (t.length > 0 || includeBlank) out.push(t); + } + } else { + extractParagraphs(value, out, includeBlank); + } + } + } +} + +/** + * Extract text from a slide XML + * @param xml XML to extract text from + * @param includeBlank whether to include blank paragraphs + * @returns text from the slide + */ +function extractTextFromSlideXml(xml: string, includeBlank: boolean): string { + const obj = xmlParser.parse(xml) as unknown; + const paragraphs: string[] = []; + extractParagraphs(obj, paragraphs, includeBlank); + const s = paragraphs.map((p) => `${p}\n`).join(''); + return s.replace(/\n+$/g, '\n'); +} + +/** + * Extract text from a PPTX file + * @param buffer buffer + * @param options options + * @returns extracted text + */ +async function extractText(buffer: Buffer, options: Options): Promise { + let zip: JSZip; + try { + zip = await JSZip.loadAsync(buffer); + } catch (unknownError) { + if (unknownError instanceof Error) { + if (unknownError.message?.includes('End of central directory')) { + throw new Error( + `File not correctly recognized as zip file, ${unknownError.message}`, + ); + } + throw unknownError; + } + throw new Error('Unknown error while reading PPTX file'); + } + + const slideFiles = Object.keys(zip.files) + .filter((name) => /^ppt\/slides\/slide\d+\.xml$/.test(name)) + .map((name) => { + const m = /slide(\d+)\.xml$/.exec(name); + return { name, index: Number(m?.[1] ?? NaN) }; + }) + .filter((s) => Number.isFinite(s.index)) + .sort((a, b) => compareNumbers(a.index, b.index)); + + const notesFiles = Object.keys(zip.files) + .filter((name) => /^ppt\/notesSlides\/notesSlide\d+\.xml$/.test(name)) + .map((name) => { + const m = /notesSlide(\d+)\.xml$/.exec(name); + return { name, index: Number(m?.[1] ?? NaN) }; + }) + .filter((s) => Number.isFinite(s.index)) + .sort((a, b) => compareNumbers(a.index, b.index)); + + if (slideFiles.length === 0) { + throw new Error( + 'Extraction could not find slides in file, are you sure it is the mime type it says it is?', + ); + } + + const includeBlank = Boolean( + options.preserveLineBreaks || options.preserveOnlyMultipleLineBreaks, + ); + const slideTexts: Map = new Map(); + for (const { name, index } of slideFiles) { + const file = zip.file(name); + if (!file) continue; + const xml = await file.async('string'); + slideTexts.set(index, extractTextFromSlideXml(xml, includeBlank)); + } + + const notesTexts: Map = new Map(); + for (const { name, index } of notesFiles) { + const file = zip.file(name); + if (!file) continue; + const xml = await file.async('string'); + notesTexts.set(index, extractTextFromSlideXml(xml, includeBlank)); + } + + const parts: string[] = []; + for (const { index } of slideFiles) { + const s = slideTexts.get(index); + if (s) parts.push(s); + const n = notesTexts.get(index); + if (n) { + parts.push(n); + // Some presentations include slide number in notes. Legacy extractor captured it; add index explicitly. + parts.push(`${index} `); + } + } + + return parts.join(''); +} + +export default { + inputKind: 'buffer' as const, + types: [ + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'application/vnd.openxmlformats-officedocument.presentationml.template', + ], + extract: extractText, +}; diff --git a/lib/extractors/rtf.js b/lib/extractors/rtf.js deleted file mode 100644 index 5a60882..0000000 --- a/lib/extractors/rtf.js +++ /dev/null @@ -1,74 +0,0 @@ -var exec = require( 'child_process' ).exec - , os = require( 'os' ) - , path = require( 'path' ) - , htmlExtract = require( './html' ) - , util = require( '../util' ) - , types - ; - -function extractText( filePath, options, cb ) { - var execOptions = util.createExecOptions( 'rtf', options ) - , escapedPath = filePath.replace( /\s/g, '\\ ' ) - ; - - // Going to output html from unrtf because unrtf does a great job of - // going to html, but does a crap job of going to text. It leaves sections - // out, strips apostrophes, leaves nasty quotes in for bullets and more - // that I've likely not yet discovered. - // - // textract can go from html to text on its own, so let unrtf go to html - // then extract the text from that - // - // Also do not have to worry about stripping comments from unrtf text - // output since HTML comments are not included in output. Also, the - // unrtf --quiet option doesn't work. - exec( 'unrtf --html --nopict ' + escapedPath, - execOptions, - function( error, stdout /* , stderr */ ) { - var err; - if ( error ) { - err = new Error( 'unrtf read of file named [[ ' + - path.basename( filePath ) + ' ]] failed: ' + error ); - cb( err, null ); - } else { - htmlExtract.extractFromText( stdout.trim(), {}, cb ); - } - } - ); -} - -function testForBinary( options, cb ) { - // just non-osx extractor - if ( os.platform() === 'darwin' ) { - cb( true ); - return; - } - - exec( 'unrtf ' + __filename, - function( error /* , stdout, stderr */ ) { - var msg; - if ( error !== null && error.message && - error.message.indexOf( 'not found' ) !== -1 ) { - msg = 'INFO: \'unrtf\' does not appear to be installed, ' + - 'so textract will be unable to extract RTFs.'; - cb( false, msg ); - } else { - cb( true ); - } - } - ); -} - -// rely on native tools on osx -if ( os.platform() === 'darwin' ) { - types = []; - // types = ['application/rtf', 'text/rtf']; -} else { - types = ['application/rtf', 'text/rtf']; -} - -module.exports = { - types: types, - extract: extractText, - test: testForBinary -}; diff --git a/lib/extractors/rtf.ts b/lib/extractors/rtf.ts new file mode 100644 index 0000000..3981adf --- /dev/null +++ b/lib/extractors/rtf.ts @@ -0,0 +1,93 @@ +import { exec } from 'node:child_process'; +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import type { Options } from '../types.js'; +import { createExecOptions } from '../util.js'; +import htmlExtract from './html.js'; + +/** + * Extract text from a RTF file + * @param filePath path to file + * @param options options + * @returns extracted text + */ +async function extractText( + filePath: string, + options: Options, +): Promise { + const execOptions = createExecOptions('rtf', options); + const escapedPath = filePath.replace(/\s/g, '\\ '); + // Going to output html from unrtf because unrtf does a great job of + // going to html, but does a crap job of going to text. It leaves sections + // out, strips apostrophes, leaves nasty quotes in for bullets and more + // that I've likely not yet discovered. + // + // textract can go from html to text on its own, so let unrtf go to html + // then extract the text from that + // + // Also do not have to worry about stripping comments from unrtf text + // output since HTML comments are not included in output. Also, the + // unrtf --quiet option doesn't work. + return new Promise((resolve, reject) => { + exec( + `unrtf --html --nopict ${escapedPath}`, + execOptions, + (error, stdout /* , stderr */) => { + if (error) { + reject( + new Error( + `unrtf read of file named [[ ${path.basename(filePath)} ]] failed: ${ + error.message + }`, + ), + ); + return; + } + + const text = htmlExtract.extractFromString( + stdout.toString().trim(), + options, + ); + resolve(text); + }, + ); + }); +} + +/** + * Test if unrtf is installed + * @param _options options (not used) + * @returns true if unrtf is installed + */ +async function testForBinary(_options: Options): Promise { + // just non-osx extractor + if (os.platform() === 'darwin') { + return true; + } + + const filename = fileURLToPath(import.meta.url); + + return new Promise((resolve, reject) => { + exec(`unrtf ${filename}`, (error /* , stdout, stderr */) => { + if (error?.message?.includes('not found')) { + reject( + new Error( + "INFO: 'unrtf' does not appear to be installed, so textract will be unable to extract RTFs.", + ), + ); + return; + } + + resolve(true); + }); + }); +} + +export default { + inputKind: 'filePath' as const, + // rely on native tools on osx + types: os.platform() === 'darwin' ? [] : ['application/rtf', 'text/rtf'], + extract: extractText, + test: testForBinary, +}; diff --git a/lib/extractors/text.js b/lib/extractors/text.js deleted file mode 100644 index 1c44764..0000000 --- a/lib/extractors/text.js +++ /dev/null @@ -1,36 +0,0 @@ -var fs = require( 'fs' ) - , iconv = require( 'iconv-lite' ) - , jschardet = require( 'jschardet' ) - , path = require( 'path' ) - ; - -function extractText( filePath, options, cb ) { - fs.readFile( filePath, function( error, data ) { - var encoding, decoded, detectedEncoding; - if ( error ) { - cb( error, null ); - return; - } - try { - detectedEncoding = jschardet.detect( data ).encoding; - if ( !detectedEncoding ) { - error = new Error( 'Could not detect encoding for file named [[ ' + - path.basename( filePath ) + ' ]]' ); - cb( error, null ); - return; - } - encoding = detectedEncoding.toLowerCase(); - - decoded = iconv.decode( data, encoding ); - } catch ( e ) { - cb( e ); - return; - } - cb( null, decoded ); - }); -} - -module.exports = { - types: [/text\//, 'application/csv', 'application/javascript'], - extract: extractText -}; diff --git a/lib/extractors/text.ts b/lib/extractors/text.ts new file mode 100644 index 0000000..4e02f18 --- /dev/null +++ b/lib/extractors/text.ts @@ -0,0 +1,25 @@ +import { decode } from 'iconv-lite'; +import { detect } from 'jschardet'; +import type { Options } from '../types.js'; + +/** + * Extract text from a text file + * @param buffer buffer + * @param _options options (not used) + * @returns extracted text + */ +function extractText(buffer: Buffer, _options: Options): string { + const { encoding: detectedEncoding } = detect(buffer); + if (!detectedEncoding) { + throw new Error(`Could not detect encoding`); + } + const encoding = detectedEncoding.toLowerCase(); + + return decode(buffer, encoding); +} + +export default { + inputKind: 'buffer' as const, + types: [/text\//, 'application/csv', 'application/javascript'], + extract: extractText, +}; diff --git a/lib/extractors/xls.js b/lib/extractors/xls.js deleted file mode 100644 index b929e06..0000000 --- a/lib/extractors/xls.js +++ /dev/null @@ -1,35 +0,0 @@ -var path = require( 'path' ) - , J = require( 'j' ) - ; - -function extractText( filePath, options, cb ) { - var CSVs, wb, result, error; - - try { - wb = J.readFile( filePath ); - CSVs = J.utils.to_csv( wb ); - } catch ( err ) { - error = new Error( 'Could not extract ' + path.basename( filePath ) + ', ' + err ); - cb( error, null ); - return; - } - - result = ''; - Object.keys( CSVs ).forEach( function( key ) { - result += CSVs[key]; - }); - - cb( null, result ); -} - -module.exports = { - types: ['application/vnd.ms-excel', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', - 'application/vnd.ms-excel.sheet.macroEnabled.12', - 'application/vnd.oasis.opendocument.spreadsheet', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', - 'application/vnd.oasis.opendocument.spreadsheet-template' - ], - extract: extractText -}; diff --git a/lib/extractors/xls.ts b/lib/extractors/xls.ts new file mode 100644 index 0000000..4097f97 --- /dev/null +++ b/lib/extractors/xls.ts @@ -0,0 +1,43 @@ +import path from 'node:path'; +import * as XLSX from 'xlsx'; +import type { Options } from '../types.js'; + +/** + * Extract text from a XLS file + * @param filePath path to file + * @param _options options (not used) + * @returns extracted text + */ +function extractText(filePath: string, _options: Options): string { + let wb: XLSX.WorkBook; + + try { + wb = XLSX.readFile(filePath); + } catch (err) { + throw new Error( + `Could not extract ${path.basename(filePath)}, ${(err as Error).message}`, + ); + } + + const sheets = wb.Sheets; + let result = ''; + for (const key of Object.keys(sheets)) { + result += XLSX.utils.sheet_to_csv(sheets[key]); + } + + return result; +} + +export default { + inputKind: 'filePath' as const, + types: [ + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'application/vnd.ms-excel.sheet.macroEnabled.12', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'application/vnd.oasis.opendocument.spreadsheet-template', + ], + extract: extractText, +}; diff --git a/lib/index.d.ts b/lib/index.d.ts deleted file mode 100644 index 0c4f2e4..0000000 --- a/lib/index.d.ts +++ /dev/null @@ -1,222 +0,0 @@ -/// - -import * as ChildProc from "child_process"; -import { URL } from "url"; - -export interface extractorExecOpts { - exec: { [index: string]: string }; -} - -export interface Config { - /** - * Pass this in as true and textract will not strip any line breaks. - * @default false - */ - preserveLineBreaks?: boolean | undefined; - /** - * Some extractors, like PDF, insert line breaks at the end of every line, even if the middle of a sentence. - * If this option is set to true, then any instances of a single line break are removed but multiple line breaks are preserved. - * Check your output with this option, though, this doesn't preserve paragraphs unless there are multiple breaks. - * @default false - */ - preserveOnlyMultipleLineBreaks?: boolean | undefined; - /** - * Some extractors (dxf) use node's exec functionality. - * This setting allows for providing config to exec execution. - * One reason you might want to provide this config is if you are dealing with very large files. - * You might want to increase the exec maxBuffer setting. - */ - exec?: ChildProc.ExecException | undefined; - /** - * Doc extractor options for non OS X. - * See `drawingtotext` manual for available options - */ - doc?: extractorExecOpts | undefined; - /** - * DXF extractor options. - * See `antiword` manual for available options - */ - dxf?: extractorExecOpts | undefined; - /** - * Images (png, jpg, gif) extractor options. - * See `tesseract` manual for available options - */ - images?: extractorExecOpts | undefined; - /** - * RTF extractor options. - * See `unrtf` manual for available options - */ - rtf?: extractorExecOpts | undefined; - tesseract?: { - /** - * A pass-through to tesseract allowing for setting of language for extraction. - */ - lang: string; - } | { - /** - * `tesseract.lang` allows a quick means to provide the most popular tesseract option, - * but if you need to configure more options, you can simply pass `cmd`. - * `cmd` is the string that matches the command-line options you want to pass to tesseract. - * For instance, to provide language and psm, - * you would pass `{ tesseract: { cmd:"-l chi_sim -psm 10" } }` - */ - cmd: string; - } | undefined; - /** - * This is a proxy options object to the library textract uses for pdf extraction: pdf-text-extract. - * Options include ownerPassword, userPassword if you are extracting text from password protected PDFs. - * IMPORTANT: textract modifies the pdf-text-extract layout default so that, instead of layout: layout, it uses layout:raw. - * It is not suggested you modify this without understanding what trouble that might get you in. - * See [this GH issue](https://github.com/dbashford/textract/issues/75) for why textract overrides that library's default. - */ - pdftotextOptions?: { - firstPage?: number | undefined; - lastPage?: number | undefined; - resolution?: number | undefined; - crop?: { - x: number; - y: number; - w: number; - h: number; - } | undefined; - /** - * Do not change unless you know what you are doing! - * @default "raw" - */ - layout?: "layout" | "raw" | "htmlmeta" | undefined; - /** - * @default "UTF-8" - */ - encoding?: "UCS-2" | "ASCII7" | "Latin1" | "UTF-8" | "ZapfDingbats" | "Symbol" | undefined; - eol?: "unix" | "dos" | "mac" | undefined; - ownerPassword?: string | undefined; - userPassword?: string | undefined; - /** - * @default true - */ - splitPages?: boolean | undefined; - } | undefined; - /** - * When extracting HTML, whether or not to include `alt` text with the extracted text. - * @default false - */ - includeAltText?: boolean | undefined; -} - -export interface URLConfig extends Config { - /** - * Used with fromUrl, if set, rather than using the content-type from the URL request, will use the provided typeOverride. - */ - typeOverride?: string | undefined; -} - -/** - * Get text from file by path - * @param filePath path to file - * @param callback callback - */ -export function fromFileWithPath(filePath: string, callback: (error: Error | null, text: string) => void): void; -/** - * Get text from file by path - * @param filePath path to file - * @param config configuration object - * @param callback callback - */ -export function fromFileWithPath( - filePath: string, - config: Config, - callback: (error: Error | null, text: string) => void, -): void; - -/** - * Get text from file by path - * @param mimeType mime type of file - * @param filePath path to file - * @param callback callback - */ -export function fromFileWithMimeAndPath( - mimeType: string, - filePath: string, - callback: (error: Error | null, text: string) => void, -): void; -/** - * Get text from file by path - * @param mimeType mime type of file - * @param filePath path to file - * @param config configuration object - * @param callback callback - */ -export function fromFileWithMimeAndPath( - mimeType: string, - filePath: string, - config: Config, - callback: (error: Error | null, text: string) => void, -): void; - -/** - * Get text from file buffer - * @param mimeType mime type of file - * @param buffer path to file - * @param callback callback - */ -export function fromBufferWithMime( - mimeType: string, - buffer: Buffer, - callback: (error: Error | null, text: string) => void, -): void; -/** - * Get text from file buffer - * @param mimeType mime type of file - * @param buffer path to file - * @param config configuration object - * @param callback callback - */ -export function fromBufferWithMime( - mimeType: string, - buffer: Buffer, - config: Config, - callback: (error: Error | null, text: string) => void, -): void; - -/** - * Get text from file buffer - * @param name file name or path - * @param buffer buffer with file content - * @param callback callback - */ -export function fromBufferWithName( - name: string, - buffer: Buffer, - callback: (error: Error | null, text: string) => void, -): void; -/** - * Get text from file buffer - * @param name file name or path - * @param buffer buffer with file content - * @param config configuration object - * @param callback callback - */ -export function fromBufferWithName( - name: string, - buffer: Buffer, - config: Config, - callback: (error: Error | null, text: string) => void, -): void; - -/** - * Get text from url - * @param url url as string or object - * @param callback callback - */ -export function fromUrl(url: string | URL, callback: (error: Error | null, text: string) => void): void; -/** - * Get text from url - * @param url url as string or object - * @param config configuration object - * @param callback callback - */ -export function fromUrl( - url: string | URL, - config: URLConfig, - callback: (error: Error | null, text: string) => void, -): void; diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index 49635ce..0000000 --- a/lib/index.js +++ /dev/null @@ -1,168 +0,0 @@ -var fs = require( 'fs' ) - , path = require( 'path' ) - , mime = require( 'mime' ) - , extract = require( './extract' ) - , os = require( 'os' ) - , got = require( 'got' ) - , tmpDir = os.tmpdir() - ; - -function _genRandom() { - return Math.floor( ( Math.random() * 100000000000 ) + 1 ); -} - -function _extractWithType( type, filePath, options, cb ) { - fs.exists( filePath, function( exists ) { - if ( exists ) { - extract( type, filePath, options, cb ); - } else { - cb( new Error( 'File at path [[ ' + filePath + ' ]] does not exist.' ), null ); - } - }); -} - -function _returnArgsError( _args ) { - var args = Array.prototype.slice.call( _args ) - , callback - ; - - args.forEach( function( parm ) { - if ( parm && typeof parm === 'function' ) { - callback = parm; - } - }); - - if ( callback ) { - callback( new Error( 'Incorrect parameters passed to textract.' ), null ); - } else { - // eslint-disable-next-line no-console - console.error( 'textract could not find a callback function to execute.' ); - } -} - -function _writeBufferToDisk( buff, cb ) { - var fullPath = path.join( tmpDir, 'textract_file_' + _genRandom() ); - - fs.open( fullPath, 'w', function( err, fd ) { - if ( err ) { - throw new Error( 'error opening temp file: ' + err ); - } else { - fs.write( fd, buff, 0, buff.length, null, function( err2 ) { - if ( err2 ) { - throw new Error( 'error writing temp file: ' + err2 ); - } else { - fs.close( fd, function() { - cb( fullPath ); - }); - } - }); - } - }); -} - -function fromFileWithMimeAndPath( type, filePath, options, cb ) { - var called = false; - - if ( typeof type === 'string' && typeof filePath === 'string' ) { - if ( typeof cb === 'function' && typeof options === 'object' ) { - // (mimeType, filePath, options, callback) - _extractWithType( type, filePath, options, cb ); - called = true; - } else if ( typeof options === 'function' && cb === undefined ) { - // (mimeType, filePath, callback) - _extractWithType( type, filePath, {}, options ); - called = true; - } - } - - if ( !called ) { - _returnArgsError( arguments ); - } -} - -function fromFileWithPath( filePath, options, cb ) { - var type; - if ( typeof filePath === 'string' && - ( typeof options === 'function' || typeof cb === 'function' ) ) { - type = ( options && options.typeOverride ) || mime.getType( filePath ); - fromFileWithMimeAndPath( type, filePath, options, cb ); - } else { - _returnArgsError( arguments ); - } -} - -// eslint-disable-next-line no-unused-vars -function fromBufferWithMime( type, bufferContent, options, cb, withPath ) { - if ( typeof type === 'string' && - bufferContent && - bufferContent instanceof Buffer && - ( typeof options === 'function' || typeof cb === 'function' ) ) { - if(typeof options === 'function') { cb = options; options = {} } - _writeBufferToDisk( bufferContent, function( newPath ) { - fromFileWithMimeAndPath( type, newPath, options, function( err, text ) { - // Remove temporary file regardless of error, ignore error on unlink - fs.unlink(newPath, function() {}) - if(cb) cb( err, text ) - }); - }); - } else { - _returnArgsError( arguments ); - } -} - -function fromBufferWithName( filePath, bufferContent, options, cb ) { - var type; - if ( typeof filePath === 'string' ) { - type = mime.getType( filePath ); - fromBufferWithMime( type, bufferContent, options, cb, true ); - } else { - _returnArgsError( arguments ); - } -} - -function fromUrl( url, options, cb ) { - var urlNoQueryParams, extname, filePath, fullFilePath, file, href, callbackCalled; - - // allow url to be either a string or to be a - // Node URL Object: https://nodejs.org/api/url.html - href = ( typeof url === 'string' ) ? url : url.href; - - if ( href ) { - options = options || {}; - urlNoQueryParams = href.split( '?' )[0]; - extname = path.extname( urlNoQueryParams ); - filePath = _genRandom() + extname; - fullFilePath = path.join( tmpDir, filePath ); - file = fs.createWriteStream( fullFilePath ); - file.on( 'finish', function() { - if ( !callbackCalled ) { - fromFileWithPath( fullFilePath, options, cb ); - } - }); - - got.stream( url ) - .on( 'response', function( response ) { - // allows for overriding by the developer or automatically - // populating based on server response. - if ( !options.typeOverride ) { - options.typeOverride = response.headers['content-type'].split( /;/ )[0]; - } - }) - .on( 'error', function( error ) { - var _cb = ( typeof options === 'function' ) ? options : cb; - callbackCalled = true; - _cb( error ); - }) - .pipe( file ); - } else { - _returnArgsError( arguments ); - } -} - -module.exports = { - fromFileWithPath: fromFileWithPath, - fromFileWithMimeAndPath: fromFileWithMimeAndPath, - fromBufferWithName: fromBufferWithName, - fromBufferWithMime: fromBufferWithMime, - fromUrl: fromUrl -}; \ No newline at end of file diff --git a/lib/index.ts b/lib/index.ts new file mode 100644 index 0000000..fb43ea2 --- /dev/null +++ b/lib/index.ts @@ -0,0 +1,36 @@ +import mime from 'mime'; +import extractBase from './extract.js'; +import type { Options } from './types.js'; + +/** + * Extract text from a buffer + * @param buffer buffer + * @param mimeType mime type + * @param options options (optional) + * @returns extracted text + */ +export async function extractFromBuffer( + buffer: Buffer, + mimeType: string, + options: Options = {}, +): Promise { + const text = await extractBase(mimeType, { buffer }, options); + return text; +} + +/** + * Extract text from a file + * @param filePath filePath + * @param mimeType mime type (optional, if not provided, the mime type will be inferred from the file extension) + * @param options options (optional) + * @returns extracted text + */ +export async function extractFromFile( + filePath: string, + mimeType?: string, + options: Options = {}, +): Promise { + const effectiveMimeType = mimeType ?? mime.getType(filePath) ?? ''; + const text = await extractBase(effectiveMimeType, { filePath }, options); + return text; +} diff --git a/lib/pdf-text-extract/LICENSE b/lib/pdf-text-extract/LICENSE new file mode 100644 index 0000000..f174751 --- /dev/null +++ b/lib/pdf-text-extract/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2018, ftorto +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/pdf-text-extract/README.md b/lib/pdf-text-extract/README.md new file mode 100644 index 0000000..bcffe9f --- /dev/null +++ b/lib/pdf-text-extract/README.md @@ -0,0 +1,3 @@ +# PDF Text Extract + +Oriignal author: Noah Isaacson diff --git a/lib/pdf-text-extract/index.ts b/lib/pdf-text-extract/index.ts new file mode 100644 index 0000000..f6e1332 --- /dev/null +++ b/lib/pdf-text-extract/index.ts @@ -0,0 +1,211 @@ +import { spawn } from 'node:child_process'; +import path from 'node:path'; + +export interface Options { + firstPage?: number | undefined; + lastPage?: number | undefined; + resolution?: number | undefined; + crop?: + | { + x: number; + y: number; + w: number; + h: number; + } + | undefined; + /** + * Do not change unless you know what you are doing! + * @default "raw" + */ + layout?: 'layout' | 'raw' | 'htmlmeta' | undefined; + /** + * @default "UTF-8" + */ + encoding?: + | 'UCS-2' + | 'ASCII7' + | 'Latin1' + | 'UTF-8' + | 'ZapfDingbats' + | 'Symbol' + | undefined; + eol?: 'unix' | 'dos' | 'mac' | undefined; + ownerPassword?: string | undefined; + userPassword?: string | undefined; + cwd?: string | null; +} + +/** + * Build the arguments for the pdftotext command + * @param options - The options for the extraction + * @returns The arguments for the pdftotext command + */ +function buildArgs(options: Options) { + const resolvedOptions = { + encoding: 'UTF-8', + layout: 'layout', + ...options, + }; + + // Build args based on options + const args: string[] = []; + + // First and last page to convert + if (resolvedOptions.firstPage !== undefined) { + args.push('-f'); + args.push(resolvedOptions.firstPage.toString()); + } + if (resolvedOptions.lastPage !== undefined) { + args.push('-l'); + args.push(resolvedOptions.lastPage.toString()); + } + + // Resolution, in dpi. (null is pdftotext default = 72) + if (resolvedOptions.resolution !== undefined) { + args.push('-r'); + args.push(resolvedOptions.resolution.toString()); + } + + // If defined, should be an object { x:x, y:y, w:w, h:h } + if (resolvedOptions.crop !== undefined) { + if (resolvedOptions.crop.x !== undefined) { + args.push('-x'); + args.push(resolvedOptions.crop.x.toString()); + } + if (resolvedOptions.crop.y !== undefined) { + args.push('-y'); + args.push(resolvedOptions.crop.y.toString()); + } + if (resolvedOptions.crop.w !== undefined) { + args.push('-W'); + args.push(resolvedOptions.crop.w.toString()); + } + if (resolvedOptions.crop.h !== undefined) { + args.push('-H'); + args.push(resolvedOptions.crop.h.toString()); + } + } + + // One of either 'layout', 'raw' or 'htmlmeta' + if (resolvedOptions.layout === 'layout') { + args.push('-layout'); + } else if (resolvedOptions.layout === 'raw') { + args.push('-raw'); + } else if (resolvedOptions.layout === 'htmlmeta') { + args.push('-htmlmeta'); + } + + // Output text encoding (UCS-2, ASCII7, Latin1, UTF-8, ZapfDingbats or Symbol) + if (resolvedOptions.encoding) { + args.push('-enc'); + args.push(resolvedOptions.encoding); + } + + // Output end of line convention (unix, dos or mac) + if (resolvedOptions.eol !== undefined) { + args.push('-eol'); + args.push(resolvedOptions.eol); + } + + // Owner and User password (for encrypted files) + if (resolvedOptions.ownerPassword !== undefined) { + args.push('-opw'); + args.push(resolvedOptions.ownerPassword); + } + if (resolvedOptions.userPassword !== undefined) { + args.push('-upw'); + args.push(resolvedOptions.userPassword); + } + + return args; +} + +/** + * Split the content into pages + * @param content - The content to split + * @returns The pages + */ +function splitPages(content: string) { + const pages = content.split(/\f/); + if (!pages.length) { + throw new Error( + 'pdf-text-extract failed: no text returned from the pdftotext command', + ); + } + // sometimes there can be an extract blank page on the end + const lastPage = pages[pages.length - 1]; + if (!lastPage) { + pages.pop(); + } + return pages; +} + +/** + * Spawns pdftotext and returns its output + * @param command - The command to use to extract the text + * @param args - The arguments to use to extract the text + * @param options - The options to use to extract the text + * @param cb - The callback to use to handle the output + */ +function streamResults( + command: string, + args: string[], + options: Options, + cb: (error: Error | null, output: string) => void, +) { + let output = ''; + let stderr = ''; + + const stdoutHandler = (data: string) => { + output += data; + }; + + const stderrHandler = (data: string) => { + stderr += data; + }; + + const closeHandler = (code: number) => { + if (code !== 0) { + cb(new Error(`pdf-text-extract command failed: ${stderr}`), ''); + return; + } + cb(null, output); + }; + + const child = spawn(command, args, { cwd: options.cwd ?? undefined }); + child.stdout.setEncoding('utf8'); + child.stderr.setEncoding('utf8'); + child.stdout.on('data', stdoutHandler); + child.stderr.on('data', stderrHandler); + child.on('close', closeHandler); +} + +/** + * Extract the text from the PDF file + * @param filePath - The path to the PDF file + * @param options - The options for the extraction + * @param pdfToTextCommand - The command to use to extract the text + * @returns The pages from the PDF file + */ +export async function pdfTextExtract( + filePath: string, + options: Options = {}, + pdfToTextCommand = 'pdftotext', +) { + const resolvedFilePath = path.resolve(filePath); + + const args = buildArgs(options); + // finish up arguments + args.push(resolvedFilePath); + args.push('-'); + + return new Promise((resolve, reject) => { + streamResults(pdfToTextCommand, args, options, (error, output) => { + if (error) { + reject(error); + return; + } + resolve(splitPages(output)); + }); + }); +} diff --git a/lib/types.ts b/lib/types.ts new file mode 100644 index 0000000..5aab164 --- /dev/null +++ b/lib/types.ts @@ -0,0 +1,82 @@ +import type { ExecOptions } from 'node:child_process'; +import type { Options as PdfTextExtractOptions } from './pdf-text-extract/index.js'; + +export type Input = + | { + buffer: Buffer; + } + | { + filePath: string; + }; + +export interface ExtractorExecOptions { + exec: ExecOptions; +} + +export interface Options { + /** + * Pass this in as true and textract will not strip any line breaks. + * @default false + */ + preserveLineBreaks?: boolean | undefined; + /** + * Some extractors, like PDF, insert line breaks at the end of every line, even if the middle of a sentence. + * If this option is set to true, then any instances of a single line break are removed but multiple line breaks are preserved. + * Check your output with this option, though, this doesn't preserve paragraphs unless there are multiple breaks. + * @default false + */ + preserveOnlyMultipleLineBreaks?: boolean | undefined; + /** + * Some extractors (doc) use node's exec functionality. + * This setting allows for providing config to exec execution. + * One reason you might want to provide this config is if you are dealing with very large files. + * You might want to increase the exec maxBuffer setting. + */ + exec?: ExtractorExecOptions['exec'] | undefined; + /** + * Doc extractor options for non OS X. + * See `drawingtotext` manual for available options + */ + doc?: ExtractorExecOptions | undefined; + /** + * Images (png, jpg, gif) extractor options. + * See `tesseract` manual for available options + */ + images?: ExtractorExecOptions | undefined; + /** + * RTF extractor options. + * See `unrtf` manual for available options + */ + rtf?: ExtractorExecOptions | undefined; + tesseract?: + | { + /** + * A pass-through to tesseract allowing for setting of language for extraction. + */ + lang: string; + } + | { + /** + * `tesseract.lang` allows a quick means to provide the most popular tesseract option, + * but if you need to configure more options, you can simply pass `cmd`. + * `cmd` is the string that matches the command-line options you want to pass to tesseract. + * For instance, to provide language and psm, + * you would pass `{ tesseract: { cmd:"-l chi_sim --psm 10" } }` + */ + cmd: string; + } + | undefined; + /** + * This is a proxy options object to the library textract uses for pdf extraction: pdf-text-extract. + * Options include ownerPassword, userPassword if you are extracting text from password protected PDFs. + * IMPORTANT: textract modifies the pdf-text-extract layout default so that, instead of layout: layout, it uses layout:raw. + * It is not suggested you modify this without understanding what trouble that might get you in. + * See [this GH issue](https://github.com/dbashford/textract/issues/75) for why textract overrides that library's default. + */ + pdftotextOptions?: PdfTextExtractOptions | undefined; + /** + * When extracting HTML, whether or not to include `alt` text with the extracted text. + * @default false + */ + includeAltText?: boolean | undefined; +} diff --git a/lib/util.js b/lib/util.js deleted file mode 100644 index 747b22c..0000000 --- a/lib/util.js +++ /dev/null @@ -1,168 +0,0 @@ -var exec = require( 'child_process' ).exec - , path = require( 'path' ) - , fs = require( 'fs' ) - , os = require( 'os' ) - , outDir = path.join( os.tmpdir(), 'textract' ) - , replacements = [ - [/[\u201C|\u201D|]|“|â€/g, '"'], // fancy double quotes - [/[\u2018|\u2019]|’|‘]/g, '\''], // fancy single quotes/apostrophes - [/…/g, '…'], // elipses - [/–|—/g, '–'] // long hyphen - ] - , rLen = replacements.length - ; - -function ensureTmpDir() { - if ( !fs.existsSync( outDir ) ) { - fs.mkdirSync( outDir, { - recursive: true - }); - } -} - -// replace nasty quotes with simple ones -function replaceBadCharacters( text ) { - var i, repl; - for ( i = 0; i < rLen; i++ ) { - repl = replacements[i]; - text = text.replace( repl[0], repl[1] ); - } - return text; -} - -function yauzlError( err, cb ) { - var msg = err.message; - if ( msg === 'end of central directory record signature not found' ) { - msg = 'File not correctly recognized as zip file, ' + msg; - } - cb( new Error( msg ), null ); -} - -function createExecOptions( type, options ) { - var execOptions = {}; - if ( options[type] && options[type].exec ) { - execOptions = options[type].exec; - } else { - if ( options.exec ) { - execOptions = options.exec; - } - } - return execOptions; -} - -function unzipCheck( type, cb ) { - exec( 'unzip', - function( error /* , stdout, stderr */ ) { - if ( error ) { - // eslint-disable-next-line no-console - console.error( 'textract: \'unzip\' does not appear to be installed, ' + - 'so textract will be unable to extract ' + type + '.' ); - } - cb( error === null ); - } - ); -} - -function getTextFromZipFile( zipfile, entry, cb ) { - zipfile.openReadStream( entry, function( err, readStream ) { - var text = '' - , error = '' - ; - - if ( err ) { - cb( err, null ); - return; - } - - readStream.on( 'data', function( chunk ) { - text += chunk; - }); - readStream.on( 'end', function() { - if ( error.length > 0 ) { - cb( error, null ); - } else { - cb( null, text ); - } - }); - readStream.on( 'error', function( _err ) { - error += _err; - }); - }); -} - -/** - * 1) builds an exec command using provided `genCommand` callback - * 2) runs that command against an input file path - * resulting in an output file - * 3) reads that output file in - * 4) cleans the output file up - * 5) executes a callback with the contents of the file - * - * @param {string} label Name for the extractor, e.g. `Tesseract` - * @param {string} filePath path to file to be extractor - * @param {object} options extractor options as provided - * via user configuration - * @param {object} execOptions execution options passed to - * `exec` commmand as provided via user configuration - * @param {function} genCommand function used to generate - * the command to be executed - * @param {string} cb callback that is passed error/text - * - */ -function runExecIntoFile( label, filePath, options, execOptions, genCommand, cb ) { - // escape the file paths - var fileTempOutPath = path.join( outDir, path.basename( filePath, path.extname( filePath ) ) ) - , escapedFilePath = filePath.replace( /\s/g, '\\ ' ) - , escapedFileTempOutPath = fileTempOutPath.replace( /\s/g, '\\ ' ) - , cmd = genCommand( options, escapedFilePath, escapedFileTempOutPath ) - ; - - ensureTmpDir(); - - exec( cmd, execOptions, - function( error /* , stdout, stderr */ ) { - if ( error !== null ) { - error = new Error( 'Error extracting [[ ' + - path.basename( filePath ) + ' ]], exec error: ' + error.message ); - cb( error, null ); - return; - } - - fs.exists( fileTempOutPath + '.txt', function( exists ) { - if ( exists ) { - fs.readFile( fileTempOutPath + '.txt', 'utf8', function( error2, text ) { - if ( error2 ) { - error2 = new Error( 'Error reading' + label + - ' output at [[ ' + fileTempOutPath + ' ]], error: ' + error2.message ); - cb( error2, null ); - } else { - fs.unlink( fileTempOutPath + '.txt', function( error3 ) { - if ( error3 ) { - error3 = new Error( 'Error, ' + label + - ' , cleaning up temp file [[ ' + fileTempOutPath + - ' ]], error: ' + error3.message ); - cb( error3, null ); - } else { - cb( null, text.toString() ); - } - }); - } - }); - } else { - error = new Error( 'Error reading ' + label + - ' output at [[ ' + fileTempOutPath + ' ]], file does not exist' ); - cb( error, null ); - } - }); - } - ); -} - -module.exports = { - createExecOptions: createExecOptions, - unzipCheck: unzipCheck, - getTextFromZipFile: getTextFromZipFile, - yauzlError: yauzlError, - runExecIntoFile: runExecIntoFile, - replaceBadCharacters: replaceBadCharacters -}; diff --git a/lib/util.ts b/lib/util.ts new file mode 100644 index 0000000..2cbe607 --- /dev/null +++ b/lib/util.ts @@ -0,0 +1,191 @@ +import { exec, type ExecOptions } from 'node:child_process'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import type { Input, Options } from './types.js'; + +const outDirPrefix = path.join(os.tmpdir(), 'textract-'); +const replacements = [ + [/[\u201C|\u201D|]|“|â€/g, '"'], // fancy double quotes + [/[\u2018|\u2019]|’|‘]/g, "'"], // fancy single quotes/apostrophes + [/…/g, '…'], // elipses + [/–|—/g, '–'], // long hyphen +] as const; + +/** + * Ensure the temporary directory exists + * @returns void + */ +async function makeTemporaryDirectory(): Promise { + return fs.promises.mkdtemp(outDirPrefix); +} + +/** + * Replace nasty quotes with simple ones + * @param text text to replace bad characters in + * @returns text with bad characters replaced + */ +export function replaceBadCharacters(text: string): string { + let result = text; + for (const [from, to] of replacements) { + result = result.replace(from, to); + } + return result; +} + +/** + * Create exec options for an extractor + * @param type extractor type + * @param options options + * @returns exec options + */ +export function createExecOptions( + type: 'doc' | 'images' | 'rtf', + options: Options, +): ExecOptions { + let execOptions: ExecOptions = {}; + if (options[type]?.exec) { + return options[type].exec; + } else if (options.exec) { + execOptions = options.exec; + } + return execOptions; +} + +/** + * 1) builds an exec command using provided `genCommand` callback + * 2) runs that command against an input file path + * resulting in an output file + * 3) reads that output file in + * 4) cleans the output file up + * 5) executes a callback with the contents of the file + * @param label Name for the extractor, e.g. `Tesseract` + * @param filePath path to file to be extractor + * @param options extractor options as provided via user configuration + * @param execOptions execution options passed to `exec` commmand as provided via user configuration + * @param genCommand function used to generate the command to be executed + * @returns text from the file + */ +export async function runExecIntoFile( + label: string, + filePath: string, + options: Options, + execOptions: ExecOptions, + genCommand: ( + escapedFilePath: string, + escapedFileTempOutPath: string, + options: Options, + ) => string, +) { + const outDir = await makeTemporaryDirectory(); + + // escape the file paths + const fileTempOutPath = path.join( + outDir, + path.basename(filePath, path.extname(filePath)), + ); + const outFilePath = `${fileTempOutPath}.txt`; + const escapedFilePath = filePath.replace(/\s/g, '\\ '); + const escapedFileTempOutPath = fileTempOutPath.replace(/\s/g, '\\ '); + const cmd = genCommand(escapedFilePath, escapedFileTempOutPath, options); + + await new Promise((resolve, reject) => { + exec(cmd, execOptions, (error /* , stdout, stderr */) => { + if (error) { + reject( + new Error( + `Error extracting [[ ${path.basename(filePath)} ]], exec error: ${ + error.message + }`, + ), + ); + return; + } + resolve(); + }); + }); + + try { + // check if the output file exists + await fs.promises.access(`${fileTempOutPath}.txt`); + } catch (_error) { + throw new Error( + `Error reading ${label} output at [[ ${ + fileTempOutPath + } ]], file does not exist`, + ); + } + + let text: string; + try { + text = await fs.promises.readFile(outFilePath, 'utf8'); + } catch (error) { + throw new Error( + `Error reading${label} output at [[ ${ + fileTempOutPath + } ]], error: ${(error as Error).message}`, + ); + } + + try { + await fs.promises.unlink(outFilePath); + } catch (error) { + throw new Error( + `Error, ${label}, cleaning up temp file [[ ${ + fileTempOutPath + } ]], error: ${(error as Error).message}`, + ); + } + + return text; +} + +/** + * Generate a random seed for the temporary file name + * @returns random seed + */ +function genRandom() { + return Math.floor(Math.random() * 100000000000 + 1).toString(); +} + +const tmpDir = os.tmpdir(); + +/** + * Get the buffer from the input + * @param input input + * @returns buffer + */ +export async function getBufferInput(input: Input): Promise { + if ('buffer' in input) { + return input.buffer; + } + if ('filePath' in input) { + const buffer = await fs.promises.readFile(input.filePath); + return buffer; + } + throw new Error('Invalid input'); +} + +/** + * Get the file path from the input + * @param input input + * @returns file path + */ +export async function getFilePathInput( + input: Input, +): Promise<{ filePath: string; cleanup: () => Promise }> { + if ('filePath' in input) { + return { filePath: input.filePath, cleanup: async () => {} }; + } + if ('buffer' in input) { + const filePath = path.join(tmpDir, `textract_file_${genRandom()}`); + await fs.promises.writeFile(filePath, input.buffer); + return { + filePath, + cleanup: async () => { + await fs.promises.unlink(filePath); + }, + }; + } + throw new Error('Invalid input'); +} diff --git a/package.json b/package.json index ea47586..5ad6ba1 100644 --- a/package.json +++ b/package.json @@ -1,91 +1,64 @@ { "name": "@speechifyinc/textract", - "version": "2.5.3", + "version": "3.0.0-alpha.1", + "type": "module", "publishConfig": { "access": "restricted", "registry": "https://npm.pkg.github.com" }, - "homepage": "https://github.com/dbashford/textract", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "scripts": { + "test": "vitest", + "lint": "eslint \"{lib,bin,scripts,test}/**/*.{js,ts}\"", + "lint:fix": "eslint --fix \"{lib,bin,scripts,test}/**/*.{js,ts}\"", + "typecheck": "tsc --noEmit", + "format": "prettier --write \"{lib,bin,scripts,test}/**/*.{js,ts}\"", + "build": "rimraf dist && tsc -p tsconfig.build.json", + "prepublishOnly": "pnpm typecheck && pnpm lint && pnpm build" + }, "author": "David Bashford", "description": "Extracting text from files of various type including html, pdf, doc, docx, xls, xlsx, csv, pptx, png, jpg, gif, rtf, text/*, and various open office.", "contributors": [ { "name": "David Bashford", "email": "dbashford@hotmail.com" + }, + { + "name": "Eugene Mirotin", + "email": "eugene.mirotin@speechify.com" } ], - "repository": { - "type": "git", - "url": "https://github.com/dbashford/textract" - }, - "keywords": [ - "textract", - "extract", - "html", - "csv", - "text", - "pdf", - "docx", - "doc", - "xls", - "xlsx", - "png", - "jpg", - "gif", - "rtf", - "dxf", - "pptx", - "html", - "markdown", - "xml", - "odt", - "ott", - "xlsb", - "xlsm", - "xltx", - "ods", - "ots", - "potx", - "odg", - "otg", - "epub" - ], "dependencies": { - "mime": "2.2.0", - "pdf-text-extract": "1.3.1", - "xpath": "0.0.23", - "xmldom": "0.1.27", - "j": "0.4.3", - "cheerio": "1.0.0-rc.2", - "marked": "0.6.2", - "meow": "3.7.0", - "got": "5.7.1", - "html-entities": "1.2.0", - "iconv-lite": "0.4.15", - "jschardet": "1.4.1", - "yauzl": "2.7.0", - "epub2": "1.3.4" + "cheerio": "^1.1.2", + "epub2": "^3.0.2", + "fast-xml-parser": "^5.3.1", + "html-entities": "^2.6.0", + "iconv-lite": "^0.7.0", + "jschardet": "^3.1.4", + "jszip": "^3.10.1", + "mammoth": "^1.11.0", + "marked": "^16.4.1", + "mime": "^4.1.0", + "xlsx": "^0.18.5" }, "devDependencies": { - "chai": "1.5.0", - "eslint": "2.11.1", - "eslint-config-airbnb": "^9.0.1", - "eslint-plugin-react": "^5.1.1", - "eslint-plugin-jsx-a11y": "^1.2.0", - "eslint-plugin-import": "^1.7.0 ", - "mocha": "1.9.0" - }, - "scripts": { - "test": "node_modules/.bin/mocha", - "lint": "node_modules/.bin/eslint -c .eslintrc.json lib" + "@speechifyinc/platform-code-conformity-kit": "^3.0.0", + "@types/node": "^22.19.0", + "domhandler": "^5.0.3", + "eslint": "^9.39.1", + "prettier": "^3.6.2", + "rimraf": "^6.1.0", + "typescript": "^5.9.3", + "vitest": "^4.0.7" }, "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">=22" }, - "bin": { - "textract": "./bin/textract" + "volta": { + "node": "22.14.0", + "pnpm": "10.20.0" }, - "main": "./lib/index", - "types": "./lib/index.d.ts" + "packageManager": "pnpm@10.20.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..83bb9f0 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,6364 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + cheerio: + specifier: ^1.1.2 + version: 1.1.2 + epub2: + specifier: ^3.0.2 + version: 3.0.2(ts-toolbelt@9.6.0) + fast-xml-parser: + specifier: ^5.3.1 + version: 5.3.1 + html-entities: + specifier: ^2.6.0 + version: 2.6.0 + iconv-lite: + specifier: ^0.7.0 + version: 0.7.0 + jschardet: + specifier: ^3.1.4 + version: 3.1.4 + jszip: + specifier: ^3.10.1 + version: 3.10.1 + mammoth: + specifier: ^1.11.0 + version: 1.11.0 + marked: + specifier: ^16.4.1 + version: 16.4.1 + mime: + specifier: ^4.1.0 + version: 4.1.0 + xlsx: + specifier: ^0.18.5 + version: 0.18.5 + devDependencies: + '@speechifyinc/platform-code-conformity-kit': + specifier: ^3.0.0 + version: 3.0.0(@typescript-eslint/eslint-plugin@8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3))(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3))(class-validator@0.14.2)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1))(eslint@9.39.1)(next@15.5.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(prettier@3.6.2)(typescript@5.9.3) + '@types/node': + specifier: ^22.19.0 + version: 22.19.0 + domhandler: + specifier: ^5.0.3 + version: 5.0.3 + eslint: + specifier: ^9.39.1 + version: 9.39.1 + prettier: + specifier: ^3.6.2 + version: 3.6.2 + rimraf: + specifier: ^6.1.0 + version: 6.1.0 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vitest: + specifier: ^4.0.7 + version: 4.0.7(@types/debug@4.1.12)(@types/node@22.19.0) + +packages: + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@darraghor/eslint-plugin-nestjs-typed@6.9.3': + resolution: {integrity: sha512-toWGGvAFJjq5NlQDzeu0Mby5GoNLxXmEzDvv/AqN5svPQQVc1NeC4PN2W+q9dgERui5yrWMnAg2VwKlAbNWanw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + '@typescript-eslint/parser': ^7.0.0 || ^8.0.0 + class-validator: '*' + eslint: '>=9.18.0' + + '@emnapi/core@1.7.0': + resolution: {integrity: sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw==} + + '@emnapi/runtime@1.7.0': + resolution: {integrity: sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@es-joy/jsdoccomment@0.50.2': + resolution: {integrity: sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==} + engines: {node: '>=18'} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-plugin-eslint-comments@4.5.0': + resolution: {integrity: sha512-MAhuTKlr4y/CE3WYX26raZjy+I/kS2PLKSzvfmDCGrBLTFHOYwqROZdr4XwPgXwX3K9rjzMr4pSmUWGnzsUyMg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.14.0': + resolution: {integrity: sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.15.2': + resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.1': + resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/markdown@6.6.0': + resolution: {integrity: sha512-IsWPy2jU3gaQDlioDC4sT4I4kG1hX1OMWs/q2sWwJrPoMASHW/Z4SDw+6Aql6EsHejGbagYuJbFq9Zvx+Y1b1Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.3.5': + resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.4': + resolution: {integrity: sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.4': + resolution: {integrity: sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.3': + resolution: {integrity: sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.3': + resolution: {integrity: sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.3': + resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.3': + resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.3': + resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.3': + resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.3': + resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.3': + resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.3': + resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.4': + resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.4': + resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.4': + resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.4': + resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.4': + resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.4': + resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.4': + resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.4': + resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.4': + resolution: {integrity: sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.4': + resolution: {integrity: sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.4': + resolution: {integrity: sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@next/env@15.5.6': + resolution: {integrity: sha512-3qBGRW+sCGzgbpc5TS1a0p7eNxnOarGVQhZxfvTdnV0gFI61lX7QNtQ4V1TSREctXzYn5NetbUsLvyqwLFJM6Q==} + + '@next/eslint-plugin-next@15.5.6': + resolution: {integrity: sha512-YxDvsT2fwy1j5gMqk3ppXlsgDopHnkM4BoxSVASbvvgh5zgsK8lvWerDzPip8k3WVzsTZ1O7A7si1KNfN4OZfQ==} + + '@next/swc-darwin-arm64@15.5.6': + resolution: {integrity: sha512-ES3nRz7N+L5Umz4KoGfZ4XX6gwHplwPhioVRc25+QNsDa7RtUF/z8wJcbuQ2Tffm5RZwuN2A063eapoJ1u4nPg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@15.5.6': + resolution: {integrity: sha512-JIGcytAyk9LQp2/nuVZPAtj8uaJ/zZhsKOASTjxDug0SPU9LAM3wy6nPU735M1OqacR4U20LHVF5v5Wnl9ptTA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@15.5.6': + resolution: {integrity: sha512-qvz4SVKQ0P3/Im9zcS2RmfFL/UCQnsJKJwQSkissbngnB/12c6bZTCB0gHTexz1s6d/mD0+egPKXAIRFVS7hQg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@15.5.6': + resolution: {integrity: sha512-FsbGVw3SJz1hZlvnWD+T6GFgV9/NYDeLTNQB2MXoPN5u9VA9OEDy6fJEfePfsUKAhJufFbZLgp0cPxMuV6SV0w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@15.5.6': + resolution: {integrity: sha512-3QnHGFWlnvAgyxFxt2Ny8PTpXtQD7kVEeaFat5oPAHHI192WKYB+VIKZijtHLGdBBvc16tiAkPTDmQNOQ0dyrA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@15.5.6': + resolution: {integrity: sha512-OsGX148sL+TqMK9YFaPFPoIaJKbFJJxFzkXZljIgA9hjMjdruKht6xDCEv1HLtlLNfkx3c5w2GLKhj7veBQizQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@15.5.6': + resolution: {integrity: sha512-ONOMrqWxdzXDJNh2n60H6gGyKed42Ieu6UTVPZteXpuKbLZTH4G4eBMsr5qWgOBA+s7F+uB4OJbZnrkEDnZ5Fg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@15.5.6': + resolution: {integrity: sha512-pxK4VIjFRx1MY92UycLOOw7dTdvccWsNETQ0kDHkBlcFH1GrTLUjSiHU1ohrznnux6TqRHgv5oflhfIWZwVROQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@rollup/rollup-android-arm-eabi@4.52.5': + resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.52.5': + resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.52.5': + resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.52.5': + resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.52.5': + resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.52.5': + resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.52.5': + resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.52.5': + resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.52.5': + resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.52.5': + resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.52.5': + resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.52.5': + resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.52.5': + resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.52.5': + resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.52.5': + resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.52.5': + resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.52.5': + resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==} + cpu: [x64] + os: [win32] + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@rushstack/eslint-patch@1.14.1': + resolution: {integrity: sha512-jGTk8UD/RdjsNZW8qq10r0RBvxL8OWtoT+kImlzPDFilmozzM+9QmIJsmze9UiSBrFU45ZxhTYBypn9q9z/VfQ==} + + '@speechifyinc/platform-code-conformity-kit@3.0.0': + resolution: {integrity: sha512-QJ2sfXgt4AZsmFyVRiN34+mPTRhKepZH7u6zA3DtgYrmybWAT3s2rrhRlUM9SOmjw2QPp67jDT8kPmsvtQIf9w==, tarball: https://npm.pkg.github.com/download/@speechifyinc/platform-code-conformity-kit/3.0.0/16a271b9c68c492c79952f042fdf2b09f0af60bf} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + eslint: ^9.0.0 + next: ^15.0.0 + prettier: ^3.4.0 + typescript: ^5.0.0 + peerDependenciesMeta: + next: + optional: true + typescript: + optional: true + + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@storybook/csf@0.1.13': + resolution: {integrity: sha512-7xOOwCLGB3ebM87eemep89MYRFTko+D8qE7EdAAq74lgdqRR5cOUtYWJLjO2dLtP94nqoOdHJo6MdLLKzg412Q==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@22.19.0': + resolution: {integrity: sha512-xpr/lmLPQEj+TUnHmR+Ab91/glhJvsqcjB+yY0Ix9GO70H6Lb4FHH5GeqdOE5btAx7eIMwuHkp4H2MSkLcqWbA==} + + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/validator@13.15.4': + resolution: {integrity: sha512-LSFfpSnJJY9wbC0LQxgvfb+ynbHftFo0tMsFOl/J4wexLnYMmDSPaj2ZyDv3TkfL1UePxPrxOWJfbiRS8mQv7A==} + + '@typescript-eslint/eslint-plugin@8.46.3': + resolution: {integrity: sha512-sbaQ27XBUopBkRiuY/P9sWGOWUW4rl8fDoHIUmLpZd8uldsTyB4/Zg6bWTegPoTLnKj9Hqgn3QD6cjPNB32Odw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.46.3 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.46.3': + resolution: {integrity: sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.46.3': + resolution: {integrity: sha512-Fz8yFXsp2wDFeUElO88S9n4w1I4CWDTXDqDr9gYvZgUpwXQqmZBr9+NTTql5R3J7+hrJZPdpiWaB9VNhAKYLuQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.46.3': + resolution: {integrity: sha512-FCi7Y1zgrmxp3DfWfr+3m9ansUUFoy8dkEdeQSgA9gbm8DaHYvZCdkFRQrtKiedFf3Ha6VmoqoAaP68+i+22kg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.46.3': + resolution: {integrity: sha512-GLupljMniHNIROP0zE7nCcybptolcH8QZfXOpCfhQDAdwJ/ZTlcaBOYebSOZotpti/3HrHSw7D3PZm75gYFsOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.46.3': + resolution: {integrity: sha512-ZPCADbr+qfz3aiTTYNNkCbUt+cjNwI/5McyANNrFBpVxPt7GqpEYz5ZfdwuFyGUnJ9FdDXbGODUu6iRCI6XRXw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.46.3': + resolution: {integrity: sha512-G7Ok9WN/ggW7e/tOf8TQYMaxgID3Iujn231hfi0Pc7ZheztIJVpO44ekY00b7akqc6nZcvregk0Jpah3kep6hA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.46.3': + resolution: {integrity: sha512-f/NvtRjOm80BtNM5OQtlaBdM5BRFUv7gf381j9wygDNL+qOYSNOgtQ/DCndiYi80iIOv76QqaTmp4fa9hwI0OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.46.3': + resolution: {integrity: sha512-VXw7qmdkucEx9WkmR3ld/u6VhRyKeiF1uxWwCy/iuNfokjJ7VhsgLSOTjsol8BunSw190zABzpwdNsze2Kpo4g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.46.3': + resolution: {integrity: sha512-uk574k8IU0rOF/AjniX8qbLSGURJVUCeM5e4MIMKBFFi8weeiLrG1fyQejyLXQpRZbU/1BuQasleV/RfHC3hHg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + '@vitest/expect@4.0.7': + resolution: {integrity: sha512-jGRG6HghnJDjljdjYIoVzX17S6uCVCBRFnsgdLGJ6CaxfPh8kzUKe/2n533y4O/aeZ/sIr7q7GbuEbeGDsWv4Q==} + + '@vitest/mocker@4.0.7': + resolution: {integrity: sha512-OsDwLS7WnpuNslOV6bJkXVYVV/6RSc4eeVxV7h9wxQPNxnjRvTTrIikfwCbMyl8XJmW6oOccBj2Q07YwZtQcCw==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.0.7': + resolution: {integrity: sha512-YY//yxqTmk29+/pK+Wi1UB4DUH3lSVgIm+M10rAJ74pOSMgT7rydMSc+vFuq9LjZLhFvVEXir8EcqMke3SVM6Q==} + + '@vitest/runner@4.0.7': + resolution: {integrity: sha512-orU1lsu4PxLEcDWfjVCNGIedOSF/YtZ+XMrd1PZb90E68khWCNzD8y1dtxtgd0hyBIQk8XggteKN/38VQLvzuw==} + + '@vitest/snapshot@4.0.7': + resolution: {integrity: sha512-xJL+Nkw0OjaUXXQf13B8iKK5pI9QVtN9uOtzNHYuG/o/B7fIEg0DQ+xOe0/RcqwDEI15rud1k7y5xznBKGUXAA==} + + '@vitest/spy@4.0.7': + resolution: {integrity: sha512-FW4X8hzIEn4z+HublB4hBF/FhCVaXfIHm8sUfvlznrcy1MQG7VooBgZPMtVCGZtHi0yl3KESaXTqsKh16d8cFg==} + + '@vitest/utils@4.0.7': + resolution: {integrity: sha512-HNrg9CM/Z4ZWB6RuExhuC6FPmLipiShKVMnT9JlQvfhwR47JatWLChA6mtZqVHqypE6p/z6ofcjbyWpM7YLxPQ==} + + '@xmldom/xmldom@0.8.11': + resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} + engines: {node: '>=10.0.0'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + adler-32@1.3.1: + resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} + engines: {node: '>=0.8'} + + adm-zip@0.5.16: + resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} + engines: {node: '>=12.0'} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + are-docs-informative@0.0.2: + resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} + engines: {node: '>=14'} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-hyper-unique@2.1.6: + resolution: {integrity: sha512-BdlHRqjKSYs88WFaVNVEc6Kv8ln/FdzCKPbcDPuWs4/EXkQFhnjc8TyR7hnPxRjcjo5LKOhUMGUWpAqRgeJvpA==} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.11.0: + resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} + engines: {node: '>=4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.8.25: + resolution: {integrity: sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA==} + hasBin: true + + bluebird@3.4.7: + resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.27.0: + resolution: {integrity: sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001753: + resolution: {integrity: sha512-Bj5H35MD/ebaOV4iDLqPEtiliTN29qkGtEHCwawWn4cYm+bPJM2NsaP30vtZcnERClMzp52J4+aw2UNbK4o+zw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + cfb@1.2.2: + resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==} + engines: {node: '>=0.8'} + + chai@6.2.0: + resolution: {integrity: sha512-aUTnJc/JipRzJrNADXVvpVqi6CO0dn3nx4EVPxijri+fj3LUUDyZQOgVeW54Ob3Y1Xh9Iz8f+CgaCl8v0mn9bA==} + engines: {node: '>=18'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.1.2: + resolution: {integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==} + engines: {node: '>=20.18.1'} + + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} + + class-validator@0.14.2: + resolution: {integrity: sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw==} + + clean-regexp@1.0.0: + resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} + engines: {node: '>=4'} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + codepage@1.15.0: + resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} + engines: {node: '>=0.8'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + comment-parser@1.4.1: + resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} + engines: {node: '>= 12.0.0'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + core-js-compat@3.46.0: + resolution: {integrity: sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crlf-normalize@1.0.20: + resolution: {integrity: sha512-h/rBerTd3YHQGfv7tNT25mfhWvRq2BBLCZZ80GFarFxf6HQGbpW6iqDL3N+HBLpjLfAdcBXfWAzVlLfHkRUQBQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + + deep-eql@4.0.0: + resolution: {integrity: sha512-GxJC5MOg2KyQlv6WiUF/VAnMj4MWnYiXo4oLgeptOELVoknyErb4Z8+5F/IM/K4g9/80YzzatxmWcyRwUseH0A==} + engines: {node: '>=6'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dingbat-to-unicode@1.0.1: + resolution: {integrity: sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + duck@0.1.12: + resolution: {integrity: sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + electron-to-chromium@1.5.245: + resolution: {integrity: sha512-rdmGfW47ZhL/oWEJAY4qxRtdly2B98ooTJ0pdEI4jhVLZ6tNf8fPtov2wS1IRKwFJT92le3x4Knxiwzl7cPPpQ==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + epub2@3.0.2: + resolution: {integrity: sha512-rhvpt27CV5MZfRetfNtdNwi3XcNg1Am0TwfveJkK8YWeHItHepQ8Js9J06v8XRIjuTrCW/NSGYMTy55Of7BfNQ==} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + eslint-compat-utils@0.5.1: + resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + + eslint-config-next@15.5.6: + resolution: {integrity: sha512-cGr3VQlPsZBEv8rtYp4BpG1KNXDqGvPo9VC1iaCgIA11OfziC/vczng+TnAS3WpRIR3Q5ye/6yl+CRUuZ1fPGg==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-config-prettier@10.1.8: + resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-import-context@0.1.9: + resolution: {integrity: sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + peerDependencies: + unrs-resolver: ^1.0.0 + peerDependenciesMeta: + unrs-resolver: + optional: true + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-es-x@7.8.0: + resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '>=8' + + eslint-plugin-import-x@4.16.1: + resolution: {integrity: sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/utils': ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 + eslint-import-resolver-node: '*' + peerDependenciesMeta: + '@typescript-eslint/utils': + optional: true + eslint-import-resolver-node: + optional: true + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jest@28.14.0: + resolution: {integrity: sha512-P9s/qXSMTpRTerE2FQ0qJet2gKbcGyFTPAJipoKxmWqR6uuFqIqk8FuEfg5yBieOezVrEfAMZrEwJ6yEp+1MFQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + jest: '*' + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + jest: + optional: true + + eslint-plugin-jsdoc@50.8.0: + resolution: {integrity: sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-n@17.23.1: + resolution: {integrity: sha512-68PealUpYoHOBh332JLLD9Sj7OQUDkFpmcfqt8R9sySfFSeuGJjMTJQvCRRB96zO3A/PELRLkPrzsHmzEFQQ5A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.23.0' + + eslint-plugin-no-relative-import-paths@1.6.1: + resolution: {integrity: sha512-YZNeOnsOrJcwhFw0X29MXjIzu2P/f5X2BZDPWw1R3VUYBRFxNIh77lyoL/XrMU9ewZNQPcEvAgL/cBOT1P330A==} + + eslint-plugin-perfectionist@4.15.1: + resolution: {integrity: sha512-MHF0cBoOG0XyBf7G0EAFCuJJu4I18wy0zAoT1OHfx2o6EOx1EFTIzr2HGeuZa1kDcusoX0xJ9V7oZmaeFd773Q==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + eslint: '>=8.45.0' + + eslint-plugin-prettier@5.5.4: + resolution: {integrity: sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-promise@7.2.1: + resolution: {integrity: sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-plugin-storybook@0.11.2: + resolution: {integrity: sha512-0Z4DUklJrC+GHjCRXa7PYfPzWC15DaVnwaOYenpgXiCEijXPZkLKCms+rHhtoRcWccP7Z8DpOOaP1gc3P9oOwg==} + engines: {node: '>= 18'} + peerDependencies: + eslint: '>=8' + + eslint-plugin-unicorn@56.0.1: + resolution: {integrity: sha512-FwVV0Uwf8XPfVnKSGpMg7NtlZh0G0gBarCaFcMUOoqPxXryxdYxTRRv4kH6B9TFCVIrjRXG+emcxIk2ayZilog==} + engines: {node: '>=18.18'} + peerDependencies: + eslint: '>=8.56.0' + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.39.1: + resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + engines: {node: '>=12.0.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-xml-parser@5.3.1: + resolution: {integrity: sha512-jbNkWiv2Ec1A7wuuxk0br0d0aTMUtQ4IkL+l/i1r9PRf6pLXjDgsBsWwO+UyczmQlnehi4Tbc8/KIvxGQe+I/A==} + hasBin: true + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fault@2.0.1: + resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + format@0.2.2: + resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} + engines: {node: '>=0.4.x'} + + frac@1.1.2: + resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} + engines: {node: '>=0.8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@11.0.3: + resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + engines: {node: 20 || >=22} + hasBin: true + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + + html-entities@2.6.0: + resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} + + htmlparser2@10.0.0: + resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.7.0: + resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} + engines: {node: '>=0.10.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-builtin-module@3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + + jackspeak@4.1.1: + resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + engines: {node: 20 || >=22} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jschardet@3.1.4: + resolution: {integrity: sha512-/kmVISmrwVwtyYU40iQUOp3SUPk2dhNCMsZBQX0R1/jZ8maaXJ/oZIzUOiyOqcgtLnETFKYChbJ5iDC/eWmFHg==} + engines: {node: '>=0.1.90'} + + jsdoc-type-pratt-parser@4.1.0: + resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} + engines: {node: '>=12.0.0'} + + jsesc@0.5.0: + resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + libphonenumber-js@1.12.25: + resolution: {integrity: sha512-u90tUu/SEF8b+RaDKCoW7ZNFDakyBtFlX1ex3J+VH+ElWes/UaitJLt/w4jGu8uAE41lltV/s+kMVtywcMEg7g==} + + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lop@0.4.2: + resolution: {integrity: sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw==} + + lru-cache@11.2.2: + resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} + engines: {node: 20 || >=22} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + mammoth@1.11.0: + resolution: {integrity: sha512-BcEqqY/BOwIcI1iR5tqyVlqc3KIaMRa4egSoK83YAVrBf6+yqdAAbtUcFDCWX8Zef8/fgNZ6rl4VUv+vVX8ddQ==} + engines: {node: '>=12.0.0'} + hasBin: true + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + marked@16.4.1: + resolution: {integrity: sha512-ntROs7RaN3EvWfy3EZi14H4YxmT6A5YvywfhO+0pm+cH/dnSQRmdAmoFIc3B9aiwTehyk7pESH4ofyBY+V5hZg==} + engines: {node: '>= 20'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-frontmatter@2.0.1: + resolution: {integrity: sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-frontmatter@2.0.0: + resolution: {integrity: sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime@4.1.0: + resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} + engines: {node: '>=16'} + hasBin: true + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + minimatch@10.1.1: + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} + engines: {node: 20 || >=22} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + natural-orderby@5.0.0: + resolution: {integrity: sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==} + engines: {node: '>=18'} + + next@15.5.6: + resolution: {integrity: sha512-zTxsnI3LQo3c9HSdSf91O1jMNsEzIXDShXd4wVdg9y5shwLqBXi4ZtUUJyB86KGVSJLZx0PFONvO54aheGX8QQ==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + option@0.2.4: + resolution: {integrity: sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-imports-exports@0.2.4: + resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse-statements@1.0.11: + resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} + + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-dom@19.2.0: + resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} + peerDependencies: + react: ^19.2.0 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + engines: {node: '>=0.10.0'} + + read-pkg-up@7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + + read-pkg@5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp-tree@0.1.27: + resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} + hasBin: true + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + regjsparser@0.10.0: + resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} + hasBin: true + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@6.1.0: + resolution: {integrity: sha512-DxdlA1bdNzkZK7JiNWH+BAx1x4tEJWoTofIopFo6qWUU94jYrFZ0ubY05TqH3nWPJ1nKa1JWVFDINZ3fnrle/A==} + engines: {node: 20 || >=22} + hasBin: true + + rollup@4.52.5: + resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sax@1.4.3: + resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + sharp@0.34.4: + resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + + spdx-license-ids@3.0.22: + resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + ssf@0.11.2: + resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} + engines: {node: '>=0.8'} + + stable-hash-x@0.2.0: + resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} + engines: {node: '>=12.0.0'} + + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strnum@2.1.1: + resolution: {integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + synckit@0.11.11: + resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} + engines: {node: ^14.18.0 || >=16.0.0} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-declaration-location@1.0.7: + resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==} + peerDependencies: + typescript: '>=4.0.0' + + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + + ts-toolbelt@9.6.0: + resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==} + + ts-type@3.0.1: + resolution: {integrity: sha512-cleRydCkBGBFQ4KAvLH0ARIkciduS745prkGVVxPGvcRGhMMoSJUB7gNR1ByKhFTEYrYRg2CsMRGYnqp+6op+g==} + peerDependencies: + ts-toolbelt: ^9.6.0 + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} + engines: {node: '>=4'} + + type-fest@0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + + type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typedarray-dts@1.0.0: + resolution: {integrity: sha512-Ka0DBegjuV9IPYFT1h0Qqk5U4pccebNIJCGl8C5uU7xtOs+jpJvKGAY4fHGK25hTmXZOEUl9Cnsg5cS6K/b5DA==} + + typescript-eslint@8.46.3: + resolution: {integrity: sha512-bAfgMavTuGo+8n6/QQDVQz4tZ4f7Soqg53RbrlZQEoAltYop/XR4RAts/I0BrO3TTClTSTFJ0wYbla+P8cEWJA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + underscore@1.13.7: + resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + undici@7.16.0: + resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} + engines: {node: '>=20.18.1'} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + update-browserslist-db@1.1.4: + resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + validator@13.15.20: + resolution: {integrity: sha512-KxPOq3V2LmfQPP4eqf3Mq/zrT0Dqp2Vmx2Bn285LwVahLc+CsxOM0crBHczm8ijlcjZ0Q5Xd6LW3z3odTPnlrw==} + engines: {node: '>= 0.10'} + + vite@7.2.0: + resolution: {integrity: sha512-C/Naxf8H0pBx1PA4BdpT+c/5wdqI9ILMdwjSMILw7tVIh3JsxzZqdeTLmmdaoh5MYUEOyBnM9K3o0DzoZ/fe+w==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.0.7: + resolution: {integrity: sha512-xQroKAadK503CrmbzCISvQUjeuvEZzv6U0wlnlVFOi5i3gnzfH4onyQ29f3lzpe0FresAiTAd3aqK0Bi/jLI8w==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.7 + '@vitest/browser-preview': 4.0.7 + '@vitest/browser-webdriverio': 4.0.7 + '@vitest/ui': 4.0.7 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + wmf@1.0.2: + resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} + engines: {node: '>=0.8'} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + word@0.3.0: + resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==} + engines: {node: '>=0.8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + xlsx@0.18.5: + resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==} + engines: {node: '>=0.8'} + hasBin: true + + xml2js@0.6.2: + resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} + engines: {node: '>=4.0.0'} + + xmlbuilder@10.1.1: + resolution: {integrity: sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==} + engines: {node: '>=4.0'} + + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-validator-identifier@7.28.5': {} + + '@darraghor/eslint-plugin-nestjs-typed@6.9.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(class-validator@0.14.2)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/parser': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.46.3 + '@typescript-eslint/type-utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + class-validator: 0.14.2 + eslint: 9.39.1 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1) + glob: 11.0.3 + reflect-metadata: 0.2.2 + ts-api-utils: 2.1.0(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-node + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + - typescript + + '@emnapi/core@1.7.0': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.7.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@es-joy/jsdoccomment@0.50.2': + dependencies: + '@types/estree': 1.0.8 + '@typescript-eslint/types': 8.46.3 + comment-parser: 1.4.1 + esquery: 1.6.0 + jsdoc-type-pratt-parser: 4.1.0 + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@eslint-community/eslint-plugin-eslint-comments@4.5.0(eslint@9.39.1)': + dependencies: + escape-string-regexp: 4.0.0 + eslint: 9.39.1 + ignore: 5.3.2 + + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)': + dependencies: + eslint: 9.39.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.14.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/core@0.15.2': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.1': {} + + '@eslint/markdown@6.6.0': + dependencies: + '@eslint/core': 0.14.0 + '@eslint/plugin-kit': 0.3.5 + github-slugger: 2.0.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-frontmatter: 2.0.1 + mdast-util-gfm: 3.1.0 + micromark-extension-frontmatter: 2.0.0 + micromark-extension-gfm: 3.0.0 + transitivePeerDependencies: + - supports-color + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.3.5': + dependencies: + '@eslint/core': 0.15.2 + levn: 0.4.1 + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.3 + optional: true + + '@img/sharp-darwin-x64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.3 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.3': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.3': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.3': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.3': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.3': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.3': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.3': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.3': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.3': + optional: true + + '@img/sharp-linux-arm64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.3 + optional: true + + '@img/sharp-linux-arm@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.3 + optional: true + + '@img/sharp-linux-ppc64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.3 + optional: true + + '@img/sharp-linux-s390x@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.3 + optional: true + + '@img/sharp-linux-x64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.3 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.4': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 + optional: true + + '@img/sharp-wasm32@0.34.4': + dependencies: + '@emnapi/runtime': 1.7.0 + optional: true + + '@img/sharp-win32-arm64@0.34.4': + optional: true + + '@img/sharp-win32-ia32@0.34.4': + optional: true + + '@img/sharp-win32-x64@0.34.4': + optional: true + + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.2 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.7.0 + '@emnapi/runtime': 1.7.0 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@next/env@15.5.6': + optional: true + + '@next/eslint-plugin-next@15.5.6': + dependencies: + fast-glob: 3.3.1 + + '@next/swc-darwin-arm64@15.5.6': + optional: true + + '@next/swc-darwin-x64@15.5.6': + optional: true + + '@next/swc-linux-arm64-gnu@15.5.6': + optional: true + + '@next/swc-linux-arm64-musl@15.5.6': + optional: true + + '@next/swc-linux-x64-gnu@15.5.6': + optional: true + + '@next/swc-linux-x64-musl@15.5.6': + optional: true + + '@next/swc-win32-arm64-msvc@15.5.6': + optional: true + + '@next/swc-win32-x64-msvc@15.5.6': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@nolyfill/is-core-module@1.0.39': {} + + '@pkgr/core@0.2.9': {} + + '@rollup/rollup-android-arm-eabi@4.52.5': + optional: true + + '@rollup/rollup-android-arm64@4.52.5': + optional: true + + '@rollup/rollup-darwin-arm64@4.52.5': + optional: true + + '@rollup/rollup-darwin-x64@4.52.5': + optional: true + + '@rollup/rollup-freebsd-arm64@4.52.5': + optional: true + + '@rollup/rollup-freebsd-x64@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.52.5': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.52.5': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-x64-musl@4.52.5': + optional: true + + '@rollup/rollup-openharmony-arm64@4.52.5': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.52.5': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.52.5': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.52.5': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.52.5': + optional: true + + '@rtsao/scc@1.1.0': {} + + '@rushstack/eslint-patch@1.14.1': {} + + '@speechifyinc/platform-code-conformity-kit@3.0.0(@typescript-eslint/eslint-plugin@8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3))(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3))(class-validator@0.14.2)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1))(eslint@9.39.1)(next@15.5.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(prettier@3.6.2)(typescript@5.9.3)': + dependencies: + '@darraghor/eslint-plugin-nestjs-typed': 6.9.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(class-validator@0.14.2)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1)(typescript@5.9.3) + '@eslint-community/eslint-plugin-eslint-comments': 4.5.0(eslint@9.39.1) + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.39.1 + '@eslint/markdown': 6.6.0 + eslint: 9.39.1 + eslint-config-next: 15.5.6(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1))(eslint@9.39.1)(typescript@5.9.3) + eslint-config-prettier: 10.1.8(eslint@9.39.1) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1))(eslint@9.39.1) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1) + eslint-plugin-jest: 28.14.0(@typescript-eslint/eslint-plugin@8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) + eslint-plugin-jsdoc: 50.8.0(eslint@9.39.1) + eslint-plugin-n: 17.23.1(eslint@9.39.1)(typescript@5.9.3) + eslint-plugin-no-relative-import-paths: 1.6.1 + eslint-plugin-perfectionist: 4.15.1(eslint@9.39.1)(typescript@5.9.3) + eslint-plugin-prettier: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.6.2) + eslint-plugin-promise: 7.2.1(eslint@9.39.1) + eslint-plugin-storybook: 0.11.2(eslint@9.39.1)(typescript@5.9.3) + eslint-plugin-unicorn: 56.0.1(eslint@9.39.1) + prettier: 3.6.2 + typescript-eslint: 8.46.3(eslint@9.39.1)(typescript@5.9.3) + optionalDependencies: + next: 15.5.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/eslint' + - '@typescript-eslint/eslint-plugin' + - '@typescript-eslint/parser' + - '@typescript-eslint/utils' + - class-validator + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - eslint-plugin-import + - jest + - supports-color + + '@standard-schema/spec@1.0.0': {} + + '@storybook/csf@0.1.13': + dependencies: + type-fest: 2.19.0 + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + optional: true + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@22.19.0': + dependencies: + undici-types: 6.21.0 + + '@types/normalize-package-data@2.4.4': {} + + '@types/unist@3.0.3': {} + + '@types/validator@13.15.4': {} + + '@typescript-eslint/eslint-plugin@8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.46.3 + '@typescript-eslint/type-utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.3 + eslint: 9.39.1 + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.46.3 + '@typescript-eslint/types': 8.46.3 + '@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.3 + debug: 4.4.3 + eslint: 9.39.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.46.3(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.3(typescript@5.9.3) + '@typescript-eslint/types': 8.46.3 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.46.3': + dependencies: + '@typescript-eslint/types': 8.46.3 + '@typescript-eslint/visitor-keys': 8.46.3 + + '@typescript-eslint/tsconfig-utils@8.46.3(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.46.3(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.46.3 + '@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.1 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.46.3': {} + + '@typescript-eslint/typescript-estree@8.46.3(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.46.3(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.46.3(typescript@5.9.3) + '@typescript-eslint/types': 8.46.3 + '@typescript-eslint/visitor-keys': 8.46.3 + debug: 4.4.3 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@typescript-eslint/scope-manager': 8.46.3 + '@typescript-eslint/types': 8.46.3 + '@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3) + eslint: 9.39.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.46.3': + dependencies: + '@typescript-eslint/types': 8.46.3 + eslint-visitor-keys: 4.2.1 + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + '@vitest/expect@4.0.7': + dependencies: + '@standard-schema/spec': 1.0.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.7 + '@vitest/utils': 4.0.7 + chai: 6.2.0 + tinyrainbow: 3.0.3 + + '@vitest/mocker@4.0.7(vite@7.2.0(@types/node@22.19.0))': + dependencies: + '@vitest/spy': 4.0.7 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.2.0(@types/node@22.19.0) + + '@vitest/pretty-format@4.0.7': + dependencies: + tinyrainbow: 3.0.3 + + '@vitest/runner@4.0.7': + dependencies: + '@vitest/utils': 4.0.7 + pathe: 2.0.3 + + '@vitest/snapshot@4.0.7': + dependencies: + '@vitest/pretty-format': 4.0.7 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.0.7': {} + + '@vitest/utils@4.0.7': + dependencies: + '@vitest/pretty-format': 4.0.7 + tinyrainbow: 3.0.3 + + '@xmldom/xmldom@0.8.11': {} + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + adler-32@1.3.1: {} + + adm-zip@0.5.16: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + are-docs-informative@0.0.2: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-hyper-unique@2.1.6: + dependencies: + deep-eql: 4.0.0 + lodash: 4.17.21 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + assertion-error@2.0.1: {} + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.11.0: {} + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.8.25: {} + + bluebird@3.4.7: {} + + bluebird@3.7.2: {} + + boolbase@1.0.0: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.27.0: + dependencies: + baseline-browser-mapping: 2.8.25 + caniuse-lite: 1.0.30001753 + electron-to-chromium: 1.5.245 + node-releases: 2.0.27 + update-browserslist-db: 1.1.4(browserslist@4.27.0) + + builtin-modules@3.3.0: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001753: {} + + ccount@2.0.1: {} + + cfb@1.2.2: + dependencies: + adler-32: 1.3.1 + crc-32: 1.2.2 + + chai@6.2.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + character-entities@2.0.2: {} + + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.2.2 + css-what: 6.2.2 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.1.2: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.1 + htmlparser2: 10.0.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 7.16.0 + whatwg-mimetype: 4.0.0 + + ci-info@4.3.1: {} + + class-validator@0.14.2: + dependencies: + '@types/validator': 13.15.4 + libphonenumber-js: 1.12.25 + validator: 13.15.20 + + clean-regexp@1.0.0: + dependencies: + escape-string-regexp: 1.0.5 + + client-only@0.0.1: + optional: true + + codepage@1.15.0: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + comment-parser@1.4.1: {} + + concat-map@0.0.1: {} + + core-js-compat@3.46.0: + dependencies: + browserslist: 4.27.0 + + core-util-is@1.0.3: {} + + crc-32@1.2.2: {} + + crlf-normalize@1.0.20(ts-toolbelt@9.6.0): + dependencies: + ts-type: 3.0.1(ts-toolbelt@9.6.0) + transitivePeerDependencies: + - ts-toolbelt + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-what@6.2.2: {} + + damerau-levenshtein@1.0.8: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.2.0: + dependencies: + character-entities: 2.0.2 + + deep-eql@4.0.0: + dependencies: + type-detect: 4.1.0 + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + dequal@2.0.3: {} + + detect-libc@2.1.2: + optional: true + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dingbat-to-unicode@1.0.1: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + duck@0.1.12: + dependencies: + underscore: 1.13.7 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.5.245: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encoding-sniffer@0.2.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + entities@4.5.0: {} + + entities@6.0.1: {} + + epub2@3.0.2(ts-toolbelt@9.6.0): + dependencies: + adm-zip: 0.5.16 + array-hyper-unique: 2.1.6 + bluebird: 3.7.2 + crlf-normalize: 1.0.20(ts-toolbelt@9.6.0) + tslib: 2.8.1 + xml2js: 0.6.2 + transitivePeerDependencies: + - ts-toolbelt + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.24.0: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + escalade@3.2.0: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + eslint-compat-utils@0.5.1(eslint@9.39.1): + dependencies: + eslint: 9.39.1 + semver: 7.7.3 + + eslint-config-next@15.5.6(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1))(eslint@9.39.1)(typescript@5.9.3): + dependencies: + '@next/eslint-plugin-next': 15.5.6 + '@rushstack/eslint-patch': 1.14.1 + '@typescript-eslint/eslint-plugin': 8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1))(eslint@9.39.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.1) + eslint-plugin-react: 7.37.5(eslint@9.39.1) + eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-config-prettier@10.1.8(eslint@9.39.1): + dependencies: + eslint: 9.39.1 + + eslint-import-context@0.1.9(unrs-resolver@1.11.1): + dependencies: + get-tsconfig: 4.13.0 + stable-hash-x: 0.2.0 + optionalDependencies: + unrs-resolver: 1.11.1 + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1))(eslint@9.39.1): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + eslint: 9.39.1 + get-tsconfig: 4.13.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.15 + unrs-resolver: 1.11.1 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1))(eslint@9.39.1) + transitivePeerDependencies: + - supports-color + + eslint-plugin-es-x@7.8.0(eslint@9.39.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@eslint-community/regexpp': 4.12.2 + eslint: 9.39.1 + eslint-compat-utils: 0.5.1(eslint@9.39.1) + + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1): + dependencies: + '@typescript-eslint/types': 8.46.3 + comment-parser: 1.4.1 + debug: 4.4.3 + eslint: 9.39.1 + eslint-import-context: 0.1.9(unrs-resolver@1.11.1) + is-glob: 4.0.3 + minimatch: 10.1.1 + semver: 7.7.3 + stable-hash-x: 0.2.0 + unrs-resolver: 1.11.1 + optionalDependencies: + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jest@28.14.0(@typescript-eslint/eslint-plugin@8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3): + dependencies: + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + eslint: 9.39.1 + optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + - typescript + + eslint-plugin-jsdoc@50.8.0(eslint@9.39.1): + dependencies: + '@es-joy/jsdoccomment': 0.50.2 + are-docs-informative: 0.0.2 + comment-parser: 1.4.1 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint: 9.39.1 + espree: 10.4.0 + esquery: 1.6.0 + parse-imports-exports: 0.2.4 + semver: 7.7.3 + spdx-expression-parse: 4.0.0 + transitivePeerDependencies: + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.1): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.11.0 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.39.1 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-n@17.23.1(eslint@9.39.1)(typescript@5.9.3): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + enhanced-resolve: 5.18.3 + eslint: 9.39.1 + eslint-plugin-es-x: 7.8.0(eslint@9.39.1) + get-tsconfig: 4.13.0 + globals: 15.15.0 + globrex: 0.1.2 + ignore: 5.3.2 + semver: 7.7.3 + ts-declaration-location: 1.0.7(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + eslint-plugin-no-relative-import-paths@1.6.1: {} + + eslint-plugin-perfectionist@4.15.1(eslint@9.39.1)(typescript@5.9.3): + dependencies: + '@typescript-eslint/types': 8.46.3 + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + eslint: 9.39.1 + natural-orderby: 5.0.0 + transitivePeerDependencies: + - supports-color + - typescript + + eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.6.2): + dependencies: + eslint: 9.39.1 + prettier: 3.6.2 + prettier-linter-helpers: 1.0.0 + synckit: 0.11.11 + optionalDependencies: + eslint-config-prettier: 10.1.8(eslint@9.39.1) + + eslint-plugin-promise@7.2.1(eslint@9.39.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + eslint: 9.39.1 + + eslint-plugin-react-hooks@5.2.0(eslint@9.39.1): + dependencies: + eslint: 9.39.1 + + eslint-plugin-react@7.37.5(eslint@9.39.1): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 9.39.1 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-plugin-storybook@0.11.2(eslint@9.39.1)(typescript@5.9.3): + dependencies: + '@storybook/csf': 0.1.13 + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + eslint: 9.39.1 + ts-dedent: 2.2.0 + transitivePeerDependencies: + - supports-color + - typescript + + eslint-plugin-unicorn@56.0.1(eslint@9.39.1): + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + ci-info: 4.3.1 + clean-regexp: 1.0.0 + core-js-compat: 3.46.0 + eslint: 9.39.1 + esquery: 1.6.0 + globals: 15.15.0 + indent-string: 4.0.0 + is-builtin-module: 3.2.1 + jsesc: 3.1.0 + pluralize: 8.0.0 + read-pkg-up: 7.0.1 + regexp-tree: 0.1.27 + regjsparser: 0.10.0 + semver: 7.7.3 + strip-indent: 3.0.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.1: + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.39.1 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + esutils@2.0.3: {} + + expect-type@1.2.2: {} + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-xml-parser@5.3.1: + dependencies: + strnum: 2.1.1 + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fault@2.0.1: + dependencies: + format: 0.2.2 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + format@0.2.2: {} + + frac@1.1.2: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + github-slugger@2.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@11.0.3: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.1.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + + globals@14.0.0: {} + + globals@15.15.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + globrex@0.1.2: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hosted-git-info@2.8.9: {} + + html-entities@2.6.0: {} + + htmlparser2@10.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 6.0.1 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.7.0: + dependencies: + safer-buffer: 2.1.2 + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + immediate@3.0.6: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + inherits@2.0.4: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-arrayish@0.2.1: {} + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-builtin-module@3.2.1: + dependencies: + builtin-modules: 3.3.0 + + is-bun-module@2.0.0: + dependencies: + semver: 7.7.3 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jackspeak@4.1.1: + dependencies: + '@isaacs/cliui': 8.0.2 + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jschardet@3.1.4: {} + + jsdoc-type-pratt-parser@4.1.0: {} + + jsesc@0.5.0: {} + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + libphonenumber-js@1.12.25: {} + + lie@3.3.0: + dependencies: + immediate: 3.0.6 + + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash@4.17.21: {} + + longest-streak@3.1.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lop@0.4.2: + dependencies: + duck: 0.1.12 + option: 0.2.4 + underscore: 1.13.7 + + lru-cache@11.2.2: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + mammoth@1.11.0: + dependencies: + '@xmldom/xmldom': 0.8.11 + argparse: 1.0.10 + base64-js: 1.5.1 + bluebird: 3.4.7 + dingbat-to-unicode: 1.0.1 + jszip: 3.10.1 + lop: 0.4.2 + path-is-absolute: 1.0.1 + underscore: 1.13.7 + xmlbuilder: 10.1.1 + + markdown-table@3.0.4: {} + + marked@16.4.1: {} + + math-intrinsics@1.1.0: {} + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-frontmatter@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + escape-string-regexp: 5.0.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-extension-frontmatter: 2.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + merge2@1.4.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-frontmatter@2.0.0: + dependencies: + fault: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime@4.1.0: {} + + min-indent@1.0.1: {} + + minimatch@10.1.1: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + minipass@7.1.2: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + natural-orderby@5.0.0: {} + + next@15.5.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@next/env': 15.5.6 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001753 + postcss: 8.4.31 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + styled-jsx: 5.1.6(react@19.2.0) + optionalDependencies: + '@next/swc-darwin-arm64': 15.5.6 + '@next/swc-darwin-x64': 15.5.6 + '@next/swc-linux-arm64-gnu': 15.5.6 + '@next/swc-linux-arm64-musl': 15.5.6 + '@next/swc-linux-x64-gnu': 15.5.6 + '@next/swc-linux-x64-musl': 15.5.6 + '@next/swc-win32-arm64-msvc': 15.5.6 + '@next/swc-win32-x64-msvc': 15.5.6 + sharp: 0.34.4 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + optional: true + + node-releases@2.0.27: {} + + normalize-package-data@2.5.0: + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.11 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + option@0.2.4: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + pako@1.0.11: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-imports-exports@0.2.4: + dependencies: + parse-statements: 1.0.11 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-statements@1.0.11: {} + + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-scurry@2.0.0: + dependencies: + lru-cache: 11.2.2 + minipass: 7.1.2 + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pluralize@8.0.0: {} + + possible-typed-array-names@1.1.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + optional: true + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.6.2: {} + + process-nextick-args@2.0.1: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + react-dom@19.2.0(react@19.2.0): + dependencies: + react: 19.2.0 + scheduler: 0.27.0 + optional: true + + react-is@16.13.1: {} + + react@19.2.0: + optional: true + + read-pkg-up@7.0.1: + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + + read-pkg@5.2.0: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + reflect-metadata@0.2.2: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp-tree@0.1.27: {} + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + regjsparser@0.10.0: + dependencies: + jsesc: 0.5.0 + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.5: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + rimraf@6.1.0: + dependencies: + glob: 11.0.3 + package-json-from-dist: 1.0.1 + + rollup@4.52.5: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.52.5 + '@rollup/rollup-android-arm64': 4.52.5 + '@rollup/rollup-darwin-arm64': 4.52.5 + '@rollup/rollup-darwin-x64': 4.52.5 + '@rollup/rollup-freebsd-arm64': 4.52.5 + '@rollup/rollup-freebsd-x64': 4.52.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 + '@rollup/rollup-linux-arm-musleabihf': 4.52.5 + '@rollup/rollup-linux-arm64-gnu': 4.52.5 + '@rollup/rollup-linux-arm64-musl': 4.52.5 + '@rollup/rollup-linux-loong64-gnu': 4.52.5 + '@rollup/rollup-linux-ppc64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-musl': 4.52.5 + '@rollup/rollup-linux-s390x-gnu': 4.52.5 + '@rollup/rollup-linux-x64-gnu': 4.52.5 + '@rollup/rollup-linux-x64-musl': 4.52.5 + '@rollup/rollup-openharmony-arm64': 4.52.5 + '@rollup/rollup-win32-arm64-msvc': 4.52.5 + '@rollup/rollup-win32-ia32-msvc': 4.52.5 + '@rollup/rollup-win32-x64-gnu': 4.52.5 + '@rollup/rollup-win32-x64-msvc': 4.52.5 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.1.2: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safer-buffer@2.1.2: {} + + sax@1.4.3: {} + + scheduler@0.27.0: + optional: true + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.7.3: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + setimmediate@1.0.5: {} + + sharp@0.34.4: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.4 + '@img/sharp-darwin-x64': 0.34.4 + '@img/sharp-libvips-darwin-arm64': 1.2.3 + '@img/sharp-libvips-darwin-x64': 1.2.3 + '@img/sharp-libvips-linux-arm': 1.2.3 + '@img/sharp-libvips-linux-arm64': 1.2.3 + '@img/sharp-libvips-linux-ppc64': 1.2.3 + '@img/sharp-libvips-linux-s390x': 1.2.3 + '@img/sharp-libvips-linux-x64': 1.2.3 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 + '@img/sharp-linux-arm': 0.34.4 + '@img/sharp-linux-arm64': 0.34.4 + '@img/sharp-linux-ppc64': 0.34.4 + '@img/sharp-linux-s390x': 0.34.4 + '@img/sharp-linux-x64': 0.34.4 + '@img/sharp-linuxmusl-arm64': 0.34.4 + '@img/sharp-linuxmusl-x64': 0.34.4 + '@img/sharp-wasm32': 0.34.4 + '@img/sharp-win32-arm64': 0.34.4 + '@img/sharp-win32-ia32': 0.34.4 + '@img/sharp-win32-x64': 0.34.4 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + siginfo@2.0.0: {} + + signal-exit@4.1.0: {} + + source-map-js@1.2.1: {} + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.22 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.22 + + spdx-expression-parse@4.0.0: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.22 + + spdx-license-ids@3.0.22: {} + + sprintf-js@1.0.3: {} + + ssf@0.11.2: + dependencies: + frac: 1.1.2 + + stable-hash-x@0.2.0: {} + + stable-hash@0.0.5: {} + + stackback@0.0.2: {} + + std-env@3.10.0: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.2 + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + + strip-bom@3.0.0: {} + + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + + strip-json-comments@3.1.1: {} + + strnum@2.1.1: {} + + styled-jsx@5.1.6(react@19.2.0): + dependencies: + client-only: 0.0.1 + react: 19.2.0 + optional: true + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + synckit@0.11.11: + dependencies: + '@pkgr/core': 0.2.9 + + tapable@2.3.0: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinyrainbow@3.0.3: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@2.1.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-declaration-location@1.0.7(typescript@5.9.3): + dependencies: + picomatch: 4.0.3 + typescript: 5.9.3 + + ts-dedent@2.2.0: {} + + ts-toolbelt@9.6.0: {} + + ts-type@3.0.1(ts-toolbelt@9.6.0): + dependencies: + '@types/node': 22.19.0 + ts-toolbelt: 9.6.0 + tslib: 2.8.1 + typedarray-dts: 1.0.0 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-detect@4.1.0: {} + + type-fest@0.6.0: {} + + type-fest@0.8.1: {} + + type-fest@2.19.0: {} + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typedarray-dts@1.0.0: {} + + typescript-eslint@8.46.3(eslint@9.39.1)(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.46.3(@typescript-eslint/parser@8.46.3(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.46.3(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.3(eslint@9.39.1)(typescript@5.9.3) + eslint: 9.39.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + underscore@1.13.7: {} + + undici-types@6.21.0: {} + + undici@7.16.0: {} + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + update-browserslist-db@1.1.4(browserslist@4.27.0): + dependencies: + browserslist: 4.27.0 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + validator@13.15.20: {} + + vite@7.2.0(@types/node@22.19.0): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.52.5 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.19.0 + fsevents: 2.3.3 + + vitest@4.0.7(@types/debug@4.1.12)(@types/node@22.19.0): + dependencies: + '@vitest/expect': 4.0.7 + '@vitest/mocker': 4.0.7(vite@7.2.0(@types/node@22.19.0)) + '@vitest/pretty-format': 4.0.7 + '@vitest/runner': 4.0.7 + '@vitest/snapshot': 4.0.7 + '@vitest/spy': 4.0.7 + '@vitest/utils': 4.0.7 + debug: 4.4.3 + es-module-lexer: 1.7.0 + expect-type: 1.2.2 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.2.0(@types/node@22.19.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/debug': 4.1.12 + '@types/node': 22.19.0 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + wmf@1.0.2: {} + + word-wrap@1.2.5: {} + + word@0.3.0: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.1.2 + + xlsx@0.18.5: + dependencies: + adler-32: 1.3.1 + cfb: 1.2.2 + codepage: 1.15.0 + crc-32: 1.2.2 + ssf: 0.11.2 + wmf: 1.0.2 + word: 0.3.0 + + xml2js@0.6.2: + dependencies: + sax: 1.4.3 + xmlbuilder: 11.0.1 + + xmlbuilder@10.1.1: {} + + xmlbuilder@11.0.1: {} + + yocto-queue@0.1.0: {} + + zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..145dbbc --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,5 @@ +onlyBuiltDependencies: + - es5-ext + - esbuild + - sharp + - unrs-resolver diff --git a/prettier.config.mjs b/prettier.config.mjs new file mode 100644 index 0000000..8d7a8df --- /dev/null +++ b/prettier.config.mjs @@ -0,0 +1,3 @@ +import prettierConfig from '@speechifyinc/platform-code-conformity-kit/prettier/configs/default.js'; + +export default prettierConfig; diff --git a/scripts/images b/scripts/images deleted file mode 100755 index 69df8d5..0000000 --- a/scripts/images +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env node -var exec = require("child_process").exec; -exec('tesseract', - function (error, stdout, stderr) { - if (error && error.toString().indexOf("tesseract") > -1 || stderr && stderr.toString().indexOf("tesseract") > -1) { - console.log("Found tesseract, textract should be able to use it.") - } else { - console.log("tesseract cannot be found/executed by this script, errors to follow.") - console.log("**************ERROR*****************"); - console.log(error); - console.log("**************stderr*****************") - console.log(stderr); - console.log("**************stdout*****************") - console.log(stdout); - } - } -); \ No newline at end of file diff --git a/scripts/pdf b/scripts/pdf deleted file mode 100755 index 31c0328..0000000 --- a/scripts/pdf +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env node -var exec = require("child_process").exec; -exec( "pdftotext -v", - function( error, stdout, stderr ) { - if (stderr && stderr.indexOf("pdftotext version") > -1) { - console.log("Found pdftotext, textract should be able to use it.") - } else { - console.log("pdftotext cannot be found/executed by this script, errors to follow.") - console.log("**************ERROR*****************"); - console.log(error); - console.log("**************stderr*****************") - console.log(stderr); - console.log("**************stdout*****************") - console.log(stdout); - } - } -); \ No newline at end of file diff --git a/test/buffer.test.ts b/test/buffer.test.ts new file mode 100644 index 0000000..8171c50 --- /dev/null +++ b/test/buffer.test.ts @@ -0,0 +1,120 @@ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import mime from 'mime'; +import { describe, it, expect } from 'vitest'; +import { extractFromBuffer } from '../lib/index.js'; + +const isOSX = os.platform() === 'darwin'; + +const TEST_CASES = [ + [ + 'html', + 'test.html', + ' This is a long string of text that should get extracted with new lines inserted', + ], + + [ + 'doc', + 'doc.doc', + isOSX + ? 'Word Specification Sample Working Draft 04, 16 August 2002 Document identifier: wd-spectools-word-sa' + : ' Word Specification Sample Working Draft 04, 16 August 2002 Document identifier: wd-spectools-word-s', + ], + + ['xls', 'test.xls', 'This,is,a,spreadsheet,yay!'], + + ['xlsx', 'pi.xlsx', 'This is the value of PI:,3.141592'], + + ['pdf', 'pdf.pdf', 'This is a test. Please ignore.'], + + [ + 'docx', + 'docx.docx', + 'This is a test Just so you know: Lorem ipsum dolor sit amet, consecutuer adipiscing elit, sed diam n', + ], + + ['text/*', 'txt.txt', 'This is a plain old text file.'], + + [ + 'pptx', + 'ppt.pptx', + 'This is some title Text And a sub-title Text in Lists Bullet 1 Bullet 2 Bullet 3 Number 1 Number 2 N', + ], + + [ + 'markdown', + 'test.md', + ' This is an h1 This is an h2 This text has been bolded and italicized ', + ], + + ['ods', 'ods.ods', 'This,is,a,ods Really,it,is, I,promise,,'], + + [ + 'xml', + 'xml.xml', + ' Empire Burlesque Bob Dylan USA Columbia 10.90 1985 Hide your heart Bonnie Tyler UK CBS Records 9.90', + ], + + ['odt', 'odt.odt', 'This is an ODT THIS IS A HEADING More ODT'], + + [ + 'potx', + 'potx.potx', + 'This is a potx template Yep, a potx I had no idea These were even a thing ', + ], + + [ + 'xltx', + 'xltx.xltx', + ',,,,,, Packing Slip ,Your Company Name,,,,"July 24, 2015", , Your Company Slogan,,,,, ,,,,,, ,Addres', + ], + + [ + 'ott', + 'ott.ott', + 'This is a document template, yay templates! Woo templates get me so excited!', + ], + + [ + 'ots', + 'ots.ots', + "This,is, template, an,open,office,template isn't,it,awesome?, you,know,it,is", + ], + + [ + 'odg', + 'odg.odg', + "This is a drawing? A drawing, a drawing! This is a drawing, Aren't you mad envious?", + ], + + [ + 'otg', + 'otg.otg', + 'This is a drawing template A drawing template. Who would really ever need to extract from one of the', + ], + + [ + 'odp', + 'odp.odp', + "This is a title This is a slide's text This is a 2nd page And a 2nd page's content", + ], + + [ + 'otp', + 'otp.otp', + 'This is a template title Template page text 2nd prezo text', + ], +] as const; + +const DIR = fileURLToPath(path.dirname(import.meta.url)); + +describe('textract fromBufferWithMime', () => { + it.each(TEST_CASES)('will %s files', async (_ext, name, expectedText) => { + const docPath = path.join(DIR, 'files', name); + const textBuff = fs.readFileSync(docPath); + const text = await extractFromBuffer(textBuff, mime.getType(docPath) ?? ''); + expect(text.substring(0, 100)).toEqual(expectedText); + }); +}); diff --git a/test/buffer_test.js b/test/buffer_test.js deleted file mode 100644 index 602b051..0000000 --- a/test/buffer_test.js +++ /dev/null @@ -1,159 +0,0 @@ -var fs = require("fs") - , path = require("path") - , mime = require("mime") - ; - -var test = function(_testFunction, withMime) { - - var testFunction; - - beforeEach(function() { - testFunction = _testFunction(); - }); - - var _test = function(ext, name, _text) { - it('will ' + ext + ' files', function(done) { - var docPath = path.join( __dirname, "files", name); - var textBuff = fs.readFileSync(docPath); - - testFunction( - (withMime) ? mime.getType( docPath ) : docPath, - textBuff, function( error, text ) { - - expect(error).to.be.null; - expect(text).to.be.an('string'); - expect(text.substring(0,100)).to.eql(_text); - done(); - }); - }); - }; - - _test( - "html", - "test.html", - " This is a long string of text that should get extracted with new lines inserted" - ) - - _test( - "doc", - "doc.doc", - " Word Specification Sample Working Draft 04, 16 August 2002 Document identifier: wd-spectools-word-s" - ); - - _test( - "xls", - "test.xls", - "This,is,a,spreadsheet,yay! " - ); - - _test( - "xlsx", - "pi.xlsx", - 'This is the value of PI:,3.141592 ' - ); - - _test( - "pdf", - "pdf.pdf", - "This is a test. Please ignore." - ); - - _test( - "docx", - "docx.docx", - "This is a test Just so you know: Lorem ipsum dolor sit amet, consecutuer adipiscing elit, sed diam n" - ); - - _test( - "text/*", - "txt.txt", - "This is a plain old text file." - ); - - _test( - "pptx", - "ppt.pptx", - "This is some title Text And a sub-title Text in Lists Bullet 1 Bullet 2 Bullet 3 Number 1 Number 2 N" - ); - - _test( - "markdown", - "test.md", - " This is an h1 This is an h2 This text has been bolded and italicized " - ); - - _test( - "ods", - "ods.ods", - "This,is,a,ods Really,it,is, I,promise,, " - ); - - _test( - "xml", - "xml.xml", - " Empire Burlesque Bob Dylan USA Columbia 10.90 1985 Hide your heart Bonnie Tyler UK CBS Records 9.90" - ); - - _test( - "odt", - "odt.odt", - "This is an ODT THIS IS A HEADING More ODT" - ); - - _test( - "potx", - "potx.potx", - "This is a potx template Yep, a potx I had no idea These were even a thing " - ); - - _test( - "xltx", - "xltx.xltx", - ",,,,,, Packing Slip ,Your Company Name,,,,\"July 24, 2015\", , Your Company Slogan,,,,, ,,,,,, ,Addres" - ); - - _test( - "ott", - "ott.ott", - "This is a document template, yay templates! Woo templates get me so excited!" - ); - - _test( - "ots", - "ots.ots", - "This,is , template, an,open,office,template isn't,it,awesome?, you,know,it,is " - ); - - _test( - 'odg', - 'odg.odg', - "This is a drawing? A drawing, a drawing! This is a drawing, Aren't you mad envious?" - ); - - _test( - 'otg', - 'otg.otg', - "This is a drawing template A drawing template. Who would really ever need to extract from one of the" - ); - - _test( - 'odp', - 'odp.odp', - "This is a title This is a slide's text This is a 2nd page And a 2nd page's content" - ); - - _test( - 'otp', - 'otp.otp', - "This is a template title Template page text 2nd prezo text" - ); - -}; - -describe('textract fromBufferWithName', function() { - test(function(){ return global.fromBufferWithName }, false); -}); - -describe('textract fromBufferWithMime', function() { - test(function(){ return global.fromBufferWithMime }, true); -}); diff --git a/test/cli_test.js b/test/cli_test.js deleted file mode 100644 index 7373919..0000000 --- a/test/cli_test.js +++ /dev/null @@ -1,17 +0,0 @@ -var exec = require("child_process").exec - , path = require("path") - , cliPath = path.join(__dirname, "..", "bin", "textract") - , testFilePath = path.join(__dirname, "files", "css.css") - ; - -describe("cli", function(){ - it("will extract text", function(done) { - exec( cliPath + " " + testFilePath, - function( error, stdout, stderr ) { - expect(stdout).to.eql(".foo {color:red}\n"); - done(); - } - ); - }) -}); - diff --git a/test/common.js b/test/common.js deleted file mode 100644 index 39424ea..0000000 --- a/test/common.js +++ /dev/null @@ -1,10 +0,0 @@ -global.expect = require('chai').expect; - -var textract = require('../lib'); - -global.textract = textract; -global.fromBufferWithName = textract.fromBufferWithName; -global.fromBufferWithMime = textract.fromBufferWithMime; -global.fromFileWithPath = textract.fromFileWithPath; -global.fromFileWithMimeAndPath = textract.fromFileWithMimeAndPath; -global.fromUrl = textract.fromUrl; \ No newline at end of file diff --git a/test/extract.test.ts b/test/extract.test.ts new file mode 100644 index 0000000..9260070 --- /dev/null +++ b/test/extract.test.ts @@ -0,0 +1,671 @@ +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { describe, it, expect } from 'vitest'; +import { extractFromFile } from '../lib/index.js'; + +const DIR = fileURLToPath(path.dirname(import.meta.url)); +const isOSX = os.platform() === 'darwin'; + +describe('textract', () => { + describe('for .csv files ', () => { + // is some oddness testing html files, not sure what the deal is + + it('from csv files', async () => { + const docPath = path.join(DIR, 'files', 'csv.csv'); + const text = await extractFromFile(docPath); + expect(text.length).toEqual(18); + expect(text).toEqual('Foo,Bar Foo2,Bar2 '); + }); + + it('it will extract text from csv files and insert newlines in the right places', async () => { + const docPath = path.join(DIR, 'files', 'csv.csv'); + const text = await extractFromFile(docPath, undefined, { + preserveLineBreaks: true, + }); + expect(text.length).toEqual(18); + expect(text).toEqual('Foo,Bar\nFoo2,Bar2\n'); + }); + }); + + describe('for .html files', () => { + // is some oddness testing html files, not sure what the deal is + + it('will extract text from html files and insert newlines in the right places', async () => { + const docPath = path.join(DIR, 'files', 'test.html'); + const text = await extractFromFile(docPath, undefined, { + preserveLineBreaks: true, + }); + expect(text.length).toEqual(80); + expect(text).toEqual( + '\nThis is a\nlong string\nof text\nthat should get extracted\nwith new lines inserted', + ); + }); + + it('will extract text from html files', async () => { + const docPath = path.join(DIR, 'files', 'Google.html'); + const text = await extractFromFile(docPath); + expect(text.length).toEqual(869); + expect(text.substring(565, 620)).toEqual( + 'you say next. Learn more No thanks Enable "Ok Google" I', + ); + }); + + it('will extract text from html files and preserve alt text when asked', async () => { + const docPath = path.join(DIR, 'files', 'test-alt.html'); + const text = await extractFromFile(docPath, undefined, { + includeAltText: true, + }); + expect(text.length).toEqual(46); + expect(text).toEqual(' This is a paragraph that has an image inside '); + }); + }); + + describe('for .rss files', () => { + it('will extract text from rss files', async () => { + const docPath = path.join(DIR, 'files', 'rss.rss'); + const text = await extractFromFile(docPath); + expect(text.length).toEqual(5399); + expect(text.substring(0, 100)).toEqual( + ' FeedForAll Sample Feed RSS is a fascinating technology. The uses for RSS are expanding daily. Take ', + ); + }); + + it('will extract text from rss files and preserve line breaks', async () => { + const docPath = path.join(DIR, 'files', 'rss.rss'); + const text = await extractFromFile(docPath, undefined, { + preserveLineBreaks: true, + }); + expect(text.length).toEqual(5534); + expect(text.substring(0, 100)).toEqual( + '\n FeedForAll Sample Feed\n RSS is a fascinating technology. The uses for RSS are expanding daily. Tak', + ); + }); + }); + + describe('for .epub files', { timeout: 10_000 }, () => { + it('will extract text from epub files', async () => { + const docPath = path.join(DIR, 'files', 'Metamorphosis-jackson.epub'); + + const text = await extractFromFile(docPath); + expect(text.length).toEqual(119329); + expect(text.substring(3000, 3500)).toEqual( + 'dboard so that he could lift his head better; found where the itch was, and saw that it was covered with lots of little white spots which he didn\'t know what to make of; and when he tried to feel the place with one of his legs he drew it quickly back because as soon as he touched it he was overcome by a cold shudder. He slid back into his former position. "Getting up early all the time", he thought, "it makes you stupid. You\'ve got to get enough sleep. Other travelling salesmen live a life of lu', + ); + }); + + it('will extract text from epub files and preserve line breaks', async () => { + const docPath = path.join(DIR, 'files', 'Metamorphosis-jackson.epub'); + + const text = await extractFromFile(docPath, undefined, { + preserveLineBreaks: true, + }); + expect(text.length).toEqual(119342); + expect(text.substring(3000, 3500)).toEqual( + 'rds the headboard so that he could lift his head better; found where the itch was, and saw that it was covered with lots of little white spots which he didn\'t know what to make of; and when he tried to feel the place with one of his legs he drew it quickly back because as soon as he touched it he was overcome by a cold shudder.\nHe slid back into his former position. "Getting up early all the time", he thought, "it makes you stupid. You\'ve got to get enough sleep. Other travelling salesmen live a', + ); + }); + }); + + describe('for .atom files', () => { + it('will extract text from atom files', async () => { + const docPath = path.join(DIR, 'files', 'atom.atom'); + const text = await extractFromFile(docPath); + expect(text.length).toEqual(26731); + expect(text.substring(0, 100)).toEqual( + ' @{}[]tag:theregister.co.uk,2005:feed/theregister.co.uk/data_centre/storage/ The Register - Data Cen', + ); + }); + + it('will extract text from atom files and preserve line breaks', async () => { + const docPath = path.join(DIR, 'files', 'atom.atom'); + const text = await extractFromFile(docPath, undefined, { + preserveLineBreaks: true, + }); + expect(text.length).toEqual(27441); + expect(text.substring(0, 100)).toEqual( + '\n @{}[]tag:theregister.co.uk,2005:feed/theregister.co.uk/data_centre/storage/\n The Register - Data C', + ); + }); + }); + + describe('for .rtf files', () => { + it('will extract text from rtf files', async () => { + const docPath = path.join(DIR, 'files', 'sample.rtf'); + const text = await extractFromFile(docPath); + expect(text.substring(144, 220)).toContain( + "So we're going to end this paragraph here and go on", + ); + }); + + it('will extract when there are spaces in the name', async () => { + const docPath = path.join(DIR, 'files', 'sample rtf.rtf'); + const text = await extractFromFile(docPath); + expect(text.substring(144, 220)).toContain( + "So we're going to end this paragraph here and go on", + ); + }); + + it('will extract text from actual rtf files with lines left in', async () => { + const docPath = path.join(DIR, 'files', 'sample.rtf'); + const text = await extractFromFile(docPath, undefined, { + preserveLineBreaks: true, + }); + expect(text.substring(144, 227)).toContain( + "So we're going to end this paragraph here and go on to a nice", + ); + }); + }); + + describe('for .doc files', () => { + it('will extract text from actual doc files', async () => { + const docPath = path.join(DIR, 'files', 'doc.doc'); + const text = await extractFromFile(docPath); + expect(text.substring(0, 100)).toEqual( + isOSX + ? 'Word Specification Sample Working Draft 04, 16 August 2002 Document identifier: wd-spectools-word-sa' + : ' Word Specification Sample Working Draft 04, 16 August 2002 Document identifier: wd-spectools-word-s', + ); + }); + + it('will extract text from actual doc files with spaces in the name', async () => { + const docPath = path.join(DIR, 'files', 'doc space.doc'); + const text = await extractFromFile(docPath); + expect(text.substring(0, 100)).toEqual( + isOSX + ? 'Word Specification Sample Working Draft 04, 16 August 2002 Document identifier: wd-spectools-word-sa' + : ' Word Specification Sample Working Draft 04, 16 August 2002 Document identifier: wd-spectools-word-s', + ); + }); + + it('will not extract text from text files masquerading as doc files', async () => { + try { + const docPath = path.join(DIR, 'files', 'notadoc.doc'); + await extractFromFile(docPath); + } catch (error) { + expect(error).toBeInstanceOf(Error); + expect((error as Error).message).toContain( + 'does not appear to really be a .doc file', + ); + } + }); + + it('will extract text from large .doc', async () => { + const docPath = path.join(DIR, 'files', 'sample.doc'); + const text = await extractFromFile(docPath); + expect(text.length).toBeGreaterThan(30_000); + }); + + it('will extract text preserving line breaks without word wrap', async () => { + const docPath = path.join(DIR, 'files', 'multiple-long-paragraphs.doc'); + const text = await extractFromFile(docPath, undefined, { + preserveLineBreaks: true, + }); + expect(text.split(/[\r\n]+/g).length).toEqual(isOSX ? 3 : 21); + }); + }); + + describe('for .xls files', () => { + it('will extract text', async () => { + const docPath = path.join(DIR, 'files', 'test.xls'); + const text = await extractFromFile(docPath); + expect(text.substring(0, 20)).toEqual('This,is,a,spreadshee'); + }); + + it('will extract text from multi-line files', async () => { + const docPath = path.join(DIR, 'files', 'test-multiline.xls'); + const text = await extractFromFile(docPath); + expect(text.substring(0, 40)).toEqual( + 'This,is,a,spreadsheet,yay! And ,this,is,', + ); + }); + + it('will extract text from multi-line files and keep line breaks', async () => { + const docPath = path.join(DIR, 'files', 'test-multiline.xls'); + const text = await extractFromFile(docPath, undefined, { + preserveLineBreaks: true, + }); + expect(text.substring(0, 40)).toEqual( + 'This,is,a,spreadsheet,yay!\nAnd ,this,is,', + ); + }); + }); + + describe('for .xlsx files', () => { + it('will extract text and numbers from XLSX files', async () => { + const filePath = path.join(DIR, 'files', 'pi.xlsx'); + const text = await extractFromFile(filePath); + expect(text).toEqual('This is the value of PI:,3.141592'); + }); + + it('will extract text from XLSX files with multiple sheets', async () => { + const filePath = path.join(DIR, 'files', 'xlsx.xlsx'); + const text = await extractFromFile(filePath); + expect(text.substring(49, 96)).toEqual( + 'Color,Pattern,Sex,GeneralSizePotential,GeneralA', + ); + }); + + it('will error when input file is not an actual xlsx file', async () => { + const filePath = path.join(DIR, 'files', 'notaxlsx.xlsx'); + try { + await extractFromFile(filePath); + } catch (error) { + expect((error as Error).message).toMatch( + /Could not extract .* PRN files unsupported/, + ); + } + }); + }); + + describe('for .pdf files', () => { + it('will extract text from actual pdf files', async () => { + const filePath = path.join(DIR, 'files', 'pdf.pdf'); + const text = await extractFromFile(filePath); + expect(text).toEqual('This is a test. Please ignore.'); + }); + + it('will extract pdf text and preserve multiple lines', async () => { + const filePath = path.join(DIR, 'files', 'testpdf-multiline.pdf'); + const text = await extractFromFile(filePath, undefined, { + preserveLineBreaks: true, + }); + expect(text).toEqual( + 'This is a test,\nA multi-line test,\nLets hope it works', + ); + }); + + it("will error out when pdf file isn't actually a pdf", async () => { + const filePath = path.join(DIR, 'files', 'notapdf.pdf'); + try { + await extractFromFile(filePath); + } catch (error) { + expect((error as Error).message).toContain( + 'Error extracting PDF text for file', + ); + } + }); + + it('will properly handle multiple columns', async () => { + const filePath = path.join(DIR, 'files', 'two_columns.pdf'); + const text = await extractFromFile(filePath, undefined, { + preserveLineBreaks: true, + }); + expect( + text.indexOf( + 'Abstract— This work deals with a multi-cell topology based\non current-source converters based power cells.', + ), + ).toBeGreaterThan(500); + }); + + it('can handle files with spaces in the name', async () => { + const filePath = path.join(DIR, 'files', 'two columns.pdf'); + const text = await extractFromFile(filePath, undefined, { + preserveLineBreaks: true, + }); + expect( + text.indexOf( + 'Abstract— This work deals with a multi-cell topology based\non current-source converters based power cells.', + ), + ).toBeGreaterThan(500); + }); + + it('can handle PDFs with passwords', async () => { + const filePath = path.join( + DIR, + 'files', + 'pdf-example-password.original.pdf', + ); + const text = await extractFromFile(filePath, undefined, { + pdftotextOptions: { userPassword: 'test' }, + }); + expect(text.substring(0, 200)).toEqual( + 'Backup4all –backup solution for network environments Starting from version 2 it is easier to install Backup4all in a network environment. Network administrators can install Backup4all on a single comp', + ); + }); + + it('can handle PDFs with full-width Japanese characters', async () => { + const filePath = path.join(DIR, 'files', 'full-width-j.pdf'); + const text = await extractFromFile(filePath); + expect(text.replace(/ /g, '').substring(2685, 2900)).toEqual( + '$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ᄀᄁᆪᄂᆬᆭᄃᄄᄅᆰᆱᆲᆳᆴᆵᄚᄆᄇᄈᄡᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵ¢£¬ ̄¦¥₩F', + ); + }); + + // it( 'can handle arabic', function( done ) { + // var filePath = path.join( DIR, 'files', 'arabic.pdf' ); + // extractFromFile( filePath, function( error, text ) { + // expect( error ).to.be.null; + // expect( text ).to.be.a( 'string' ); + // expect( text.substring( 0, 200 ) ).to.eql( '' ); + // done(); + // }); + // }); + }); + + describe('for .docx files', () => { + it('will extract text from actual docx files', async () => { + const filePath = path.join(DIR, 'files', 'docx.docx'); + const text = await extractFromFile(filePath); + expect(text.substring(0, 20)).toEqual('This is a test Just '); + }); + + it('will extract text from actual docx files and preserve line breaks', async () => { + const filePath = path.join(DIR, 'files', 'docx.docx'); + const text = await extractFromFile(filePath, undefined, { + preserveLineBreaks: true, + }); + expect(text.substring(20, 40)).toContain('so you know:\nLorem'); + }); + + it('will extract text from actual docx files and preserve line breaks [line-breaks.docx]', async () => { + const filePath = path.join(DIR, 'files', 'line-breaks.docx'); + const text = await extractFromFile(filePath, undefined, { + preserveLineBreaks: true, + }); + expect(text).toEqual('Paragraph follows\nLine break follows\nend'); + }); + + it("will error out when docx file isn't actually a docx", async () => { + const filePath = path.join(DIR, 'files', 'notadocx.docx'); + try { + await extractFromFile(filePath); + } catch (error) { + expect((error as Error).message).toContain( + 'File not correctly recognized as zip file', + ); + } + }); + + it('will not extract smashed together text', async () => { + const filePath = path.join(DIR, 'files', 'testresume.docx'); + const text = await extractFromFile(filePath); + expect(text.substring(0, 31)).toEqual('Karol Miner 336 W. Chugalug Way'); + }); + + it('can handle funky formatting', async () => { + const filePath = path.join(DIR, 'files', 'Untitleddocument.docx'); + const text = await extractFromFile(filePath); + expect(text).toEqual( + "this is a test document that won't be extracted properly.", + ); + }); + + it('can handle a huge docx', async () => { + const filePath = path.join(DIR, 'files', 'LargeLorem.docx'); + const text = await extractFromFile(filePath); + expect(text.substring(0, 100)).toEqual( + 'Hashtag chambray XOXO PBR&B chia small batch. Before they sold out banh mi raw denim, fap synth hell', + ); + }); + + it('can handle arabic', async () => { + const filePath = path.join(DIR, 'files', 'arabic.docx'); + const text = await extractFromFile(filePath); + expect(text.substring(0, 100)).toEqual( + 'التعرف الضوئي على الحروف إشعار عدم التمييز (المصدر: مكتب الصحة والخدمات الإنسانية من أجل الحقوق المد', + ); + }); + }); + + describe('for text/* files', () => { + it('will extract text from specifically a .txt file', async () => { + const filePath = path.join(DIR, 'files', 'txt.txt'); + const text = await extractFromFile(filePath); + expect(text).toEqual('This is a plain old text file.'); + }); + + it('will extract text from specifically a non utf8 .txt file', async () => { + const filePath = path.join(DIR, 'files', 'non-utf8.txt'); + const text = await extractFromFile(filePath); + expect(text).toEqual('これは非UTF8 テキストファイルです '); + }); + + it('will error when .txt file encoding cannot be detected', async () => { + const filePath = path.join(DIR, 'files', 'unknown-encoding.txt'); + try { + await extractFromFile(filePath); + } catch (error) { + expect((error as Error).message).toContain('Could not detect encoding'); + } + }); + + it('will extract text specifically from a .css file', async () => { + const filePath = path.join(DIR, 'files', 'css.css'); + const text = await extractFromFile(filePath); + expect(text).toEqual('.foo {color:red}'); + }); + + it('will extract text specifically from a .js file', async () => { + const filePath = path.join(DIR, 'files', 'js.js'); + const text = await extractFromFile(filePath); + expect(text).toEqual("console.log('javascript is cooler than you'); "); + }); + + it('will remove extraneous white space from a .txt file', async () => { + const filePath = path.join(DIR, 'files', 'spacey.txt'); + const text = await extractFromFile(filePath); + expect(text).toEqual('this has lots of space'); + }); + + it('will not remove fancy quotes from a .txt file', async () => { + const filePath = path.join(DIR, 'files', 'fancyquote.txt'); + const text = await extractFromFile(filePath); + expect(text).toEqual('this has "fancy" quotes'); + }); + }); + + describe('for .pptx files', () => { + it('will extract text PPTX files', async () => { + const filePath = path.join(DIR, 'files', 'ppt.pptx'); + const text = await extractFromFile(filePath); + expect(text.substring(55, 96)).toEqual( + 'ullet 1 Bullet 2 Bullet 3 Number 1 Number', + ); + }); + + it('will extract text PPTX files with notes', async () => { + const filePath = path.join(DIR, 'files', 'PrezoWithNotes.pptx'); + const text = await extractFromFile(filePath); + expect(text).toEqual('This is a slide These are speaker notes 1 '); + }); + + it('will extract slides in the right order', async () => { + const filePath = path.join(DIR, 'files', 'order.pptx'); + const text = await extractFromFile(filePath, undefined, { + preserveLineBreaks: true, + }); + + const lines = text.split('\n').filter((line) => /^Slide/.exec(line)); + + const expectedLines = [ + 'Slide 1 Title', + 'Slide 1 Subtitle', + 'Slide 2: Title and Content', + 'Slide 3: Section header', + 'Slide 4: Two-Content', + 'Slide 5: Comparison', + 'Slide 8: Content w/Caption', + 'Slide 9: picture with caption', + 'Slide 10: Vertical Text', + 'Slide 11: Vertical Title and text', + ]; + + expect(lines).toEqual(expectedLines); + }); + + it('will keep preserved characters', async () => { + const filePath = path.join(DIR, 'files', 'order.pptx'); + const text = await extractFromFile(filePath, undefined, { + preserveLineBreaks: true, + }); + expect(text.indexOf('…')).toBeGreaterThan(900); + }); + }); + + describe('for odt files', () => { + it('will extract text from ODT files', async () => { + const filePath = path.join(DIR, 'files', 'spaced.odt'); + const text = await extractFromFile(filePath); + expect(text).toEqual('This Is some text'); + }); + }); + + describe('for image files', () => { + it('will extract text from PNG files', async () => { + const filePath = path.join(DIR, 'files', 'testphoto.png'); + const text = await extractFromFile(filePath); + expect(text.substring(0, 100)).toEqual( + 'performance measure against standards and targets is increasingly used in the management of complex ', + ); + }); + + it('will extract text from JPG files', async () => { + const filePath = path.join(DIR, 'files', 'testphoto.jpg'); + const text = await extractFromFile(filePath); + expect(text.substring(0, 100)).toEqual( + 'performance measure against standards and targets is increasingly used in the management of complex ', + ); + }); + + it('will extract text from GIF files', async () => { + const filePath = path.join(DIR, 'files', 'testphoto.gif'); + const text = await extractFromFile(filePath); + expect(text.substring(0, 100)).toEqual( + 'performance measure against standards and targets is increasingly used in the management of complex ', + ); + }); + + // sudo port install tesseract-chi-sim + it( + 'will extract text from language-d files', + { timeout: 5000 }, + async () => { + const filePath = path.join(DIR, 'files', 'chi.png'); + const text = await extractFromFile(filePath, undefined, { + tesseract: { lang: 'chi_sim' }, + }); + expect(text.substring(0, 6)).toEqual('卧虎藏龙,卧'); + }, + ); + + // sudo port install tesseract-eng + it('will take tesseract.cmd option', { timeout: 5000 }, async () => { + const filePath = path.join(DIR, 'files', 'testpng.png'); + const text = await extractFromFile(filePath, undefined, { + tesseract: { cmd: '-l eng --psm 3' }, + }); + expect(text.substring(0, 100)).toEqual( + 'The (quick) [brown] {fox} jumps! Over the $43,456.78 #90 dog & duck/goose, as 12.5% of E-mail', + ); + }); + }); +}); + +const TEST_CASES = [ + [ + 'markdown', + 'test.md', + ' This is an h1 This is an h2 This text has been bolded and italicized ', + '\nThis is an h1\nThis is an h2\nThis text has been bolded and italicized\n', + ], + + [ + 'ods', + 'ods.ods', + 'This,is,a,ods Really,it,is, I,promise,,', + 'This,is,a,ods\nReally,it,is,\nI,promise,,', + ], + + [ + 'xml', + 'xml.xml', + ' Empire Burlesque Bob Dylan USA Columbia 10.90 1985 Hide your heart Bonnie Tyler UK CBS Records 9.90', + '\nEmpire Burlesque\nBob Dylan\nUSA\nColumbia\n10.90\n1985\nHide your heart\nBonnie Tyler\nUK\nCBS Records\n9.90', + ], + + [ + 'odt', + 'odt.odt', + 'This is an ODT THIS IS A HEADING More ODT', + 'This is an ODT\nTHIS IS A HEADING\nMore ODT', + ], + + [ + 'potx', + 'potx.potx', + 'This is a potx template Yep, a potx I had no idea These were even a thing ', + 'This is a potx template\nYep, a potx\nI had no idea \nThese were even a thing\n', + ], + + [ + 'xltx', + 'xltx.xltx', + ',,,,,, Packing Slip ,Your Company Name,,,,"July 24, 2015", , Your Company Slogan,,,,, ,,,,,, ,Addres', + ',,,,,, Packing Slip\n,Your Company Name,,,,"July 24, 2015",\n, Your Company Slogan,,,,,\n,,,,,,\n,Addres', + ], + + [ + 'ott', + 'ott.ott', + 'This is a document template, yay templates! Woo templates get me so excited!', + 'This is a document template, yay templates!\nWoo templates get me so excited!', + ], + + [ + 'ots', + 'ots.ots', + "This,is, template, an,open,office,template isn't,it,awesome?, you,know,it,is", + "This,is, template,\nan,open,office,template\nisn't,it,awesome?,\nyou,know,it,is", + ], + + [ + 'odg', + 'odg.odg', + "This is a drawing? A drawing, a drawing! This is a drawing, Aren't you mad envious?", + "This is a drawing?\nA drawing, a drawing!\nThis is a drawing,\nAren't you mad envious?", + ], + + [ + 'otg', + 'otg.otg', + 'This is a drawing template A drawing template. Who would really ever need to extract from one of the', + 'This is a drawing template\nA drawing template.\nWho would really ever need to extract from one of the', + ], + + [ + 'odp', + 'odp.odp', + "This is a title This is a slide's text This is a 2nd page And a 2nd page's content", + "This is a title\nThis is a slide's text\nThis is a 2nd page\nAnd a 2nd page's content", + ], + + [ + 'otp', + 'otp.otp', + 'This is a template title Template page text 2nd prezo text', + 'This is a template title\nTemplate page text\n2nd prezo text', + ], +] as const; + +describe('textract', () => { + it.each(TEST_CASES)( + 'for %s files will extract text', + async (_ext, name, expectedText) => { + const docPath = path.join(DIR, 'files', name); + const text = await extractFromFile(docPath); + expect(text.substring(0, 100)).toEqual(expectedText); + }, + ); + + it.each(TEST_CASES)( + 'for %s files will extract text and preserve line breaks', + async (_ext, name, _expectedText, expectedTextWithLineBreaks) => { + const docPath = path.join(DIR, 'files', name); + const text = await extractFromFile(docPath, undefined, { + preserveLineBreaks: true, + }); + expect(text.substring(0, 100)).toEqual(expectedTextWithLineBreaks); + }, + ); +}); diff --git a/test/extract_test.js b/test/extract_test.js deleted file mode 100644 index 3ed7027..0000000 --- a/test/extract_test.js +++ /dev/null @@ -1,793 +0,0 @@ -/* eslint-disable max-len, no-unused-expressions */ -/* global fromFileWithPath */ - -var path = require( 'path' ); - -describe( 'textract', function() { - var test; - - describe( 'for .csv files ', function() { - // is some oddness testing html files, not sure what the deal is - - it( 'from csv files', function( done ) { - var docPath = path.join( __dirname, 'files', 'csv.csv' ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 18 ); - expect( text ).to.eql( 'Foo,Bar Foo2,Bar2 ' ); - done(); - }); - }); - - it( 'it will extract text from csv files and insert newlines in the right places', function( done ) { - var docPath = path.join( __dirname, 'files', 'csv.csv' ); - fromFileWithPath( docPath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 18 ); - expect( text ).to.eql( 'Foo,Bar\nFoo2,Bar2\n' ); - done(); - }); - }); - }); - - describe( 'for .html files', function() { - // is some oddness testing html files, not sure what the deal is - - it( 'will extract text from html files and insert newlines in the right places', function( done ) { - var docPath = path.join( __dirname, 'files', 'test.html' ); - fromFileWithPath( docPath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 80 ); - expect( text.substring( 0, 80 ) ).to.eql( '\nThis is a\nlong string\nof text\nthat should get extracted\nwith new lines inserted' ); - done(); - }); - }); - - - it( 'will extract text from html files', function( done ) { - var docPath = path.join( __dirname, 'files', 'Google.html' ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 869 ); - expect( text.substring( 565, 620 ) ).to.eql( 'you say next. Learn more No thanks Enable "Ok Google" I' ); - done(); - }); - }); - - it( 'will extract text from html files and preserve alt text when asked', function( done ) { - var docPath = path.join( __dirname, 'files', 'test-alt.html' ); - fromFileWithPath( docPath, { includeAltText: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 46 ); - expect( text ).to.eql( ' This is a paragraph that has an image inside ' ); - done(); - }); - }); - }); - - describe( 'for .rss files', function() { - it( 'will extract text from rss files', function( done ) { - var docPath = path.join( __dirname, 'files', 'rss.rss' ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 5399 ); - expect( text.substring( 0, 100 ) ).to.eql( ' FeedForAll Sample Feed RSS is a fascinating technology. The uses for RSS are expanding daily. Take ' ); - done(); - }); - }); - - it( 'will extract text from rss files and preserve line breaks', function( done ) { - var docPath = path.join( __dirname, 'files', 'rss.rss' ); - fromFileWithPath( docPath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 5534 ); - expect( text.substring( 0, 100 ) ).to.eql( '\n FeedForAll Sample Feed\n RSS is a fascinating technology. The uses for RSS are expanding daily. Tak' ); - done(); - }); - }); - }); - - describe( 'for .epub files', function() { - it( 'will extract text from epub files', function( done ) { - var docPath = path.join( __dirname, 'files', 'Metamorphosis-jackson.epub' ); - this.timeout( 5000 ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 119329 ); - expect( text.substring( 3000, 3500 ) ).to.eql( "dboard so that he could lift his head better; found where the itch was, and saw that it was covered with lots of little white spots which he didn't know what to make of; and when he tried to feel the place with one of his legs he drew it quickly back because as soon as he touched it he was overcome by a cold shudder. He slid back into his former position. \"Getting up early all the time\", he thought, \"it makes you stupid. You've got to get enough sleep. Other travelling salesmen live a life of lu" ); - done(); - }); - }); - - it( 'will extract text from epub files and preserve line breaks', function( done ) { - var docPath = path.join( __dirname, 'files', 'Metamorphosis-jackson.epub' ); - this.timeout( 5000 ); - fromFileWithPath( docPath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 119342 ); - expect( text.substring( 3000, 3500 ) ).to.eql( "rds the headboard so that he could lift his head better; found where the itch was, and saw that it was covered with lots of little white spots which he didn't know what to make of; and when he tried to feel the place with one of his legs he drew it quickly back because as soon as he touched it he was overcome by a cold shudder.\nHe slid back into his former position. \"Getting up early all the time\", he thought, \"it makes you stupid. You've got to get enough sleep. Other travelling salesmen live a" ); - done(); - }); - }); - }); - - describe( 'for .atom files', function() { - it( 'will extract text from atom files', function( done ) { - var docPath = path.join( __dirname, 'files', 'atom.atom' ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 26731 ); - expect( text.substring( 0, 100 ) ).to.eql( ' @{}[]tag:theregister.co.uk,2005:feed/theregister.co.uk/data_centre/storage/ The Register - Data Cen' ); - done(); - }); - }); - - it( 'will extract text from atom files and preserve line breaks', function( done ) { - var docPath = path.join( __dirname, 'files', 'atom.atom' ); - fromFileWithPath( docPath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 27441 ); - expect( text.substring( 0, 100 ) ).to.eql( '\n @{}[]tag:theregister.co.uk,2005:feed/theregister.co.uk/data_centre/storage/\n The Register - Data C' ); - done(); - }); - }); - }); - - describe( 'for .rtf files', function() { - it( 'will extract text from rtf files', function( done ) { - var docPath = path.join( __dirname, 'files', 'sample.rtf' ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 144, 220 ) ).to.eql( "bit of hidden text. So we're going to end this paragraph here and go on to a" ); - done(); - }); - }); - - it( 'will extract when there are spaces in the name', function( done ) { - var docPath = path.join( __dirname, 'files', 'sample rtf.rtf' ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 144, 220 ) ).to.eql( "bit of hidden text. So we're going to end this paragraph here and go on to a" ); - done(); - }); - }); - - it( 'will extract text from actual rtf files with lines left in', function( done ) { - var docPath = path.join( __dirname, 'files', 'sample.rtf' ); - fromFileWithPath( docPath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 144, 230 ) ).to.eql( "bit of hidden text. So we're going to end this paragraph here and go on to a nice litt" ); - done(); - }); - }); - }); - - describe( 'for .doc files', function() { - it( 'will extract text from actual doc files', function( done ) { - var docPath = path.join( __dirname, 'files', 'doc.doc' ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( ' Word Specification Sample Working Draft 04, 16 August 2002 Document identifier: wd-spectools-word-s' ); - done(); - }); - }); - - it( 'will extract text from actual doc files with spaces in the name', function( done ) { - var docPath = path.join( __dirname, 'files', 'doc space.doc' ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( ' Word Specification Sample Working Draft 04, 16 August 2002 Document identifier: wd-spectools-word-s' ); - done(); - }); - }); - - it( 'will not extract text from text files masquerading as doc files', function( done ) { - var docPath = path.join( __dirname, 'files', 'notadoc.doc' ); - fromFileWithPath( docPath, function( error, text ) { - expect( text ).to.be.null; - expect( error.toString().indexOf( 'does not appear to really be a .doc file' ) ).to.eql( 36 ); - done(); - }); - }); - - it( 'will extract text from large .doc', function( done ) { - var docPath = path.join( __dirname, 'files', 'sample.doc' ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.length ).to.eql( 32658 ); - done(); - }); - }); - - it( 'will extract text preserving line breaks without word wrap', function( done ) { - var docPath = path.join( __dirname, 'files', 'multiple-long-paragraphs.doc' ); - fromFileWithPath( docPath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text.match( /\r\n|\n/g ).length ).to.eql( 21 ); - done(); - }); - }); - }); - - describe( 'for .xls files', function() { - it( 'will extract text', function( done ) { - var docPath = path.join( __dirname, 'files', 'test.xls' ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 20 ) ).to.eql( 'This,is,a,spreadshee' ); - done(); - }); - }); - - it( 'will extract text from multi-line files', function( done ) { - var docPath = path.join( __dirname, 'files', 'test-multiline.xls' ); - fromFileWithPath( docPath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 40 ) ).to.eql( 'This,is,a,spreadsheet,yay! And ,this,is,' ); - done(); - }); - }); - - it( 'will extract text from multi-line files and keep line breaks', function( done ) { - var docPath = path.join( __dirname, 'files', 'test-multiline.xls' ); - fromFileWithPath( docPath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 40 ) ).to.eql( 'This,is,a,spreadsheet,yay!\nAnd ,this,is,' ); - done(); - }); - }); - }); - - describe( 'for .xlsx files', function() { - it( 'will extract text and numbers from XLSX files', function( done ) { - var filePath = path.join( __dirname, 'files', 'pi.xlsx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text ).to.eql( 'This is the value of PI:,3.141592 ' ); - done(); - }); - }); - - it( 'will extract text from XLSX files with multiple sheets', function( done ) { - var filePath = path.join( __dirname, 'files', 'xlsx.xlsx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 49, 96 ) ).to.eql( 'Color,Pattern,Sex,GeneralSizePotential,GeneralA' ); - done(); - }); - }); - - it( 'will error when input file is not an actual xlsx file', function( done ) { - var filePath = path.join( __dirname, 'files', 'notaxlsx.xlsx' ); - fromFileWithPath( filePath, function( error ) { - expect( error ).to.be.an( 'object' ); - expect( error.message ).to.be.a( 'string' ); - expect( error.message.substring( 0, 43 ) ).to.eql( 'Could not extract notaxlsx.xlsx, Error: PRN' ); - done(); - }); - }); - }); - - describe( 'for .pdf files', function() { - it( 'will extract text from actual pdf files', function( done ) { - var filePath = path.join( __dirname, 'files', 'pdf.pdf' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'This is a test. Please ignore.' ); - done(); - }); - }); - - it( 'will extract pdf text and preserve multiple lines', function( done ) { - var filePath = path.join( __dirname, 'files', 'testpdf-multiline.pdf' ); - fromFileWithPath( filePath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'This is a test,\nA multi-line test,\nLets hope it works' ); - done(); - }); - }); - - it( 'will error out when pdf file isn\'t actually a pdf', function( done ) { - var filePath = path.join( __dirname, 'files', 'notapdf.pdf' ); - fromFileWithPath( filePath, function( error, text ) { - expect( text ).to.be.null; - expect( error ).to.be.an( 'object' ); - expect( error.message ).to.be.a( 'string' ); - expect( error.message.substring( 0, 34 ) ).to.eql( 'Error extracting PDF text for file' ); - done(); - }); - }); - - it( 'will properly handle multiple columns', function( done ) { - var filePath = path.join( __dirname, 'files', 'two_columns.pdf' ); - fromFileWithPath( filePath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.indexOf( - 'Abstract— This work deals with a multi-cell topology based\non current-source converters based power cells.' - ) > 500 ).to.be.true; - done(); - }); - }); - - it( 'can handle files with spaces in the name', function( done ) { - var filePath = path.join( __dirname, 'files', 'two columns.pdf' ); - fromFileWithPath( filePath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.indexOf( - 'Abstract— This work deals with a multi-cell topology based\non current-source converters based power cells.' - ) > 500 ).to.be.true; - done(); - }); - }); - - it( 'can handle manage PDFs with passwords', function( done ) { - var filePath = path.join( __dirname, 'files', 'pdf-example-password.original.pdf' ); - fromFileWithPath( filePath, { pdftotextOptions: { userPassword: 'test' } }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 200 ) ).to.eql( 'Backup4all –backup solution for network environments Starting from version 2 it is easier to install Backup4all in a network environment. Network administrators can install Backup4all on a single comp' ); - done(); - }); - }); - - it( 'can handle manage PDFS with full-width Japanese characters', function( done ) { - var filePath = path.join( __dirname, 'files', 'full-width-j.pdf' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.replace( / /g, '' ).substring( 2685, 2900 ) ).to.eql( '$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ᄀᄁᆪᄂᆬᆭᄃᄄᄅᆰᆱᆲᆳᆴᆵᄚᄆᄇᄈᄡᄉᄊᄋᄌᄍᄎᄏᄐᄑ하ᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵ¢£¬ ̄¦¥₩F' ); - done(); - }); - }); - - // it( 'can handle arabic', function( done ) { - // var filePath = path.join( __dirname, 'files', 'arabic.pdf' ); - // fromFileWithPath( filePath, function( error, text ) { - // expect( error ).to.be.null; - // expect( text ).to.be.a( 'string' ); - // expect( text.substring( 0, 200 ) ).to.eql( '' ); - // done(); - // }); - // }); - }); - - describe( 'for .docx files', function() { - it( 'will extract text from actual docx files', function( done ) { - var filePath = path.join( __dirname, 'files', 'docx.docx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 20 ) ).to.eql( 'This is a test Just ' ); - done(); - }); - }); - - it( 'will extract text from actual docx files and preserve line breaks', function( done ) { - var filePath = path.join( __dirname, 'files', 'docx.docx' ); - fromFileWithPath( filePath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 20, 40 ) ).to.eql( 'so you know:\nLorem i' ); - done(); - }); - }); - - it( 'will extract text from actual docx files and preserve line breaks [line-breaks.docx]', function( done ) { - var filePath = path.join( __dirname, 'files', 'line-breaks.docx' ); - fromFileWithPath( filePath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'Paragraph follows\n\nLine break follows\n\nend\n\n' ); - done(); - }); - }); - - it( 'will error out when docx file isn\'t actually a docx', function( done ) { - var filePath = path.join( __dirname, 'files', 'notadocx.docx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( text ).to.be.null; - expect( error ).to.be.an( 'object' ); - expect( error.message ).to.be.a( 'string' ); - expect( error.message.substring( 0, 34 ) ).to.eql( 'File not correctly recognized as z' ); - done(); - }); - }); - - it( 'will not extract smashed together text', function( done ) { - var filePath = path.join( __dirname, 'files', 'testresume.docx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 31 ) ).to.eql( 'Karol Miner 336 W. Chugalug Way' ); - done(); - }); - }); - - it( 'can handle funky formatting', function( done ) { - var filePath = path.join( __dirname, 'files', 'Untitleddocument.docx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( "this is a test document that won't be extracted properly. " ); - done(); - }); - }); - - it( 'can handle a huge docx', function( done ) { - var filePath = path.join( __dirname, 'files', 'LargeLorem.docx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( 'Hashtag chambray XOXO PBR&B chia small batch. Before they sold out banh mi raw denim, fap synth hell' ); - done(); - }); - }); - - it( 'can handle arabic', function( done ) { - var filePath = path.join( __dirname, 'files', 'arabic.docx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( ' التعرف الضوئي على الحروف إشعار عدم التمييز (المصدر: مكتب الصحة والخدمات الإنسانية من أجل الحقوق الم' ); - done(); - }); - }); - }); - - describe( 'for text/* files', function() { - it( 'will extract text from specifically a .txt file', function( done ) { - var filePath = path.join( __dirname, 'files', 'txt.txt' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'This is a plain old text file.' ); - done(); - }); - }); - - it( 'will extract text from specifically a non utf8 .txt file', function( done ) { - var filePath = path.join( __dirname, 'files', 'non-utf8.txt' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'これは非UTF8 テキストファイルです ' ); - done(); - }); - }); - - it( 'will error when .txt file encoding cannot be detected', function( done ) { - var filePath = path.join( __dirname, 'files', 'unknown-encoding.txt' ); - fromFileWithPath( filePath, function( error ) { - expect( error ).to.be.an( 'object' ); - expect( error.message ).to.be.a( 'string' ); - expect( error.message ).to.eql( 'Could not detect encoding for file named [[ unknown-encoding.txt ]]' ); - done(); - }); - }); - - it( 'will extract text specifically from a .css file', function( done ) { - var filePath = path.join( __dirname, 'files', 'css.css' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( '.foo {color:red}' ); - done(); - }); - }); - - it( 'will extract text specifically from a .js file', function( done ) { - var filePath = path.join( __dirname, 'files', 'js.js' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'console.log("javascript is cooler than you")' ); - done(); - }); - }); - - it( 'will remove extraneous white space from a .txt file', function( done ) { - var filePath = path.join( __dirname, 'files', 'spacey.txt' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'this has lots of space' ); - done(); - }); - }); - - it( 'will not remove fancy quotes from a .txt file', function( done ) { - var filePath = path.join( __dirname, 'files', 'fancyquote.txt' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'this has "fancy" quotes' ); - done(); - }); - }); - }); - - describe( 'for .dxf files', function() { - it( 'will extract text from actual dxf files', function( done ) { - var filePath = path.join( __dirname, 'files', 'dxf.dxf' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - // eslint-disable-next-line no-useless-escape - expect( text ).to.eql( ' PART: FILE: {\fTimes New Roman|b0|i0|c0|p18;(800) 433-1119} {\fTimes New Roman|b0|i0|c0|p18;Barium Springs, NC 28010} {\fTimes New Roman|b0|i0|c0|p18;MultiDrain Systems, Inc.} {\fTimes New Roman|b0|i0|c0|p18;Manufacturers of MultiDrain & EconoDrain } to others for manufacturing or for any other purpose except as specifically authorized in writing by MultiDrain Systems, Inc. Proprietary rights of MultiDrain Systems, Inc. are included in the information disclosed herein. The recipient, by accepting this document, agrees that neither this document nor the information disclosed herein nor any part thereof shall be copied, reproduced or transferred 0 2" 4" 6" 8" 12" 16" GRAPHIC SCALE BAR \A1;T \A1;T \A1;T \A1;6.1" 155mm \A1;T \A1;T \A1;4.9" 124mm \A1;19.6" 497mm FRAME AND GRATE LENGTH \A1;5.5" 140mm %%UCROSS SECTIONAL VIEW SOIL SUBGRADE CONCRETE THICKNESS AND REINFORCEMENT PER STRUCTURAL ENGINEER S SPECIFICATION FOR THE APPLICATION FLOOR SLAB THICKNESS, OR 4" MIN. [100mm], OR SPECIFICATION (WHICHEVER IS GREATER) T = MONOLITHIC CONCRETE POUR (ACCEPTABLE) EXPANSION JOINT BOTH SIDES (PREFERRED) LOCK DOWN BOLT LOCK TOGGLE ANCHOR BOLT SEE ABOVE FOR ACTUAL FRAME & GRATE SECTIONS %%UPLAN %%USECTION 512AF %%UPLAN %%USECTION 513AF 514AF %%UPLAN %%USECTION 515AF %%UPLAN %%USECTION ANCHOR RIB INDEPENDENTLY ANCHORED FRAME ALFA CHANNEL \A1;502 GRATE 510AF ANCHOR FRAME 503 GRATE 510AF ANCHOR FRAME 504 GRATE 505 GRATE FRAME AND GRATE ADD 1.2" [31mm] TO OVERALL DEPTH OF CHANNEL \LNOTE: GRATE WIDTH FRAME WIDTH AC-2510AF-00 2512AF 2513AF 2514AF 2515AF ALFA CHANNEL SYSTEM DUCTILE IRON FRAME & GRATES PRODUCT DRAWING 2006 MultiDrain Systems, Inc. ' ); - done(); - }); - }); - - it( 'will error when input file is not an actual dxf file', function( done ) { - var filePath = path.join( __dirname, 'files', 'notadxf.dxf' ); - fromFileWithPath( filePath, function( error ) { - expect( error ).to.be.an( 'object' ); - expect( error.message ).to.be.a( 'string' ); - expect( error.message.substring( 0, 40 ) ).to.eql( 'Error for type: [[ image/vnd.dxf ]], fil' ); - done(); - }); - }); - }); - - describe( 'for .pptx files', function() { - it( 'will extract text PPTX files', function( done ) { - var filePath = path.join( __dirname, 'files', 'ppt.pptx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 55, 96 ) ).to.eql( 'ullet 1 Bullet 2 Bullet 3 Number 1 Number' ); - done(); - }); - }); - - it( 'will extract text PPTX files with notes', function( done ) { - var filePath = path.join( __dirname, 'files', 'PrezoWithNotes.pptx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text).to.eql( 'This is a slide These are speaker notes 1 ' ); - done(); - }); - }); - - it( 'will extract slides in the right order', function( done ) { - var filePath = path.join( __dirname, 'files', 'order.pptx' ); - fromFileWithPath( filePath, { preserveLineBreaks: true }, function( error, text ) { - var lines, linesAnswer; - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - lines = text.split( '\n' ).filter( function( line ) { - return line.match( /^Slide/ ); - }); - - linesAnswer = [ - 'Slide 1 Title', - 'Slide 1 Subtitle', - 'Slide 2: Title and Content', - 'Slide 3: Section header', - 'Slide 4: Two-Content', - 'Slide 5: Comparison', - 'Slide 8: Content w/Caption', - 'Slide 9: picture with caption', - 'Slide 10: Vertical Text', - 'Slide 11: Vertical Title and text']; - - expect( lines ).to.eql( linesAnswer ); - - done(); - }); - }); - - it( 'will keep preserved characters', function( done ) { - var filePath = path.join( __dirname, 'files', 'order.pptx' ); - fromFileWithPath( filePath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.indexOf( '…' ) ).to.eql( 928 ); - done(); - }); - }); - }); - - describe( 'for odt files', function() { - it( 'will extract text from ODT files', function( done ) { - var filePath = path.join( __dirname, 'files', 'spaced.odt' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text ).to.eql( 'This Is some text' ); - done(); - }); - }); - }); - - describe( 'for image files', function() { - it( 'will extract text from PNG files', function( done ) { - var filePath = path.join( __dirname, 'files', 'testphoto.png' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( 'performance measure against standards and targets is increasingly used in the management of complex ' ); - done(); - }); - }); - - it( 'will extract text from JPG files', function( done ) { - var filePath = path.join( __dirname, 'files', 'testphoto.jpg' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( 'performance measure against standards and targets is increasingly used in the management of complex ' ); - done(); - }); - }); - - it( 'will extract text from GIF files', function( done ) { - var filePath = path.join( __dirname, 'files', 'testphoto.gif' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( 'performance measure against standards and targets is increasingly used in the management of complex ' ); - done(); - }); - }); - - // sudo port install tesseract-chi-sim - it( 'will extract text from language-d files', function( done ) { - var filePath = path.join( __dirname, 'files', 'chi.png' ); - this.timeout( 5000 ); - fromFileWithPath( filePath, { tesseract: { lang: 'chi_sim' } }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 6 ) ).to.eql( '卧虎藏龙,卧' ); - done(); - }); - }); - - // sudo port install tesseract-eng - it( 'will take tesseract.cmd option', function( done ) { - var filePath = path.join( __dirname, 'files', 'testpng.png' ); - this.timeout( 5000 ); - fromFileWithPath( filePath, { tesseract: { cmd: '-l eng -psm 3' } }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( 'The (quick) [brown] {fox} jumps! Over the $43,456.78 #90 dog & duck/goose, as 12.5% of E-mail' ); - done(); - }); - }); - }); - - test = function( ext, name, text1, text2 ) { - describe( 'for ' + ext + ' files', function() { - it( 'will extract text', function( done ) { - var filePath = path.join( __dirname, 'files', name ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( text1 ); - done(); - }); - }); - - it( 'will extract text and preserve line breaks', function( done ) { - var filePath = path.join( __dirname, 'files', name ); - fromFileWithPath( filePath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( text2 ); - done(); - }); - }); - }); - }; - - test( - 'markdown', - 'test.md', - ' This is an h1 This is an h2 This text has been bolded and italicized ', - '\nThis is an h1\nThis is an h2\nThis text has been bolded and italicized\n' - ); - - test( - 'ods', - 'ods.ods', - 'This,is,a,ods Really,it,is, I,promise,, ', - 'This,is,a,ods\nReally,it,is,\nI,promise,,\n' - ); - - test( - 'xml', - 'xml.xml', - ' Empire Burlesque Bob Dylan USA Columbia 10.90 1985 Hide your heart Bonnie Tyler UK CBS Records 9.90', - '\nEmpire Burlesque\nBob Dylan\nUSA\nColumbia\n10.90\n1985\nHide your heart\nBonnie Tyler\nUK\nCBS Records\n9.90' - ); - - test( - 'odt', - 'odt.odt', - 'This is an ODT THIS IS A HEADING More ODT', - 'This is an ODT\nTHIS IS A HEADING\nMore ODT' - ); - - test( - 'potx', - 'potx.potx', - 'This is a potx template Yep, a potx I had no idea These were even a thing ', - 'This is a potx template\nYep, a potx\nI had no idea \nThese were even a thing\n' - ); - - test( - 'xltx', - 'xltx.xltx', - ',,,,,, Packing Slip ,Your Company Name,,,,"July 24, 2015", , Your Company Slogan,,,,, ,,,,,, ,Addres', - ',,,,,, Packing Slip\n,Your Company Name,,,,"July 24, 2015",\n, Your Company Slogan,,,,,\n,,,,,,\n,Addres' - ); - - test( - 'ott', - 'ott.ott', - 'This is a document template, yay templates! Woo templates get me so excited!', - 'This is a document template, yay templates!\nWoo templates get me so excited!' - ); - - test( - 'ots', - 'ots.ots', - "This,is , template, an,open,office,template isn't,it,awesome?, you,know,it,is ", - "This,is , template,\nan,open,office,template\nisn't,it,awesome?,\nyou,know,it,is\n" - ); - - test( - 'odg', - 'odg.odg', - "This is a drawing? A drawing, a drawing! This is a drawing, Aren't you mad envious?", - "This is a drawing?\nA drawing, a drawing!\nThis is a drawing,\nAren't you mad envious?" - ); - - test( - 'otg', - 'otg.otg', - 'This is a drawing template A drawing template. Who would really ever need to extract from one of the', - 'This is a drawing template\nA drawing template.\nWho would really ever need to extract from one of the' - ); - - test( - 'odp', - 'odp.odp', - "This is a title This is a slide's text This is a 2nd page And a 2nd page's content", - "This is a title\nThis is a slide's text\nThis is a 2nd page\nAnd a 2nd page's content" - ); - - test( - 'otp', - 'otp.otp', - 'This is a template title Template page text 2nd prezo text', - 'This is a template title\nTemplate page text\n2nd prezo text' - ); -}); diff --git a/test/files/js.js b/test/files/js.js index 647a3b8..27cc79c 100644 --- a/test/files/js.js +++ b/test/files/js.js @@ -1 +1 @@ -console.log("javascript is cooler than you") \ No newline at end of file +console.log('javascript is cooler than you'); diff --git a/test/files/notadxf.dxf b/test/files/notadxf.dxf deleted file mode 100644 index aa0665e..0000000 --- a/test/files/notadxf.dxf +++ /dev/null @@ -1 +0,0 @@ -this is not a dxf diff --git a/test/general.test.ts b/test/general.test.ts new file mode 100644 index 0000000..6daacb8 --- /dev/null +++ b/test/general.test.ts @@ -0,0 +1,27 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { describe, it, expect } from 'vitest'; +import { extractFromBuffer } from '../lib/index.js'; + +describe('textract', () => { + it('fromBufferWithMime(mimeType, buffer, options)', async () => { + const filePath = path.join(__dirname, 'files', 'new docx(1).docx'); + const textBuff = fs.readFileSync(filePath); + const text = await extractFromBuffer( + textBuff, + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + {}, + ); + expect(text.substring(0, 20)).toEqual('This is a test Just '); + }); + + it('fromBufferWithMime(mimeType, buffer)', async () => { + const filePath = path.join(__dirname, 'files', 'new docx(1).docx'); + const textBuff = fs.readFileSync(filePath); + const text = await extractFromBuffer( + textBuff, + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + ); + expect(text.substring(0, 20)).toEqual('This is a test Just '); + }); +}); diff --git a/test/general_test.js b/test/general_test.js deleted file mode 100644 index 8b4a9b7..0000000 --- a/test/general_test.js +++ /dev/null @@ -1,200 +0,0 @@ -/* eslint-disable max-len, no-unused-expressions */ -/* global textract, fromFileWithPath, fromFileWithMimeAndPath, fromBufferWithName, fromBufferWithMime, fromUrl */ - -var path = require( 'path' ) - , fs = require( 'fs' ) - ; - -describe( 'textract', function() { - it( 'should be an object', function() { - expect( textract ).to.be.an.instanceof( Object ); - }); - - it( 'properties should be functions', function() { - expect( typeof fromFileWithPath ).to.eql( 'function' ); - expect( typeof fromFileWithMimeAndPath ).to.eql( 'function' ); - expect( typeof fromBufferWithName ).to.eql( 'function' ); - expect( typeof fromBufferWithMime ).to.eql( 'function' ); - expect( typeof fromUrl ).to.eql( 'function' ); - }); - - describe( 'will error out gracefully', function() { - it( 'when file does not exist', function( done ) { - var filePath = 'foo/bar/foo.txt'; - fromFileWithPath( filePath, function( error, text ) { - expect( text ).to.be.null; - expect( error ).to.be.an( 'object' ); - expect( error.message ).to.be.an( 'string' ); - expect( error.message ).to.eql( 'File at path [[ ' + filePath + ' ]] does not exist.' ); - done(); - }); - }); - - it( 'when file has unregistered mime type', function( done ) { - var filePath = path.join( __dirname, 'files', 'MxAgCrProd.ppt' ); - fromFileWithPath( filePath, function( error, text ) { - expect( text ).to.be.null; - expect( error ).to.be.an( 'object' ); - expect( error.message ).to.be.an( 'string' ); - expect( error.typeNotFound ).to.be.true; - expect( error.message.substring( 0, 61 ) ).to.eql( 'Error for type: [[ application/vnd.ms-powerpoint ]], file: [[' ); - done(); - }); - }); - }); - - it( 'can handle types of varying cases', function( done ) { - var filePath = path.join( __dirname, 'files', 'new docx(1).docx' ); - fromFileWithMimeAndPath( 'appLication/vnd.openXMLformats-Officedocument.WordProcessingml.Document', filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 38 ) ).to.eql( 'This is a test Just so you know: Lorem' ); - done(); - }); - }); - - it( 'can handle a text file with parens', function( done ) { - var filePath = path.join( __dirname, 'files', 'new doc(1).txt' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'text!!!' ); - done(); - }); - }); - - it( 'can handle a docx file with parens', function( done ) { - var filePath = path.join( __dirname, 'files', 'new docx(1).docx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 20 ) ).to.eql( 'This is a test Just ' ); - done(); - }); - }); - - it( 'can handle cyrillic', function( done ) { - var filePath = path.join( __dirname, 'files', 'cyrillic.docx' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( 'Актуальность диссертационного исследования определяется необходимостью развития методологического об' ); - done(); - }); - }); - - it( 'can handle special chinese characters', function( done ) { - var filePath = path.join( __dirname, 'files', 'chi.txt' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( ',卧虎藏龙卧' ); - done(); - }); - }); - - describe( 'with multi line files', function() { - it( 'strips line breaks', function( done ) { - var filePath = path.join( __dirname, 'files', 'multi-line.txt' ); - fromFileWithPath( filePath, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'This file has a bunch of line breaks in it, and it also has some useful punctuation.' ); - done(); - }); - }); - - it( 'does not strip line breaks when configured as such', function( done ) { - var filePath = path.join( __dirname, 'files', 'multi-line.txt' ); - fromFileWithPath( filePath, { preserveLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'This file\nhas a bunch\nof line breaks\nin it, and it also\nhas some useful\npunctuation.' ); - done(); - }); - }); - - it( 'will only strip single line breaks when requested', function( done ) { - var filePath = path.join( __dirname, 'files', 'line-breaks.txt' ); - fromFileWithPath( filePath, { preserveOnlyMultipleLineBreaks: true }, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text ).to.eql( 'This is a text file\n\nthat has a combination of multiple\n\n\n\nand single line breaks, for use when testing the preserveOnlyMultipleLineBreaks option that keeps only\n\n\nmultiple line breaks.' ); - done(); - }); - }); - }); - - describe( 'can handle all the different API variations', function() { - var test = function( done ) { - return function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.a( 'string' ); - expect( text.substring( 0, 20 ) ).to.eql( 'This is a test Just ' ); - done(); - }; - }; - - it( 'fromFileWithPath(filePath, callback) ', function( done ) { - var filePath = path.join( __dirname, 'files', 'new docx(1).docx' ); - fromFileWithPath( filePath, test( done ) ); - }); - - it( 'fromFileWithPath(filePath, options, callback) ', function( done ) { - var filePath = path.join( __dirname, 'files', 'new docx(1).docx' ); - fromFileWithPath( filePath, {}, test( done ) ); - }); - - it( 'fromFileWithMimeAndPath(mimeType, filePath, callback)', function( done ) { - var filePath = path.join( __dirname, 'files', 'new docx(1).docx' ); - fromFileWithMimeAndPath( 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', filePath, test( done ) ); - }); - - it( 'fromFileWithMimeAndPath(mimeType, filePath, options, callback)', function( done ) { - var filePath = path.join( __dirname, 'files', 'new docx(1).docx' ); - fromFileWithMimeAndPath( 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', filePath, {}, test( done ) ); - }); - - it( 'fromBufferWithMime(mimeType, buffer, options, callback)', function( done ) { - var filePath = path.join( __dirname, 'files', 'new docx(1).docx' ) - , textBuff = fs.readFileSync( filePath ) - ; - - fromBufferWithMime( 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', textBuff, {}, test( done ) ); - }); - - it( 'fromBufferWithMime(mimeType, buffer, callback)', function( done ) { - var filePath = path.join( __dirname, 'files', 'new docx(1).docx' ) - , textBuff = fs.readFileSync( filePath ) - ; - - fromBufferWithMime( 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', textBuff, test( done ) ); - }); - - it( 'fromBufferWithName(fileName, buffer, options, callback)', function( done ) { - var filePath = path.join( __dirname, 'files', 'new docx(1).docx' ) - , textBuff = fs.readFileSync( filePath ) - ; - - fromBufferWithName( filePath, textBuff, {}, test( done ) ); - }); - - it( 'fromBufferWithName(fileName, buffer, callback)', function( done ) { - var filePath = path.join( __dirname, 'files', 'new docx(1).docx' ) - , textBuff = fs.readFileSync( filePath ) - ; - - fromBufferWithName( filePath, textBuff, test( done ) ); - }); - - it( 'fromUrl(url, options, callback)', function( done ) { - var url = 'https://cdn.rawgit.com/dbashford/textract/master/test/files/new%20docx(1).docx?raw=true'; - fromUrl( url, {}, test( done ) ); - }); - - it( 'fromUrl1(url,callback)', function( done ) { - var url = 'https://cdn.rawgit.com/dbashford/textract/master/test/files/new%20docx(1).docx?raw=true'; - fromUrl( url, test( done ) ); - }); - }); -}); diff --git a/test/invalid_calls_test.js b/test/invalid_calls_test.js deleted file mode 100644 index 3375170..0000000 --- a/test/invalid_calls_test.js +++ /dev/null @@ -1,87 +0,0 @@ -/* global fromUrl */ - -var test = function( done ) { - return function( error, text ) { - expect( text ).to.be.null; - expect( error ).to.be.an( 'object' ); - expect( error.message ).to.be.an( 'string' ); - expect( error.message ).to.eql( 'Incorrect parameters passed to textract.' ); - done(); - }; -}; - -var pathTests = function( testFunction ) { - - var funct; - - beforeEach( function() { - funct = testFunction(); - }); - - it( 'should return an error 1', function( done ) { - funct( test( done ) ); - }); - - it( 'should return an error 2', function( done ) { - funct( false, test( done ) ); - }); - - it( 'should return an error 3', function( done ) { - funct( test( done ), false ); - }); - - it( 'should return an error 4', function( done ) { - funct( 'foo', test( done ), false ); - }); - - it( 'should return an error 5', function( done ) { - funct( 'foo', {}, false, test( done ) ); - }); -}; - -var bufferTests = function( testFunction ) { - - var funct; - - beforeEach( function() { - funct = testFunction(); - }); - - it( 'should return an error 1', function( done ) { - funct( test( done ) ); - }); - - it( 'should return an error 2', function( done ) { - funct( false, test( done ) ); - }); - - it( 'should return an error 3', function( done ) { - funct( test( done ), false ); - }); - - it( 'should return an error 4', function( done ) { - funct( 'foo', test( done ), false ); - }); - - it( 'should return an error 5', function( done ) { - funct( 'foo', {}, false, test( done ) ); - }); -}; - -describe( 'when passed incorrect parameters', function() { - describe( 'fromFileWithPath', function() { - pathTests( function() { return global.fromFileWithPath; }, false ); - }); - - describe( 'fromFileWithMimeAndPath', function() { - pathTests( function() { return global.fromFileWithMimeAndPath; }, false ); - }); - - describe( 'fromBufferWithName', function() { - bufferTests( function() { return global.fromBufferWithName; }, false ); - }); - - describe( 'fromBufferWithMime', function() { - bufferTests( function() { return global.fromBufferWithMime; }, false ); - }); -}); diff --git a/test/pdf-text-extract/data/huge.pdf b/test/pdf-text-extract/data/huge.pdf new file mode 100644 index 0000000..d11fada Binary files /dev/null and b/test/pdf-text-extract/data/huge.pdf differ diff --git a/test/pdf-text-extract/data/multipage.pdf b/test/pdf-text-extract/data/multipage.pdf new file mode 100644 index 0000000..e098bdc Binary files /dev/null and b/test/pdf-text-extract/data/multipage.pdf differ diff --git a/test/pdf-text-extract/data/multipage.txt b/test/pdf-text-extract/data/multipage.txt new file mode 100644 index 0000000..cf95e31 --- /dev/null +++ b/test/pdf-text-extract/data/multipage.txt @@ -0,0 +1,160 @@ +SERVICE FOR + +UMASS LOWELL 1003 WESTFORD ST APT 20 LOWELL MA 01851 + +BILLING PERIOD + +PAGE + +1 of 2 + +Jan 2, 2013 to Jan 30, 2013 +ACCOUNT NUMBER + +00604-57016 +www.nationalgrid.com +CUSTOMER SERVICE + +Mar 28, 2013 + +$ 441.84 + +ACCOUNT BALANCE +Previous Balance Payment Received on JAN 22 ( Check ) Balance Forward Current Charges Amount Due 371.38 - 145.00 226.38 + 215.46 $ 441.84 + +1-800-322-3223 +CREDIT DEPARTMENT + +1-888-211-1313 +POWER OUTAGE OR DOWNED LINE + +1-800-465-1212 +EMAIL BILLING INQUIRES customerservice@us.ngrid.com CORRESPONDENCE ADDRESS + +PO Box 960 Northborough, MA 01532-0960 +ELECTRIC PAYMENT ADDRESS + +PO Box 11737 Newark, NJ 07101-4737 +DATE BILL ISSUED + +Market Settlement Credit represents disbursement of a fund established for the benefit of electricity energy consumers in accordance with a Federal Energy Regulatory Commission approved agreement between its Office of Enforcement and Constellation Energy Commodities Group, Inc. STAY INFORMED DURING A STORM: Text the word STORM to NGRID (64743) to register for broadcast text alerts. For more information, visit nationalgridus.com/ stormnotifications. DETAIL OF CURRENT CHARGES Delivery Services +Service Period No. of days Current Reading Previous Reading = Total Usage + +Feb 1, 2013 + +Jan 2 - Jan 30 METER NUMBER 87004455 +RATE + +28 + +70870 + +Actual + +69300 + +Actual + +1570 kWh + +NEXT SCHEDULED READ DATE + +Mar 4 + +Residential Regular R-1 Customer Charge Market Settlement Credit -0.00191 x 1570 kWh 0.03257 x 600 kWh 0.03919 x 970 kWh 0.00069 x 1570 kWh 0.01738 x 1570 kWh 0.00822 x 1570 kWh 0.0005 x 1570 kWh +Total Delivery Services + +4.00 -3.00 19.54 38.02 1.08 27.29 12.91 0.79 +$ 100.63 + +ELECTRIC USAGE HISTORY (kWh) +1650 1320 990 660 330 0 OND J F 12 Daily Averages kWh Cost Feb 13 56.1 $ 7.69 + +Dist Chg First 600 KWH Dist Chg Next 970 KWH Transition Charge Transmission Charge Energy Efficiency Chg Renewable Energy Chg + +Actual + +Estimated + +KEEP THIS PORTION FOR YOUR RECORDS. RETURN THIS PORTION WITH YOUR PAYMENT. + +ACCOUNT NUMBER + +00604-57016 +PO Box 960 Northborough MA 01532 + +Mar 28, 2013 + +$ 441.84 +ENTER AMOUNT ENCLOSED + +$ +Write account number on check and make payable to National Grid + +*AUTO**SCH 5-DIGIT 01851 UMASS LOWELL 1 UNIVERSITY AVE LOWELL MA 01854-2827 + +Please pay Gas & Electric bills separately + +047848 + +NATIONAL GRID PO BOX 11737 NEWARK NJ 07101-4737 + + SERVICE FOR + +BILLING PERIOD + +UMASS LOWELL 1003 WESTFORD ST APT 20 LOWELL MA 01851 + +PAGE + +2 of 2 + +Jan 2, 2013 to Jan 30, 2013 +ACCOUNT NUMBER + +00604-57016 +Enrollment Information To enroll with a supplier or change to another supplier, you will need the following information about your account: Loadzone WCMA Acct No: 00604-57016 Cycle: 3, LOWE Electric Usage History Month Oct 12 Nov 12 Dec 12 Jan 13 Feb 13 kWh 528 523 1045 1627 1570 + +Mar 28, 2013 + +$ 441.84 + +Supply Services +SUPPLIER + +National Grid + +Basic Service Fixed + +0.07314 x 1570 kWh +Total Supply Services + +114.83 +$ 114.83 + +Payment Plans are Available for Four or More Months. Please Contact Us at 1-888-211-1313. Aviso importante! Si usted no entiende este aviso, llame a la compania al: 1-800-322-3223. + +Explanation of General Billing Terms +KWH: Kilowatt-hour, a basic unit of electricity used. Off-Peak: Period of time when the need or demand for electricity on the Company's system is low, such as late evenings, weekends and holidays. Peak: Period of time when the need or demand for electricity on the Company's system is high, normally during the day, Monday through Friday, excluding holidays. Estimated Bill: A bill which is calculated based on your typical monthly usage rather than on an actual meter reading. It is usually rendered when we are unable to read your meter. Meter Multiplier: A number by which the usage on certain meters must be multiplied by to obtain the total usage. Demand Charge: The cost of providing electrical transmission and distribution equipment to accommodate your largest electrical load. + +Delivery Service Charges are comprised of: +Customer Charge: The cost of providing customer related service such as metering, meter reading and billing. These fixed costs are unaffected by the actual amount of electricity you use. Distribution Charge: The cost of delivering electricity from the beginning of the Company's distribution system to your home or business. Transition Charge: Company payments to its wholesale supplier for terminating its wholesale arrangements. Transmission Charge: The cost of delivering electricity from the generation company to the beginning of the Company's distribution system. Energy Efficiency Charge: The cost of energy efficiency program services offered by the Company. Renewable Energy Charge: A charge to fund initiatives for communicating the benefits of renewable energy and fostering formation, growth, expansion and retention of renewable energy and related enterprises. + +Right to Dispute Your Bill +If you believe your bill is inaccurate or you wish to dispute all or part of your bill, please contact: National Grid at 1-800- 322-3223 and request an investigation by a Company Complaint Officer. If you are not satisfied with the written decision or did not receive a written decision within 30 days, you have the right to appeal to the Massachusetts Department of Public Utilities, Consumer Division, One South Station, Boston, MA 02110. Telephone 617-737-2836 or 1-877-886-5066. + +Supplier Service Charges are comprised of: +Generation Charge: The charge(s) to provide electricity and other services to the customer by a supplier. + +Department of Public Utilities +DPU regulations provide that a company may not terminate electric service for failure to pay any portion of a bill when a customer complaint or appeal is pending. + +Right To Electric Service +If you have a financial hardship you (or anyone presently and normally living in your home) have a Right to Electric Service in the following situations: During serious illness: Contact your physician or Board of Health and have them telephone the Company immediately at 1-888-211-1313. Within seven (7) days of the phone call your physician or Board of Health must certify in writing, to the Company, that serious illness exists. The certificate protects against termination for 90 days (180 days if chronic illness) and may be renewed. Your failure to renew such certification of serious illness as set out above may result in your service being terminated. You have a child under twelve monthsold living in that home. Between November 15 and March 15 if your service is heat related. Elderly Household: If all residents in your household are 65 years of age or older; or a minor (under the age of 18), the Company can not terminate your service for failure to pay a past due bill without the approval of the Massachusetts Department of Public Utilities (DPU). For additional information on the right to electric service, please contact our Credit Department at 1-888-211-1313. + +Arrearage Management Program (AMP) +AMP provides arrears forgiveness to income-qualified residential customers. Participants must accept and stay current with monthly Budget Billing payments. For complete details and an application, visit www.nationalgridus.com or call the number on the front. + +Questions: If you have questions or complaints regarding this bill or National Grid's service quality, please contact Customer Service at 1-800-322-3223. You may also contact the Massachusetts Department of Public Utilities, Consumer Division at 617-737-2836 or toll free at 1-877-886-5066 or web site www.mass.gov/dpu. + + diff --git a/test/pdf-text-extract/data/pdf with space in name.pdf b/test/pdf-text-extract/data/pdf with space in name.pdf new file mode 100644 index 0000000..d1f00cd Binary files /dev/null and b/test/pdf-text-extract/data/pdf with space in name.pdf differ diff --git a/test/pdf-text-extract/extract.test.ts b/test/pdf-text-extract/extract.test.ts new file mode 100644 index 0000000..1c51c43 --- /dev/null +++ b/test/pdf-text-extract/extract.test.ts @@ -0,0 +1,55 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { describe, it, expect } from 'vitest'; +import { pdfTextExtract } from '../../lib/pdf-text-extract/index.js'; + +const DIR = fileURLToPath(path.dirname(import.meta.url)); + +describe('Pdf extract', () => { + it('should return output and no error when everything is ok', async () => { + const desiredNumPages = 8; + const filePath = path.join(DIR, 'data', 'multipage.pdf'); + const pages = await pdfTextExtract(filePath); + + expect(pages.length).toBe(desiredNumPages); + for (const page of pages) { + expect(page).toBeDefined(); + expect(page.length).toBeGreaterThan(0); + } + }); + + it('should accept files with space in name', async () => { + const filePath = path.join(DIR, 'data', 'pdf with space in name.pdf'); + const pages = await pdfTextExtract(filePath); + expect(pages.length).toBeGreaterThan(0); + }); + + it('should work with parallel data streams', async () => { + const filePath = path.join(DIR, 'data', 'pdf with space in name.pdf'); + + const promises = Array.from({ length: 10 }, () => pdfTextExtract(filePath)); + const pagesGroups = await Promise.all(promises); + expect(pagesGroups.length).toBe(10); + for (const pages of pagesGroups) { + expect(pages).toBeDefined(); + expect(pages.length).toBeGreaterThan(0); + expect(pages[0]).toBeDefined(); + } + }); + + it('should allow large files', { timeout: 5000 }, async () => { + const filePath = path.join(DIR, 'data', 'huge.pdf'); + + const pages = await pdfTextExtract(filePath, { + cwd: null, + }); + expect(pages.length).toBeGreaterThan(0); + }); + + it('should support custom pdftotext command', async () => { + const filePath = path.join(DIR, 'data', 'multipage.pdf'); + const pdfToTextCommand = 'pdftotext'; + const pages = await pdfTextExtract(filePath, {}, pdfToTextCommand); + expect(pages.length).toBeGreaterThan(0); + }); +}); diff --git a/test/url_test.js b/test/url_test.js deleted file mode 100644 index ca21fa1..0000000 --- a/test/url_test.js +++ /dev/null @@ -1,160 +0,0 @@ -/* eslint-disable max-len, no-unused-expressions */ -/* global fromUrl */ - -var nodeUrl = require( 'url' ); - -describe( 'fromUrl tests', function() { - var test; - - this.timeout( 3000 ); - - it( 'will properly extract files from sites with extensions that are misleading', function( done ) { - var url = 'http://apps.leg.wa.gov/billinfo/summary.aspx?bill=1276'; - fromUrl( url, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( - ' Washington State Legislature Bill Summary 2017-2018 2015-2016 2013-2014 2011-2012 2009-2010 2007-20' ); - done(); - }); - }); - - it( 'take object URL', function( done ) { - var url = 'https://cdn.rawgit.com/dbashford/textract/master/test/files/doc.doc?raw=true' - , urlObj = nodeUrl.parse( url ) - ; - - fromUrl( urlObj, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( ' Word Specification Sample Working Draft 04, 16 August 2002 Document identifier: wd-spectools-word-s' ); - done(); - }); - }); - - test = function( ext, name, _text ) { - it( 'will ' + ext + ' files', function( done ) { - var url = 'https://cdn.rawgit.com/dbashford/textract/master/test/files/' + name + '?raw=true'; - fromUrl( url, function( error, text ) { - expect( error ).to.be.null; - expect( text ).to.be.an( 'string' ); - expect( text.substring( 0, 100 ) ).to.eql( _text ); - done(); - }); - }); - }; - - test( - 'doc', - 'doc.doc', - ' Word Specification Sample Working Draft 04, 16 August 2002 Document identifier: wd-spectools-word-s' - ); - - test( - 'xls', - 'test.xls', - 'This,is,a,spreadsheet,yay! ' - ); - - test( - 'xlsx', - 'pi.xlsx', - 'This is the value of PI:,3.141592 ' - ); - - test( - 'pdf', - 'pdf.pdf', - 'This is a test. Please ignore.' - ); - - test( - 'docx', - 'docx.docx', - 'This is a test Just so you know: Lorem ipsum dolor sit amet, consecutuer adipiscing elit, sed diam n' - ); - - test( - 'text/*', - 'txt.txt', - 'This is a plain old text file.' - ); - - test( - 'pptx', - 'ppt.pptx', - 'This is some title Text And a sub-title Text in Lists Bullet 1 Bullet 2 Bullet 3 Number 1 Number 2 N' - ); - - test( - 'markdown', - 'test.md', - ' This is an h1 This is an h2 This text has been bolded and italicized ' - ); - - test( - 'ods', - 'ods.ods', - 'This,is,a,ods Really,it,is, I,promise,, ' - ); - - test( - 'xml', - 'xml.xml', - ' Empire Burlesque Bob Dylan USA Columbia 10.90 1985 Hide your heart Bonnie Tyler UK CBS Records 9.90' - ); - - test( - 'odt', - 'odt.odt', - 'This is an ODT THIS IS A HEADING More ODT' - ); - - test( - 'potx', - 'potx.potx', - 'This is a potx template Yep, a potx I had no idea These were even a thing ' - ); - - test( - 'xltx', - 'xltx.xltx', - ',,,,,, Packing Slip ,Your Company Name,,,,"July 24, 2015", , Your Company Slogan,,,,, ,,,,,, ,Addres' - ); - - test( - 'ott', - 'ott.ott', - 'This is a document template, yay templates! Woo templates get me so excited!' - ); - - test( - 'ots', - 'ots.ots', - "This,is , template, an,open,office,template isn't,it,awesome?, you,know,it,is " - ); - - test( - 'odg', - 'odg.odg', - "This is a drawing? A drawing, a drawing! This is a drawing, Aren't you mad envious?" - ); - - test( - 'otg', - 'otg.otg', - 'This is a drawing template A drawing template. Who would really ever need to extract from one of the' - ); - - test( - 'odp', - 'odp.odp', - "This is a title This is a slide's text This is a 2nd page And a 2nd page's content" - ); - - test( - 'otp', - 'otp.otp', - 'This is a template title Template page text 2nd prezo text' - ); -}); diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..cceb8db --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "outDir": "${configDir}/dist", + "declaration": true, + "declarationMap": true + }, + "include": ["lib/**/*.ts"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8c186a7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "noEmit": true, + "lib": ["ES2023"], + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "nodenext", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": true, + "declaration": false, + "removeComments": true, + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "incremental": true, + "noImplicitReturns": true, + "isolatedModules": true + }, + "include": ["lib/**/*.ts", "test/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index d455286..0000000 --- a/yarn.lock +++ /dev/null @@ -1,1572 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@types/node@*": - version "10.5.5" - resolved "https://registry.npmjs.org/@types/node/-/node-10.5.5.tgz#8e84d24e896cd77b0d4f73df274027e3149ec2ba" - -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - dependencies: - acorn "^3.0.4" - -acorn@^3.0.4, acorn@^3.1.0: - version "3.3.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - -adler-32@: - version "1.2.0" - resolved "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz#6a3e6bf0a63900ba15652808cb15c6813d1a5f25" - dependencies: - exit-on-epipe "~1.0.1" - printj "~1.1.0" - -adm-zip@^0.4.4: - version "0.4.11" - resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.11.tgz#2aa54c84c4b01a9d0fb89bb11982a51f13e3d62a" - -ajv-keywords@^1.0.0: - version "1.5.1" - resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" - -ajv@^4.7.0: - version "4.11.8" - resolved "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - dependencies: - sprintf-js "~1.0.2" - -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - dependencies: - array-uniq "^1.0.1" - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - -arrify@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - -babyparse@0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/babyparse/-/babyparse-0.2.1.tgz#069f035df3fdce6f3a455dd5dafc75178dcf3760" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -bluebird@^3.5.1: - version "3.5.1" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" - -boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - -builtin-modules@^1.0.0, builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - dependencies: - callsites "^0.2.0" - -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - -capture-stack-trace@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" - -cfb@>=0.10.0: - version "1.0.5" - resolved "https://registry.npmjs.org/cfb/-/cfb-1.0.5.tgz#5f7cf2fcb385dd41db271cf1f28a83fcd705bf06" - dependencies: - commander "^2.14.1" - printj "~1.1.2" - -cfb@~0.11.0: - version "0.11.1" - resolved "https://registry.npmjs.org/cfb/-/cfb-0.11.1.tgz#a96db8f272a6c3fb99dbbb23ef41223f48be1ea7" - dependencies: - commander "" - -chai@1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/chai/-/chai-1.5.0.tgz#9afa2003cfcb732896f829568ee308a67cbeccf0" - -chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -cheerio@1.0.0-rc.2: - version "1.0.0-rc.2" - resolved "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db" - dependencies: - css-select "~1.2.0" - dom-serializer "~0.1.0" - entities "~1.1.1" - htmlparser2 "^3.9.1" - lodash "^4.15.0" - parse5 "^3.0.1" - -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - dependencies: - restore-cursor "^1.0.1" - -cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -codepage@: - version "1.12.2" - resolved "https://registry.npmjs.org/codepage/-/codepage-1.12.2.tgz#fd4424448c8bf1db5d7e01f9ecf9e8346582a195" - dependencies: - commander "~2.14.1" - exit-on-epipe "~1.0.1" - -codepage@~1.3.6: - version "1.3.8" - resolved "https://registry.npmjs.org/codepage/-/codepage-1.3.8.tgz#4f2e5d7c0975de28f88498058dcb5afcab6a5f71" - dependencies: - commander "" - concat-stream "" - voc "" - -colors@0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" - -commander@, commander@^2.14.1: - version "2.15.1" - resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - -commander@0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" - -commander@~2.14.1: - version "2.14.1" - resolved "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -concat-stream@, concat-stream@^1.4.6: - version "1.6.1" - resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.1.tgz#261b8f518301f1d834e36342b9fea095d2620a26" - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -crc-32@: - version "1.2.0" - resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" - dependencies: - exit-on-epipe "~1.0.1" - printj "~1.1.0" - -create-error-class@^3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" - dependencies: - capture-stack-trace "^1.0.0" - -css-select@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" - dependencies: - boolbase "~1.0.0" - css-what "2.1" - domutils "1.5.1" - nth-check "~1.0.1" - -css-what@2.1: - version "2.1.0" - resolved "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" - -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - dependencies: - array-find-index "^1.0.1" - -d@1: - version "1.0.0" - resolved "https://registry.npmjs.org/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - dependencies: - es5-ext "^0.10.9" - -damerau-levenshtein@^1.0.0: - version "1.0.4" - resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" - -debug@*: - version "3.1.0" - resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - dependencies: - ms "2.0.0" - -debug@^2.1.1, debug@^2.2.0: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - -decamelize@^1.1.2: - version "1.2.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - -del@^2.0.2: - version "2.2.2" - resolved "https://registry.npmjs.org/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - dependencies: - globby "^5.0.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - rimraf "^2.2.8" - -diff@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-1.0.2.tgz#4ae73f1aee8d6fcf484f1a1ce77ce651d9b7f0c9" - -doctrine@1.3.x: - version "1.3.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.3.0.tgz#13e75682b55518424276f7c173783456ef913d26" - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -doctrine@^1.2.2: - version "1.5.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -dom-serializer@0, dom-serializer@~0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" - dependencies: - domelementtype "~1.1.1" - entities "~1.1.1" - -domelementtype@1, domelementtype@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" - -domelementtype@~1.1.1: - version "1.1.3" - resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" - -domhandler@^2.3.0: - version "2.4.1" - resolved "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz#892e47000a99be55bbf3774ffea0561d8879c259" - dependencies: - domelementtype "1" - -domutils@1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" - dependencies: - dom-serializer "0" - domelementtype "1" - -domutils@^1.5.1: - version "1.7.0" - resolved "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - dependencies: - dom-serializer "0" - domelementtype "1" - -duplexer2@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" - dependencies: - readable-stream "^2.0.2" - -entities@^1.1.1, entities@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" - -epub2@1.3.4: - version "1.3.4" - resolved "https://registry.npmjs.org/epub2/-/epub2-1.3.4.tgz#711fa98f07a99e3dbaba6878cc53b182ca42d436" - dependencies: - adm-zip "^0.4.4" - bluebird "^3.5.1" - xml2js "^0.4.4" - -error-ex@^1.2.0: - version "1.3.1" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" - dependencies: - is-arrayish "^0.2.1" - -es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.41" - resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.41.tgz#bab3e982d750f0112f0cb9e6abed72c59eb33eb2" - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.1" - next-tick "1" - -es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-map@^0.1.3: - version "0.1.5" - resolved "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - -es6-set@^0.1.4, es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - -es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - dependencies: - d "1" - es5-ext "~0.10.14" - -es6-weak-map@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" - dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-config-airbnb-base@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-3.0.1.tgz#b777e01f65e946933442b499fc8518aa251a6530" - -eslint-config-airbnb@^9.0.1: - version "9.0.1" - resolved "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-9.0.1.tgz#6708170d5034b579d52913fe49dee2f7fec7d894" - dependencies: - eslint-config-airbnb-base "^3.0.0" - -eslint-import-resolver-node@^0.2.0: - version "0.2.3" - resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c" - dependencies: - debug "^2.2.0" - object-assign "^4.0.1" - resolve "^1.1.6" - -"eslint-plugin-import@^1.7.0 ": - version "1.16.0" - resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-1.16.0.tgz#b2fa07ebcc53504d0f2a4477582ec8bff1871b9f" - dependencies: - builtin-modules "^1.1.1" - contains-path "^0.1.0" - debug "^2.2.0" - doctrine "1.3.x" - es6-map "^0.1.3" - es6-set "^0.1.4" - eslint-import-resolver-node "^0.2.0" - has "^1.0.1" - lodash.cond "^4.3.0" - lodash.endswith "^4.0.1" - lodash.find "^4.3.0" - lodash.findindex "^4.3.0" - minimatch "^3.0.3" - object-assign "^4.0.1" - pkg-dir "^1.0.0" - pkg-up "^1.0.0" - -eslint-plugin-jsx-a11y@^1.2.0: - version "1.5.5" - resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-1.5.5.tgz#da284a016c1889e73698180217e2eb988a98bab5" - dependencies: - damerau-levenshtein "^1.0.0" - jsx-ast-utils "^1.0.0" - object-assign "^4.0.1" - -eslint-plugin-react@^5.1.1: - version "5.2.2" - resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-5.2.2.tgz#7db068e1f5487f6871e4deef36a381c303eac161" - dependencies: - doctrine "^1.2.2" - jsx-ast-utils "^1.2.1" - -eslint@2.11.1: - version "2.11.1" - resolved "https://registry.npmjs.org/eslint/-/eslint-2.11.1.tgz#fbf399ddc2d6c703abcf894219854f71e37f149b" - dependencies: - chalk "^1.1.3" - concat-stream "^1.4.6" - debug "^2.1.1" - doctrine "^1.2.2" - es6-map "^0.1.3" - escope "^3.6.0" - espree "3.1.4" - estraverse "^4.2.0" - esutils "^2.0.2" - file-entry-cache "^1.1.1" - glob "^7.0.3" - globals "^9.2.0" - ignore "^3.1.2" - imurmurhash "^0.1.4" - inquirer "^0.12.0" - is-my-json-valid "^2.10.0" - is-resolvable "^1.0.0" - js-yaml "^3.5.1" - json-stable-stringify "^1.0.0" - levn "^0.3.0" - lodash "^4.0.0" - mkdirp "^0.5.0" - optionator "^0.8.1" - path-is-absolute "^1.0.0" - path-is-inside "^1.0.1" - pluralize "^1.2.1" - progress "^1.1.8" - require-uncached "^1.0.2" - shelljs "^0.6.0" - strip-json-comments "~1.0.1" - table "^3.7.8" - text-table "~0.2.0" - user-home "^2.0.0" - -espree@3.1.4: - version "3.1.4" - resolved "https://registry.npmjs.org/espree/-/espree-3.1.4.tgz#0726d7ac83af97a7c8498da9b363a3609d2a68a1" - dependencies: - acorn "^3.1.0" - acorn-jsx "^3.0.0" - -esprima@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" - -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - dependencies: - estraverse "^4.1.0" - -estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - dependencies: - d "1" - es5-ext "~0.10.14" - -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - -exit-on-epipe@, exit-on-epipe@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" - -fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - -fd-slicer@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" - dependencies: - pend "~1.2.0" - -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - -file-entry-cache@^1.1.1: - version "1.3.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" - dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -flat-cache@^1.2.1: - version "1.3.0" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" - dependencies: - circular-json "^0.3.1" - del "^2.0.2" - graceful-fs "^4.1.2" - write "^0.2.1" - -frac@0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/frac/-/frac-0.3.1.tgz#577677b7fdcbe6faf7c461f1801d34137cda4354" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -function-bind@^1.0.2: - version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - -generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - -glob@^7.0.3, glob@^7.0.5: - version "7.1.2" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - 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" - -globals@^9.2.0: - version "9.18.0" - resolved "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - -globby@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - dependencies: - array-union "^1.0.1" - arrify "^1.0.0" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -got@5.7.1: - version "5.7.1" - resolved "https://registry.npmjs.org/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35" - dependencies: - create-error-class "^3.0.1" - duplexer2 "^0.1.4" - is-redirect "^1.0.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - lowercase-keys "^1.0.0" - node-status-codes "^1.0.0" - object-assign "^4.0.1" - parse-json "^2.1.0" - pinkie-promise "^2.0.0" - read-all-stream "^3.0.0" - readable-stream "^2.0.5" - timed-out "^3.0.0" - unzip-response "^1.0.2" - url-parse-lax "^1.0.0" - -graceful-fs@^4.1.2: - version "4.1.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - -growl@1.7.x: - version "1.7.0" - resolved "https://registry.npmjs.org/growl/-/growl-1.7.0.tgz#de2d66136d002e112ba70f3f10c31cf7c350b2da" - -harb@~0.0.5: - version "0.0.7" - resolved "https://registry.npmjs.org/harb/-/harb-0.0.7.tgz#da516f41a954ac5e17093c00185b8a789c84e09a" - dependencies: - babyparse "0.2.1" - codepage "" - commander "" - ssf "0.8.2" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - dependencies: - ansi-regex "^2.0.0" - -has@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" - dependencies: - function-bind "^1.0.2" - -hosted-git-info@^2.1.4: - version "2.6.0" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222" - -html-entities@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/html-entities/-/html-entities-1.2.0.tgz#41948caf85ce82fed36e4e6a0ed371a6664379e2" - -htmlparser2@^3.9.1: - version "3.9.2" - resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" - dependencies: - domelementtype "^1.3.0" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^2.0.2" - -iconv-lite@0.4.15: - version "0.4.15" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" - -ignore@^3.1.2: - version "3.3.7" - resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - dependencies: - repeating "^2.0.0" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -inquirer@^0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" - dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^2.0.0" - figures "^1.3.5" - lodash "^4.3.0" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" - through "^2.3.6" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - -is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - dependencies: - builtin-modules "^1.0.0" - -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - -is-my-ip-valid@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" - -is-my-json-valid@^2.10.0: - version "2.17.2" - resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz#6b2103a288e94ef3de5cf15d29dd85fc4b78d65c" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - is-my-ip-valid "^1.0.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - -is-path-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" - -is-path-in-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" - dependencies: - is-path-inside "^1.0.0" - -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - dependencies: - path-is-inside "^1.0.1" - -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - -is-redirect@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" - -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - -is-retry-allowed@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" - -is-stream@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - -isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -j@0.4.3: - version "0.4.3" - resolved "https://registry.npmjs.org/j/-/j-0.4.3.tgz#6cf643541bd9f5da2ecc61957ab1757fd22d6835" - dependencies: - commander "" - concat-stream "" - harb "~0.0.5" - xlsjs "~0.7.1" - xlsx "~0.7.11" - -jade@0.26.3: - version "0.26.3" - resolved "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" - dependencies: - commander "0.6.1" - mkdirp "0.3.0" - -js-yaml@^3.5.1: - version "3.11.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jschardet@1.4.1: - version "1.4.1" - resolved "https://registry.npmjs.org/jschardet/-/jschardet-1.4.1.tgz#5e0f8966ddbe897f6d287e2196bfe0cf3a0090ec" - -json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - -jsx-ast-utils@^1.0.0, jsx-ast-utils@^1.2.1: - version "1.4.1" - resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" - -jszip@2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/jszip/-/jszip-2.4.0.tgz#487a93b76c3bffa6cb085cd61eb934eabe2d294f" - dependencies: - pako "~0.2.5" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - -lodash.cond@^4.3.0: - version "4.5.2" - resolved "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" - -lodash.endswith@^4.0.1: - version "4.2.1" - resolved "https://registry.npmjs.org/lodash.endswith/-/lodash.endswith-4.2.1.tgz#fed59ac1738ed3e236edd7064ec456448b37bc09" - -lodash.find@^4.3.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" - -lodash.findindex@^4.3.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.findindex/-/lodash.findindex-4.6.0.tgz#a3245dee61fb9b6e0624b535125624bb69c11106" - -lodash@^4.0.0, lodash@^4.3.0: - version "4.17.5" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" - -lodash@^4.15.0: - version "4.17.10" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" - -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - -lowercase-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - -marked@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/marked/-/marked-0.6.2.tgz#c574be8b545a8b48641456ca1dbe0e37b6dccc1a" - integrity sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA== - -meow@3.7.0: - version "3.7.0" - resolved "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - -mime@2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/mime/-/mime-2.2.0.tgz#161e541965551d3b549fa1114391e3a3d55b923b" - -minimatch@^3.0.3, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^1.1.3: - version "1.2.0" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -mkdirp@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" - -mkdirp@0.3.3: - version "0.3.3" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.3.tgz#595e251c1370c3a68bab2136d0e348b8105adf13" - -mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -mocha@1.9.0: - version "1.9.0" - resolved "https://registry.npmjs.org/mocha/-/mocha-1.9.0.tgz#141054b13cb03ce5ce59aece3d65d5ca01b8df0a" - dependencies: - commander "0.6.1" - debug "*" - diff "1.0.2" - growl "1.7.x" - jade "0.26.3" - mkdirp "0.3.3" - ms "0.3.0" - -ms@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/ms/-/ms-0.3.0.tgz#03edc348d613e66a56486cfdac53bcbe899cbd61" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" - -next-tick@1: - version "1.0.0" - resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - -node-status-codes@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f" - -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: - version "2.4.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -nth-check@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" - dependencies: - boolbase "~1.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -object-assign@^4.0.1, object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -onetime@^1.0.0: - version "1.1.0" - resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - -optionator@^0.8.1: - version "0.8.2" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -pako@~0.2.5: - version "0.2.9" - resolved "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" - -parse-json@^2.1.0, parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - dependencies: - error-ex "^1.2.0" - -parse5@^3.0.1: - version "3.0.3" - resolved "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" - dependencies: - "@types/node" "*" - -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - dependencies: - pinkie-promise "^2.0.0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-is-inside@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -pdf-text-extract@1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/pdf-text-extract/-/pdf-text-extract-1.3.1.tgz#a5b232ad9850949d77c435e5f44fe0d105435840" - dependencies: - yargs "^1.2.5" - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - -pkg-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - dependencies: - find-up "^1.0.0" - -pkg-up@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26" - dependencies: - find-up "^1.0.0" - -pluralize@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - -printj@~1.1.0, printj@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" - -process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - -progress@^1.1.8: - version "1.1.8" - resolved "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" - -read-all-stream@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" - dependencies: - pinkie-promise "^2.0.0" - readable-stream "^2.0.0" - -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - -readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.2.2: - version "2.3.5" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d" - 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.0.3" - util-deprecate "~1.0.1" - -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - dependencies: - is-finite "^1.0.0" - -require-uncached@^1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - -resolve@^1.1.6: - version "1.6.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz#0fbd21278b27b4004481c395349e7aba60a9ff5c" - dependencies: - path-parse "^1.0.5" - -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - -rimraf@^2.2.8: - version "2.6.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - dependencies: - glob "^7.0.5" - -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" - dependencies: - once "^1.3.0" - -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - -"semver@2 || 3 || 4 || 5": - version "5.5.0" - resolved "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - -shelljs@^0.6.0: - version "0.6.1" - resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" - -signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" - -spdx-correct@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" - -spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - -ssf@0.8.2, ssf@~0.8.1: - version "0.8.2" - resolved "https://registry.npmjs.org/ssf/-/ssf-0.8.2.tgz#b9d4dc6a1c1bcf76f8abfa96d7d7656fb2abecd6" - dependencies: - colors "0.6.2" - frac "0.3.1" - voc "" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - dependencies: - ansi-regex "^3.0.0" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - dependencies: - is-utf8 "^0.2.0" - -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - dependencies: - get-stdin "^4.0.1" - -strip-json-comments@~1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -table@^3.7.8: - version "3.8.3" - resolved "https://registry.npmjs.org/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" - dependencies: - ajv "^4.7.0" - ajv-keywords "^1.0.0" - chalk "^1.1.1" - lodash "^4.0.0" - slice-ansi "0.0.4" - string-width "^2.0.0" - -text-table@~0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - -timed-out@^3.0.0: - version "3.1.3" - resolved "https://registry.npmjs.org/timed-out/-/timed-out-3.1.3.tgz#95860bfcc5c76c277f8f8326fd0f5b2e20eba217" - -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - dependencies: - prelude-ls "~1.1.2" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - -unzip-response@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe" - -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - dependencies: - prepend-http "^1.0.1" - -user-home@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" - dependencies: - os-homedir "^1.0.0" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -validate-npm-package-license@^3.0.1: - version "3.0.3" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -voc@: - version "1.1.0" - resolved "https://registry.npmjs.org/voc/-/voc-1.1.0.tgz#d1a08aeff66646bf17cdba2e47c935a7a9b0218b" - -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - -wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -write@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - dependencies: - mkdirp "^0.5.1" - -xlsjs@~0.7.1: - version "0.7.6" - resolved "https://registry.npmjs.org/xlsjs/-/xlsjs-0.7.6.tgz#d88754569aabcf8eea70cc23961b462634a49565" - dependencies: - cfb "~0.11.0" - codepage "" - commander "" - exit-on-epipe "" - ssf "~0.8.1" - -xlsx@~0.7.11: - version "0.7.12" - resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.7.12.tgz#7144831d8ecd49c062141f7c48975d1a400988e4" - dependencies: - adler-32 "" - cfb ">=0.10.0" - codepage "~1.3.6" - commander "" - crc-32 "" - jszip "2.4.0" - ssf "~0.8.1" - -xml2js@^0.4.4: - version "0.4.19" - resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" - dependencies: - sax ">=0.6.0" - xmlbuilder "~9.0.1" - -xmlbuilder@~9.0.1: - version "9.0.7" - resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" - -xmldom@0.1.27: - version "0.1.27" - resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" - -xpath@0.0.23: - version "0.0.23" - resolved "https://registry.npmjs.org/xpath/-/xpath-0.0.23.tgz#f5e8fdc6bdc7e72885b3234f40cba2669580aafa" - -xtend@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - -yargs@^1.2.5: - version "1.3.3" - resolved "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz#054de8b61f22eefdb7207059eaef9d6b83fb931a" - -yauzl@2.7.0: - version "2.7.0" - resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.7.0.tgz#e21d847868b496fc29eaec23ee87fdd33e9b2bce" - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.0.1"