From 53241fe4638cfbc6defa1e19cdca7adc4352cb6b Mon Sep 17 00:00:00 2001 From: Gordon Farquharson Date: Wed, 8 Apr 2026 12:44:55 +0100 Subject: [PATCH 1/8] fix: :rocket: Update packages for linting and testing. Dependabot new release with latest tooling in place --- .eslintrc.cjs | 3 - config/eslint/repo/.eslintrc.cjs | 117 - config/eslint/repo/rules/banPlugin.cjs | 23 - .../eslint/repo/rules/baseFormattingRules.cjs | 349 -- .../eslint/repo/rules/baseFormattingRules.js | 184 ++ .../{baseLogicRules.cjs => baseLogicRules.js} | 16 +- .../{baseStyleRules.cjs => baseStyleRules.js} | 70 +- config/eslint/repo/rules/importPlugin.cjs | 221 -- config/eslint/repo/rules/importPlugin.js | 167 + config/eslint/repo/rules/jestPlugin.cjs | 172 - config/eslint/repo/rules/jestPlugin.js | 135 + .../repo/rules/testingLibraryPlugin.cjs | 100 - .../eslint/repo/rules/testingLibraryPlugin.js | 68 + .../{unicornPlugin.cjs => unicornPlugin.js} | 136 +- context/CHANGELOG.md | 19 + context/CONTEXT_INDEX.md | 20 + eslint.config.js | 140 + package.json | 34 +- pnpm-lock.yaml | 2936 +++++++++-------- .../types/bytecodealliance-wizer.d.ts | 4 +- .../types/regexpu-core-regexpuc.d.ts | 4 +- .../asset-loader/inline-asset/inline-asset.ts | 1 - .../create-manifest-file-map.test.ts | 2 +- .../__tests__/create-manifest.test.ts | 2 +- src/utils/__tests__/color-log.test.ts | 4 +- src/utils/__tests__/config-helpers.test.ts | 2 +- src/utils/__tests__/content-types.test.ts | 2 +- src/utils/__tests__/deep-copy.test.ts | 2 +- src/utils/__tests__/file-info.test.ts | 2 +- src/utils/__tests__/file-system.test.ts | 3 +- src/utils/syntax-checker.ts | 20 +- 31 files changed, 2310 insertions(+), 2648 deletions(-) delete mode 100644 .eslintrc.cjs delete mode 100644 config/eslint/repo/.eslintrc.cjs delete mode 100644 config/eslint/repo/rules/banPlugin.cjs delete mode 100644 config/eslint/repo/rules/baseFormattingRules.cjs create mode 100644 config/eslint/repo/rules/baseFormattingRules.js rename config/eslint/repo/rules/{baseLogicRules.cjs => baseLogicRules.js} (94%) rename config/eslint/repo/rules/{baseStyleRules.cjs => baseStyleRules.js} (90%) delete mode 100644 config/eslint/repo/rules/importPlugin.cjs create mode 100644 config/eslint/repo/rules/importPlugin.js delete mode 100644 config/eslint/repo/rules/jestPlugin.cjs create mode 100644 config/eslint/repo/rules/jestPlugin.js delete mode 100644 config/eslint/repo/rules/testingLibraryPlugin.cjs create mode 100644 config/eslint/repo/rules/testingLibraryPlugin.js rename config/eslint/repo/rules/{unicornPlugin.cjs => unicornPlugin.js} (50%) create mode 100644 eslint.config.js diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index 9c81353..0000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: './config/eslint/repo/.eslintrc.cjs', -}; diff --git a/config/eslint/repo/.eslintrc.cjs b/config/eslint/repo/.eslintrc.cjs deleted file mode 100644 index 339546c..0000000 --- a/config/eslint/repo/.eslintrc.cjs +++ /dev/null @@ -1,117 +0,0 @@ -const ban = require('./rules/banPlugin.cjs'); -const formatting = require('./rules/baseFormattingRules.cjs'); -const logic = require('./rules/baseLogicRules.cjs'); -const style = require('./rules/baseStyleRules.cjs'); -// // Plugin configs -const importPlugin = require('./rules/importPlugin.cjs'); -const jest = require('./rules/jestPlugin.cjs'); -const testingLib = require('./rules/testingLibraryPlugin.cjs'); -const unicorn = require('./rules/unicornPlugin.cjs'); - -module.exports = { - env: { - browser: true, - es2021: true, - }, - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], - globals: { - global: 'readonly', - process: 'readonly', - fastedge: 'readonly', - }, - ignorePatterns: [ - '**/node_modules/**', - 'config/eslint/**', - 'config/jest/**', - 'docs/**', - 'esbuild/**', - 'dist/**', - 'build/**', - '**/build/**', - 'types/**', - 'integration-tests/**', - 'bin/**', - 'lib/**', - '**/runtime/fastedge/**', - '**/runtime/StarlingMonkey/**', - 'github-pages/**', - ], - plugins: [ - '@typescript-eslint', - ...ban.plugins, - ...importPlugin.plugins, - ...jest.plugins, - ...testingLib.plugins, - ...unicorn.plugins, - ], - settings: { - ...ban.settings, - ...importPlugin.settings, - ...jest.settings, - ...testingLib.settings, - ...unicorn.settings, - }, - rules: { - // "n/exports-style": ["error", "module.exports"], - ...logic.rules, - ...style.rules, - ...formatting.rules, - ...ban.rules, - ...importPlugin.rules, - ...jest.rules, - ...testingLib.rules, - ...unicorn.rules, - }, - overrides: [ - ...ban.overrides, - ...testingLib.overrides, - ...jest.overrides, - { - files: ['examples/**/*.{js,ts,tsx}'], - globals: { - FetchEvent: 'readonly', - }, - rules: { - 'import/extensions': 'off', - 'import/group-exports': 'off', - 'import/exports-last': 'off', - 'import/no-default-export': 'off', - 'import/unambiguous': 'off', - 'no-console': 'off', - 'no-return-await': 'off', - 'prefer-destructuring': 'off', - '@typescript-eslint/no-unused-vars': 'off', - }, - }, - { - files: ['**/*.d.ts'], - rules: { - // Want to define set numbers as prop values - '@typescript-eslint/no-magic-numbers': 'off', - 'no-undef': ['error', { typeof: false }], - }, - }, - { - env: { - node: true, - }, - files: ['.eslintrc.{js,cjs}'], - parserOptions: { - sourceType: 'script', - }, - }, - { - // Allow the usage of 'any' within test files. - files: ['**/*.test.{ts,tsx}', '**/*.spec.{ts,tsx}'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - }, - }, - ], - parser: '@typescript-eslint/parser', - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - warnOnUnsupportedTypeScriptVersion: false, - }, -}; diff --git a/config/eslint/repo/rules/banPlugin.cjs b/config/eslint/repo/rules/banPlugin.cjs deleted file mode 100644 index 53e83e9..0000000 --- a/config/eslint/repo/rules/banPlugin.cjs +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = { - plugins: ['ban'], - settings: {}, - rules: {}, - overrides: [ - { - files: ['*.{spec,test}.{js,jsx,ts,tsx}'], - plugins: ['ban'], - globals: { jsdom: 'readonly' }, - // env: { jest: true, "jest/globals": true, node: true }, - env: { jest: true, node: true }, - rules: { - 'ban/ban': [ - 'error', - { - name: ['expect', 'hasAssertions'], - message: 'Please use `expect.assertions(n)` instead of `expect.hasAssertions()`.', - }, - ], - }, - }, - ], -}; diff --git a/config/eslint/repo/rules/baseFormattingRules.cjs b/config/eslint/repo/rules/baseFormattingRules.cjs deleted file mode 100644 index 17266d2..0000000 --- a/config/eslint/repo/rules/baseFormattingRules.cjs +++ /dev/null @@ -1,349 +0,0 @@ -module.exports = { - rules: { - // Enforce linebreaks after opening and before closing array brackets - // https://eslint.org/docs/rules/array-bracket-newline - 'array-bracket-newline': ['error', 'consistent'], // { multiline: true, minItems: null }], - // Enforce consistent spacing inside array brackets - // https://eslint.org/docs/rules/array-bracket-spacing - 'array-bracket-spacing': [ - 'error', - 'never', - { - singleValue: false, - objectsInArrays: false, - arraysInArrays: false, - }, - ], - // Enforce line breaks after each array element - // https://eslint.org/docs/rules/array-element-newline - 'array-element-newline': ['error', 'consistent'], - // Require parentheses around arrow function arguments - // https://eslint.org/docs/rules/arrow-parens - 'arrow-parens': ['error', 'always', { requireForBlockBody: false }], - // Enforce consistent spacing before and after the arrow in arrow functions - // https://eslint.org/docs/rules/arrow-spacing - 'arrow-spacing': ['error', { before: true, after: true }], - // Disallow or enforce spaces inside of blocks after opening block and before closing - // block - // https://eslint.org/docs/rules/block-spacing - 'block-spacing': ['error', 'always'], - // Enforce consistent brace style for blocks - // https://eslint.org/docs/rules/brace-style - // Turned off in favor of @typescript-eslint/brace-style - 'brace-style': ['off', '1tbs', { allowSingleLine: true }], - // Require or disallow trailing commas - // https://eslint.org/docs/rules/comma-dangle - // Turned off in favor of @typescript-eslint/comma-dangle - 'comma-dangle': [ - 'off', - { - arrays: 'always-multiline', - objects: 'always-multiline', - imports: 'always-multiline', - exports: 'always-multiline', - functions: 'always-multiline', - }, - ], - // Enforce consistent spacing before and after commas - // https://eslint.org/docs/rules/comma-spacing - // Turned off in favor of @typescript-eslint/comma-spacing - 'comma-spacing': ['off', { before: false, after: true }], - // Enforce consistent comma style - // https://eslint.org/docs/rules/comma-style - 'comma-style': [ - 'error', - 'last', - { - exceptions: { - ArrayExpression: false, - ArrayPattern: false, - ArrowFunctionExpression: false, - CallExpression: false, - FunctionDeclaration: false, - FunctionExpression: false, - ImportDeclaration: false, - ObjectExpression: false, - ObjectPattern: false, - VariableDeclaration: false, - NewExpression: false, - }, - }, - ], - // Disallow or enforce consistent spacing inside computed property brackets - // https://eslint.org/docs/rules/computed-property-spacing - 'computed-property-spacing': ['error', 'never', { enforceForClassMembers: true }], - // Enforce consistent newlines before and after dots - // https://eslint.org/docs/rules/dot-location - 'dot-location': ['error', 'property'], - // Require or disallow newline at the end of files - // https://eslint.org/docs/rules/eol-last - 'eol-last': ['error', 'always'], - // Require or disallow spacing between function identifiers and their invocations - // https://eslint.org/docs/rules/func-call-spacing - 'func-call-spacing': ['off', 'never'], - // Enforce line breaks between arguments of a function call - // https://eslint.org/docs/rules/function-call-argument-newline - 'function-call-argument-newline': ['error', 'consistent'], - // Enforce consistent line breaks inside function parentheses - // https://eslint.org/docs/rules/function-paren-newline - // Off as Prettier deals with this - 'function-paren-newline': ['off', 'consistent'], - // Enforce consistent spacing around `*` operators in generator functions - // https://eslint.org/docs/rules/generator-star-spacing - 'generator-star-spacing': ['error', { before: false, after: true }], - // Enforce the location of arrow function bodies - // https://eslint.org/docs/rules/implicit-arrow-linebreak - // Off as do not want to enforce either option. Prefer beside where fits, below where too long - 'implicit-arrow-linebreak': ['off', 'beside'], - // Enforce consistent indentation - // https://eslint.org/docs/rules/indent - // Turned off to allow prettier to enforce indentation - indent: [ - 'off', - 2, - { - SwitchCase: 1, - VariableDeclarator: 1, - outerIIFEBody: 1, - // MemberExpression: null, - FunctionDeclaration: { - parameters: 1, - body: 1, - }, - FunctionExpression: { - parameters: 1, - body: 1, - }, - CallExpression: { - arguments: 1, - }, - ArrayExpression: 1, - ObjectExpression: 1, - ImportDeclaration: 1, - flatTernaryExpressions: false, - offsetTernaryExpressions: false, - // list derived from https://github.com/benjamn/ast-types/blob/HEAD/def/jsx.js - ignoredNodes: [ - 'JSXElement', - 'JSXElement > *', - 'JSXAttribute', - 'JSXIdentifier', - 'JSXNamespacedName', - 'JSXMemberExpression', - 'JSXSpreadAttribute', - 'JSXExpressionContainer', - 'JSXOpeningElement', - 'JSXClosingElement', - 'JSXFragment', - 'JSXOpeningFragment', - 'JSXClosingFragment', - 'JSXText', - 'JSXEmptyExpression', - 'JSXSpreadChild', - ], - ignoreComments: false, - }, - ], - // Enforce the consistent use of either double or single quotes in JSX attributes - // https://eslint.org/docs/rules/jsx-quotes - 'jsx-quotes': ['error', 'prefer-single'], - // Enforce consistent spacing between keys and values in object literal properties - // https://eslint.org/docs/rules/key-spacing - 'key-spacing': [ - 'error', - { - beforeColon: false, - afterColon: true, - mode: 'strict', - }, - ], - // Enforce consistent spacing before and after keywords - // https://eslint.org/docs/rules/keyword-spacing - // Turned off in favor of @typescript-eslint/keyword-spacing - 'keyword-spacing': [ - 'off', - { - before: true, - after: true, - overrides: { - return: { after: true }, - throw: { after: true }, - case: { after: true }, - }, - }, - ], - // Enforce position of line comments - // https://eslint.org/docs/rules/line-comment-position - // Don't want to enforce a particular comment style - 'line-comment-position': ['off', { position: 'above' }], - // Enforce consistent linebreak style - // https://eslint.org/docs/rules/linebreak-style - 'linebreak-style': ['error', 'unix'], - // Require empty lines around comments - // https://eslint.org/docs/rules/lines-around-comment - // Don't want to enforce a particular comment style - 'lines-around-comment': 'off', - // Require or disallow an empty line between class members - // https://eslint.org/docs/rules/lines-between-class-members - // Turned off in favor of @typescript-eslint/lines-between-class-members - 'lines-between-class-members': ['off', 'always', { exceptAfterSingleLine: false }], - // Enforce a maximum line length - // https://eslint.org/docs/rules/max-len - 'max-len': [ - 'warn', - { - code: 100, - tabWidth: 2, - comments: 100, - ignoreComments: true, - ignoreTrailingComments: false, - ignoreUrls: true, - ignoreStrings: true, - ignoreTemplateLiterals: true, - ignoreRegExpLiterals: true, - }, - ], - // Enforce a maximum number of statements allowed per line - // https://eslint.org/docs/rules/max-statements-per-line - 'max-statements-per-line': ['off', { max: 1 }], - // Enforce newlines between operands of ternary expressions - // https://eslint.org/docs/rules/multiline-ternary - // Want to be able to decide which is best - 'multiline-ternary': ['off', 'always'], - // Enforce or disallow parentheses when invoking a constructor with no arguments - // https://eslint.org/docs/rules/new-parens - 'new-parens': ['error', 'always'], - // Require a newline after each call in a method chain - // https://eslint.org/docs/rules/newline-per-chained-call - // Off as conflicts with prettier - 'newline-per-chained-call': ['off', { ignoreChainWithDepth: 2 }], - // Disallow unnecessary parentheses - // https://eslint.org/docs/rules/no-extra-parens - // Turned off in favor of @typescript-eslint/no-extra-parens - 'no-extra-parens': [ - 'off', - 'all', - { - conditionalAssign: true, - returnAssign: false, - nestedBinaryExpressions: false, - ignoreJSX: 'all', // delegate to eslint-plugin-react - enforceForArrowConditionals: false, - enforceForSequenceExpressions: false, - enforceForNewInMemberExpressions: false, - enforceForFunctionPrototypeMethods: false, - }, - ], - // Disallow mixed spaces and tabs for indentation - // https://eslint.org/docs/rules/no-mixed-spaces-and-tabs - 'no-mixed-spaces-and-tabs': 'error', - // Disallow multiple spaces - // https://eslint.org/docs/rules/no-multi-spaces - 'no-multi-spaces': ['error', { ignoreEOLComments: true, exceptions: { Property: true } }], - // Disallow multiple empty lines - // https://eslint.org/docs/rules/no-multiple-empty-lines - 'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 1, maxBOF: 0 }], - // Disallow all tabs - // https://eslint.org/docs/rules/no-tabs - 'no-tabs': ['error', { allowIndentationTabs: false }], - // Disallow trailing whitespace at the end of lines - // https://eslint.org/docs/rules/no-trailing-spaces - 'no-trailing-spaces': ['error', { skipBlankLines: false, ignoreComments: false }], - // Disallow whitespace before properties - // https://eslint.org/docs/rules/no-whitespace-before-property - 'no-whitespace-before-property': 'error', - // Enforce the location of single-line statements - // https://eslint.org/docs/rules/nonblock-statement-body-position - 'nonblock-statement-body-position': ['error', 'beside', { overrides: {} }], - // Enforce consistent line breaks after opening and before closing braces - // https://eslint.org/docs/rules/object-curly-newline - 'object-curly-newline': ['error', { consistent: true, multiline: true }], - // Enforce consistent spacing inside braces - // https://eslint.org/docs/rules/object-curly-spacing - // Turned off in favor of @typescript-eslint/object-curly-spacing - 'object-curly-spacing': ['off', 'always', { arraysInObjects: true, objectsInObjects: true }], - // Enforce placing object properties on separate lines - // https://eslint.org/docs/rules/object-property-newline - 'object-property-newline': ['error', { allowAllPropertiesOnSameLine: true }], - // Enforce consistent linebreak style for operators - // https://eslint.org/docs/rules/operator-linebreak - 'operator-linebreak': ['error', 'after', { overrides: { '?': 'before', ':': 'before' } }], - // Require or disallow padding within blocks - // https://eslint.org/docs/rules/padded-blocks - 'padded-blocks': [ - 'error', - { - blocks: 'never', - classes: 'never', - switches: 'never', - }, - { - allowSingleLineBlocks: true, - }, - ], - // Require or disallow padding lines between statements - // https://eslint.org/docs/rules/padding-line-between-statements - // Do not want to require lines between each statement or not - // Prefer @typescript-eslint/padding-line-between-statements if changing - 'padding-line-between-statements': 'off', - // Enforce the consistent use of either backticks, double, or single quotes - // https://eslint.org/docs/rules/quotes - // Turned off in favor of @typescript-eslint/quotes - quotes: ['warn', 'single', { avoidEscape: true, allowTemplateLiterals: true }], - // Enforce spacing between rest and spread operators and their expressions - // https://eslint.org/docs/rules/rest-spread-spacing - 'rest-spread-spacing': ['error', 'never'], - // Require or disallow semicolons instead of ASI - // https://eslint.org/docs/rules/semi - // Turned off in favor of @typescript-eslint/semi - semi: ['off', 'always', { omitLastInOneLineBlock: false }], - // Enforce consistent spacing before and after semicolons - // https://eslint.org/docs/rules/semi-spacing - 'semi-spacing': ['error', { before: false, after: true }], - // Enforce location of semicolons - // https://eslint.org/docs/rules/semi-style - 'semi-style': ['error', 'last'], - // Enforce consistent spacing before blocks - // https://eslint.org/docs/rules/space-before-blocks - 'space-before-blocks': ['error', 'always'], - // Enforce consistent spacing before `function` definition opening parenthesis - // https://eslint.org/docs/rules/space-before-function-paren - // Turned off in favor of @typescript-eslint/space-before-function-paren - 'space-before-function-paren': [ - 'off', - { anonymous: 'always', named: 'never', asyncArrow: 'always' }, - ], - // Enforce consistent spacing inside parentheses - // https://eslint.org/docs/rules/space-in-parens - 'space-in-parens': ['error', 'never'], - // Require spacing around infix operators - // https://eslint.org/docs/rules/space-infix-ops - // Turned off in favor of @typescript-eslint/space-infix-ops - 'space-infix-ops': ['off', { int32Hint: false }], - // Enforce consistent spacing before or after unary operators - // https://eslint.org/docs/rules/space-unary-ops - 'space-unary-ops': ['error', { words: true, nonwords: false, overrides: {} }], - // Enforce spacing around colons of switch statements - // https://eslint.org/docs/rules/switch-colon-spacing - 'switch-colon-spacing': ['error', { after: true, before: false }], - // Require or disallow spacing around embedded expressions of template strings - // https://eslint.org/docs/rules/template-curly-spacing - 'template-curly-spacing': ['error', 'never'], - // Require or disallow spacing between template tags and their literals - // https://eslint.org/docs/rules/template-tag-spacing - 'template-tag-spacing': ['error', 'never'], - // Require or disallow Unicode byte order mark (BOM) - // https://eslint.org/docs/rules/unicode-bom - 'unicode-bom': ['error', 'never'], - // Require parentheses around immediate `function` invocations - // https://eslint.org/docs/rules/wrap-iife - 'wrap-iife': ['error', 'inside', { functionPrototypeMethods: true }], - // Require parenthesis around regex literals - // https://eslint.org/docs/rules/wrap-regex - // Don't want to enforce wrapping regexp - 'wrap-regex': 'off', - // Require or disallow spacing around the `*` in `yield*` expressions - // https://eslint.org/docs/rules/yield-star-spacing - 'yield-star-spacing': ['error', { before: false, after: true }], - }, -}; diff --git a/config/eslint/repo/rules/baseFormattingRules.js b/config/eslint/repo/rules/baseFormattingRules.js new file mode 100644 index 0000000..69cee75 --- /dev/null +++ b/config/eslint/repo/rules/baseFormattingRules.js @@ -0,0 +1,184 @@ +export default { + rules: { + // Enforce linebreaks after opening and before closing array brackets + // https://eslint.style/rules/js/array-bracket-newline + '@stylistic/array-bracket-newline': ['error', 'consistent'], + // Enforce consistent spacing inside array brackets + // https://eslint.style/rules/js/array-bracket-spacing + '@stylistic/array-bracket-spacing': [ + 'error', + 'never', + { + singleValue: false, + objectsInArrays: false, + arraysInArrays: false, + }, + ], + // Enforce line breaks after each array element + // https://eslint.style/rules/js/array-element-newline + '@stylistic/array-element-newline': ['error', 'consistent'], + // Require parentheses around arrow function arguments + // https://eslint.style/rules/js/arrow-parens + '@stylistic/arrow-parens': ['error', 'always', { requireForBlockBody: false }], + // Enforce consistent spacing before and after the arrow in arrow functions + // https://eslint.style/rules/js/arrow-spacing + '@stylistic/arrow-spacing': ['error', { before: true, after: true }], + // Disallow or enforce spaces inside of blocks after opening block and before closing + // block + // https://eslint.style/rules/js/block-spacing + '@stylistic/block-spacing': ['error', 'always'], + // Enforce consistent comma style + // https://eslint.style/rules/js/comma-style + '@stylistic/comma-style': [ + 'error', + 'last', + { + exceptions: { + ArrayExpression: false, + ArrayPattern: false, + ArrowFunctionExpression: false, + CallExpression: false, + FunctionDeclaration: false, + FunctionExpression: false, + ImportDeclaration: false, + ObjectExpression: false, + ObjectPattern: false, + VariableDeclaration: false, + NewExpression: false, + }, + }, + ], + // Disallow or enforce consistent spacing inside computed property brackets + // https://eslint.style/rules/js/computed-property-spacing + '@stylistic/computed-property-spacing': ['error', 'never', { enforceForClassMembers: true }], + // Enforce consistent newlines before and after dots + // https://eslint.style/rules/js/dot-location + '@stylistic/dot-location': ['error', 'property'], + // Require or disallow newline at the end of files + // https://eslint.style/rules/js/eol-last + '@stylistic/eol-last': ['error', 'always'], + // Enforce line breaks between arguments of a function call + // https://eslint.style/rules/js/function-call-argument-newline + '@stylistic/function-call-argument-newline': ['error', 'consistent'], + // Enforce consistent spacing around `*` operators in generator functions + // https://eslint.style/rules/js/generator-star-spacing + '@stylistic/generator-star-spacing': ['error', { before: false, after: true }], + // Enforce the consistent use of either double or single quotes in JSX attributes + // https://eslint.style/rules/js/jsx-quotes + '@stylistic/jsx-quotes': ['error', 'prefer-single'], + // Enforce consistent spacing between keys and values in object literal properties + // https://eslint.style/rules/js/key-spacing + '@stylistic/key-spacing': [ + 'error', + { + beforeColon: false, + afterColon: true, + mode: 'strict', + }, + ], + // Enforce consistent linebreak style + // https://eslint.style/rules/js/linebreak-style + '@stylistic/linebreak-style': ['error', 'unix'], + // Enforce a maximum line length + // https://eslint.style/rules/js/max-len + '@stylistic/max-len': [ + 'warn', + { + code: 100, + tabWidth: 2, + comments: 100, + ignoreComments: true, + ignoreTrailingComments: false, + ignoreUrls: true, + ignoreStrings: true, + ignoreTemplateLiterals: true, + ignoreRegExpLiterals: true, + }, + ], + // Enforce or disallow parentheses when invoking a constructor with no arguments + // https://eslint.style/rules/js/new-parens + '@stylistic/new-parens': ['error', 'always'], + // Disallow mixed spaces and tabs for indentation + // https://eslint.style/rules/js/no-mixed-spaces-and-tabs + '@stylistic/no-mixed-spaces-and-tabs': 'error', + // Disallow multiple spaces + // https://eslint.style/rules/js/no-multi-spaces + '@stylistic/no-multi-spaces': ['error', { ignoreEOLComments: true, exceptions: { Property: true } }], + // Disallow multiple empty lines + // https://eslint.style/rules/js/no-multiple-empty-lines + '@stylistic/no-multiple-empty-lines': ['error', { max: 1, maxEOF: 1, maxBOF: 0 }], + // Disallow all tabs + // https://eslint.style/rules/js/no-tabs + '@stylistic/no-tabs': ['error', { allowIndentationTabs: false }], + // Disallow trailing whitespace at the end of lines + // https://eslint.style/rules/js/no-trailing-spaces + '@stylistic/no-trailing-spaces': ['error', { skipBlankLines: false, ignoreComments: false }], + // Disallow whitespace before properties + // https://eslint.style/rules/js/no-whitespace-before-property + '@stylistic/no-whitespace-before-property': 'error', + // Enforce the location of single-line statements + // https://eslint.style/rules/js/nonblock-statement-body-position + '@stylistic/nonblock-statement-body-position': ['error', 'beside', { overrides: {} }], + // Enforce consistent line breaks after opening and before closing braces + // https://eslint.style/rules/js/object-curly-newline + '@stylistic/object-curly-newline': ['error', { consistent: true, multiline: true }], + // Enforce placing object properties on separate lines + // https://eslint.style/rules/js/object-property-newline + '@stylistic/object-property-newline': ['error', { allowAllPropertiesOnSameLine: true }], + // Enforce consistent linebreak style for operators + // https://eslint.style/rules/js/operator-linebreak + '@stylistic/operator-linebreak': ['error', 'after', { overrides: { '?': 'before', ':': 'before' } }], + // Require or disallow padding within blocks + // https://eslint.style/rules/js/padded-blocks + '@stylistic/padded-blocks': [ + 'error', + { + blocks: 'never', + classes: 'never', + switches: 'never', + }, + { + allowSingleLineBlocks: true, + }, + ], + // Enforce the consistent use of either backticks, double, or single quotes + // https://eslint.style/rules/js/quotes + '@stylistic/quotes': ['warn', 'single', { avoidEscape: true, allowTemplateLiterals: 'always' }], + // Enforce spacing between rest and spread operators and their expressions + // https://eslint.style/rules/js/rest-spread-spacing + '@stylistic/rest-spread-spacing': ['error', 'never'], + // Enforce consistent spacing before and after semicolons + // https://eslint.style/rules/js/semi-spacing + '@stylistic/semi-spacing': ['error', { before: false, after: true }], + // Enforce location of semicolons + // https://eslint.style/rules/js/semi-style + '@stylistic/semi-style': ['error', 'last'], + // Enforce consistent spacing before blocks + // https://eslint.style/rules/js/space-before-blocks + '@stylistic/space-before-blocks': ['error', 'always'], + // Enforce consistent spacing inside parentheses + // https://eslint.style/rules/js/space-in-parens + '@stylistic/space-in-parens': ['error', 'never'], + // Enforce consistent spacing before or after unary operators + // https://eslint.style/rules/js/space-unary-ops + '@stylistic/space-unary-ops': ['error', { words: true, nonwords: false, overrides: {} }], + // Enforce spacing around colons of switch statements + // https://eslint.style/rules/js/switch-colon-spacing + '@stylistic/switch-colon-spacing': ['error', { after: true, before: false }], + // Require or disallow spacing around embedded expressions of template strings + // https://eslint.style/rules/js/template-curly-spacing + '@stylistic/template-curly-spacing': ['error', 'never'], + // Require or disallow spacing between template tags and their literals + // https://eslint.style/rules/js/template-tag-spacing + '@stylistic/template-tag-spacing': ['error', 'never'], + // Require or disallow Unicode byte order mark (BOM) + // https://eslint.org/docs/rules/unicode-bom + 'unicode-bom': ['error', 'never'], + // Require parentheses around immediate `function` invocations + // https://eslint.style/rules/js/wrap-iife + '@stylistic/wrap-iife': ['error', 'inside', { functionPrototypeMethods: true }], + // Require or disallow spacing around the `*` in `yield*` expressions + // https://eslint.style/rules/js/yield-star-spacing + '@stylistic/yield-star-spacing': ['error', { before: false, after: true }], + }, +}; diff --git a/config/eslint/repo/rules/baseLogicRules.cjs b/config/eslint/repo/rules/baseLogicRules.js similarity index 94% rename from config/eslint/repo/rules/baseLogicRules.cjs rename to config/eslint/repo/rules/baseLogicRules.js index acda273..674af8a 100644 --- a/config/eslint/repo/rules/baseLogicRules.cjs +++ b/config/eslint/repo/rules/baseLogicRules.js @@ -1,4 +1,4 @@ -module.exports = { +export default { rules: { // Enforce return statements in callbacks of array's methods // https://eslint.org/docs/rules/array-callback-return @@ -60,7 +60,7 @@ module.exports = { 'no-duplicate-case': 'error', // Disallow duplicate module imports // https://eslint.org/docs/rules/no-duplicate-imports - // Replaced with import/no-duplicates + // Replaced with import-x/no-duplicates 'no-duplicate-imports': 'off', // Disallow empty character classes in Regular Expressions // https://eslint.org/docs/rules/no-empty-character-class @@ -97,16 +97,13 @@ module.exports = { skipTemplates: true, }, ], - // Disallow number literals that lose precision - // https://eslint.org/docs/rules/no-loss-of-precision - // Turned off in favor of @typescript-eslint/no-loss-of-precision - 'no-loss-of-precision': 'off', // Disallow characters which are made with multiple code points in character class syntax // https://eslint.org/docs/rules/no-misleading-character-class 'no-misleading-character-class': 'error', - // Disallow `new` operators with the `Symbol` object - // https://eslint.org/docs/rules/no-new-symbol - 'no-new-symbol': 'error', + // Disallow `new` operators with global non-constructor functions + // https://eslint.org/docs/rules/no-new-native-nonconstructor + // (renamed from no-new-symbol in ESLint v9) + 'no-new-native-nonconstructor': 'error', // Disallow calling global object properties as functions // https://eslint.org/docs/rules/no-obj-calls 'no-obj-calls': 'error', @@ -182,7 +179,6 @@ module.exports = { 'no-useless-backreference': 'error', // Disallow assignments that can lead to race conditions due to usage of `await` or `yield` // https://eslint.org/docs/rules/require-atomic-updates - // Consider disabling if flagging things incorrectly. According to airbnb it is buggy, but could have been resolved in recent versions 'require-atomic-updates': 'error', // Require calls to `isNaN()` when check for `NaN` // https://eslint.org/docs/rules/use-isnan diff --git a/config/eslint/repo/rules/baseStyleRules.cjs b/config/eslint/repo/rules/baseStyleRules.js similarity index 90% rename from config/eslint/repo/rules/baseStyleRules.cjs rename to config/eslint/repo/rules/baseStyleRules.js index c09793f..a438459 100644 --- a/config/eslint/repo/rules/baseStyleRules.cjs +++ b/config/eslint/repo/rules/baseStyleRules.js @@ -1,4 +1,4 @@ -module.exports = { +export default { rules: { // Enforce getter and setter pairs in objects and classes // https://eslint.org/docs/rules/accessor-pairs @@ -21,7 +21,6 @@ module.exports = { camelcase: [ 'error', { - // properties: "never", properties: 'always', ignoreDestructuring: true, ignoreImports: false, @@ -42,7 +41,6 @@ module.exports = { ], // Enforce that class methods utilize `this` // https://eslint.org/docs/rules/class-methods-use-this - // { exceptMethods: [],enforceForClassFields: true } 'class-methods-use-this': 'error', // Enforce a maximum cyclomatic complexity allowed in a program // https://eslint.org/docs/rules/complexity @@ -56,7 +54,6 @@ module.exports = { 'consistent-this': ['error', 'self'], // Enforce consistent brace style for all control statements // https://eslint.org/docs/rules/curly - // FIXME: May conflict with prettier rules - if so, turn off curly: ['error', 'multi-line', 'consistent'], // Require `default` cases in `switch` statements // https://eslint.org/docs/rules/default-case @@ -99,20 +96,15 @@ module.exports = { 'guard-for-in': 'error', // Disallow specified identifiers // https://eslint.org/docs/rules/id-denylist - // Do not want to block ID's 'id-denylist': 'off', // Enforce minimum and maximum identifier lengths // https://eslint.org/docs/rules/id-length - // Do not want to enforce 'id-length': 'off', // Require identifiers to match a specified regular expression // https://eslint.org/docs/rules/id-match - // Do not want to enforce 'id-match': ['off', '^[a-z]+([A-Z][a-z]+)*$'], // Require or disallow initialization in variable declarations // https://eslint.org/docs/rules/init-declarations - // Do not want to enforce as sometimes we don't want to initialize - // Prefer @typescript-eslint/init-declarations if this changes 'init-declarations': 'off', // Enforce a maximum number of classes per file // https://eslint.org/docs/rules/max-classes-per-file @@ -122,11 +114,9 @@ module.exports = { 'max-depth': ['error', { max: 6 }], // Enforce a maximum number of lines per file // https://eslint.org/docs/rules/max-lines - // Do not want to enforce a limit 'max-lines': ['off', { max: 300, skipBlankLines: true, skipComments: true }], // Enforce a maximum number of lines of code in a function // https://eslint.org/docs/rules/max-lines-per-function - // Do not want to enforce a limit 'max-lines-per-function': [ 'off', { max: 50, skipBlankLines: true, skipComments: true, IIFEs: true }, @@ -136,11 +126,9 @@ module.exports = { 'max-nested-callbacks': ['error', { max: 10 }], // Enforce a maximum number of parameters in function definitions // https://eslint.org/docs/rules/max-params - // Do not want to enforce a limit 'max-params': ['off', { max: 3 }], // Enforce a maximum number of statements allowed in function blocks // https://eslint.org/docs/rules/max-statements - // Do not want to enforce a limit 'max-statements': ['off', { max: 10, ignoreTopLevelFunctions: true }], // Enforce a particular style for multiline comments // https://eslint.org/docs/rules/multiline-comment-style @@ -173,11 +161,6 @@ module.exports = { // Disallow lexical declarations in case clauses // https://eslint.org/docs/rules/no-case-declarations 'no-case-declarations': 'error', - // Disallow arrow functions where they could be confused with comparisons - // https://eslint.org/docs/rules/no-confusing-arrow - // Off as causes issue with prettier, and it's unlikely we're using the style that - // this rule was created to solve - 'no-confusing-arrow': ['off', { allowParens: true }], // Disallow the use of `console` // https://eslint.org/docs/rules/no-console 'no-console': 'warn', @@ -202,7 +185,6 @@ module.exports = { 'no-empty-function': ['off', { allow: [] }], // Disallow `null` comparisons without type-checking operators // https://eslint.org/docs/rules/no-eq-null - // 'eqeqeq' is more powerful and can enforce the same thing 'no-eq-null': 'off', // Disallow the use of `eval()` // https://eslint.org/docs/rules/no-eval @@ -219,19 +201,15 @@ module.exports = { // Disallow unnecessary labels // https://eslint.org/docs/rules/no-extra-label 'no-extra-label': 'error', - // Disallow unnecessary semicolons - // https://eslint.org/docs/rules/no-extra-semi - // Turned off in favor of @typescript-eslint/no-extra-semi - 'no-extra-semi': 'off', // Disallow leading or trailing decimal points in numeric literals - // https://eslint.org/docs/rules/no-floating-decimal - 'no-floating-decimal': 'error', + // https://eslint.style/rules/js/no-floating-decimal + // (moved to @stylistic in ESLint v10) + '@stylistic/no-floating-decimal': 'error', // Disallow assignments to native objects or read-only global variables // https://eslint.org/docs/rules/no-global-assign 'no-global-assign': ['error', { exceptions: [] }], // Disallow shorthand type conversions // https://eslint.org/docs/rules/no-implicit-coercion - // Do not want to enforce as shorthand can be convenient 'no-implicit-coercion': [ 'off', { @@ -244,18 +222,15 @@ module.exports = { ], // Disallow declarations in the global scope // https://eslint.org/docs/rules/no-implicit-globals - // Do not want to enforce 'no-implicit-globals': ['off', { lexicalBindings: false }], // Disallow the use of `eval()`-like methods // https://eslint.org/docs/rules/no-implied-eval 'no-implied-eval': 'error', // Disallow inline comments after code // https://eslint.org/docs/rules/no-inline-comments - // Want to allow inline comments 'no-inline-comments': 'off', // Disallow `this` keywords outside of classes or class-like objects // https://eslint.org/docs/rules/no-invalid-this - // Want to be able to use `this` inside functions // Turned off in favor of @typescript-eslint/no-invalid-this 'no-invalid-this': ['off', { capIsConstructor: true }], // Disallow the use of the `__iterator__` property @@ -291,9 +266,9 @@ module.exports = { }, ], // Disallow mixed binary operators - // https://eslint.org/docs/rules/no-mixed-operators - // FIXME: May cause issues with prettier- turn off if so - 'no-mixed-operators': [ + // https://eslint.style/rules/js/no-mixed-operators + // (moved to @stylistic in ESLint v10) + '@stylistic/no-mixed-operators': [ 'error', { groups: [ @@ -318,7 +293,6 @@ module.exports = { 'no-multi-str': 'error', // Disallow negated conditions // https://eslint.org/docs/rules/no-negated-condition - // Want to allow negated conditions 'no-negated-condition': 'off', // Disallow nested ternary expressions // https://eslint.org/docs/rules/no-nested-ternary @@ -331,8 +305,9 @@ module.exports = { // https://eslint.org/docs/rules/no-new-func 'no-new-func': 'error', // Disallow `Object` constructors - // https://eslint.org/docs/rules/no-new-object - 'no-new-object': 'error', + // https://eslint.org/docs/rules/no-object-constructor + // (renamed from no-new-object in ESLint v9) + 'no-object-constructor': 'error', // Disallow `new` operators with the `String`, `Number`, and `Boolean` objects // https://eslint.org/docs/rules/no-new-wrappers 'no-new-wrappers': 'error', @@ -445,11 +420,6 @@ module.exports = { message: 'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.', }, - // { - // selector: 'ForOfStatement', - // message: - // 'iterators/generators require regenerator-runtime, which is too heavyweight for this guide to allow them. Separately, loops should be avoided in favor of array iterations.', - // }, { selector: 'LabeledStatement', message: @@ -465,8 +435,9 @@ module.exports = { // https://eslint.org/docs/rules/no-return-assign 'no-return-assign': ['error', 'always'], // Disallow unnecessary `return await` - // https://eslint.org/docs/rules/no-return-await - 'no-return-await': 'error', + // (no-return-await removed from ESLint core in v9; @typescript-eslint/return-await + // requires typed linting which is not enabled — rule disabled for now) + // '@typescript-eslint/return-await': 'error', // Disallow `javascript:` urls // https://eslint.org/docs/rules/no-script-url 'no-script-url': 'error', @@ -482,7 +453,6 @@ module.exports = { 'no-shadow-restricted-names': 'error', // Disallow ternary operators // https://eslint.org/docs/rules/no-ternary - // Want to allow ternary operators 'no-ternary': 'off', // Disallow throwing literals as exceptions // https://eslint.org/docs/rules/no-throw-literal @@ -492,11 +462,9 @@ module.exports = { 'no-undef-init': 'error', // Disallow the use of `undefined` as an identifier // https://eslint.org/docs/rules/no-undefined - // Off as other rules prevent shadowing, and typescript suggest using undefined rather than null 'no-undefined': 'off', // Disallow dangling underscores in identifiers // https://eslint.org/docs/rules/no-underscore-dangle - // Off as we use underscore dangle (not neccessarily for private members) 'no-underscore-dangle': [ 'off', { @@ -627,7 +595,6 @@ module.exports = { // Disallow use of `Object.prototype.hasOwnProperty.call()` and prefer use of // `Object.hasOwn()` // https://eslint.org/docs/rules/prefer-object-has-own - // Off as not using ES2022 'prefer-object-has-own': 'off', // Disallow using Object.assign with an object literal as the first argument and prefer // the use of object spread instead. @@ -649,14 +616,14 @@ module.exports = { // https://eslint.org/docs/rules/ 'prefer-template': 'error', // Require quotes around object literal property names - // https://eslint.org/docs/rules/quote-props - 'quote-props': ['error', 'as-needed', { keywords: false, unnecessary: true, numbers: false }], + // https://eslint.style/rules/js/quote-props + // (moved to @stylistic in ESLint v10) + '@stylistic/quote-props': ['error', 'as-needed', { keywords: false, unnecessary: true, numbers: false }], // Enforce the consistent use of the radix argument when using `parseInt()` // https://eslint.org/docs/rules/radix radix: ['error', 'always'], // Disallow async functions which have no `await` expression // https://eslint.org/docs/rules/require-await - // This is a bad rule according to airbnb 'require-await': 'off', // Enforce the use of `u` flag on RegExp // https://eslint.org/docs/rules/require-unicode-regexp @@ -666,7 +633,6 @@ module.exports = { 'require-yield': 'error', // Enforce sorted import declarations within modules // https://eslint.org/docs/rules/sort-imports - // TODO: May wish to disable this rule if it causes issues 'sort-imports': [ 'error', { @@ -679,7 +645,6 @@ module.exports = { ], // Require object keys to be sorted // https://eslint.org/docs/rules/sort-keys - // Off as often there is a more sensible order than alphabetical 'sort-keys': ['off', 'asc', { caseSensitive: false, minKeys: 2, natural: true }], // Require variables within the same declaration block to be sorted // https://eslint.org/docs/rules/sort-vars @@ -693,19 +658,16 @@ module.exports = { line: { exceptions: ['-', '+'], markers: ['=', '!', '/'], - // space above to support sprockets directives, slash for TS /// comments }, block: { exceptions: ['-', '+'], markers: ['=', '!', ':', '::'], - // space above to support sprockets directives and flow comment types balanced: true, }, }, ], // Require or disallow strict mode directives // https://eslint.org/docs/rules/strict - // babel and TS already enforce this strict: ['error', 'never'], // Require symbol descriptions // https://eslint.org/docs/rules/symbol-description diff --git a/config/eslint/repo/rules/importPlugin.cjs b/config/eslint/repo/rules/importPlugin.cjs deleted file mode 100644 index 2ed9e1b..0000000 --- a/config/eslint/repo/rules/importPlugin.cjs +++ /dev/null @@ -1,221 +0,0 @@ -module.exports = { - settings: { - 'import/ignore': ['node_modules'], - 'import/resolver': { node: { extensions: ['.js', '.jsx', '.d.ts', '.ts', '.tsx', '.md'] } }, - }, - plugins: ['import'], - rules: { - // Ensure a default export is present, given a default import - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/default.md - 'import/default': 'error', - // Enforce a leading comment with the webpackChunkName for dynamic imports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/dynamic-import-chunkname.md - 'import/dynamic-import-chunkname': [ - 'error', - { importFunctions: [], webpackChunknameFormat: '.*' }, - ], - // Report any invalid exports, i.e. re-export of the same name - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/export.md - 'import/export': 'error', - // Ensure all exports appear after other statements - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/exports-last.md - 'import/exports-last': 'error', - // Ensure consistent use of file extension within the import path - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/extensions.md - 'import/extensions': [ - 'error', - { - js: 'never', - jsx: 'never', - ts: 'always', - tsx: 'always', - css: 'always', - json: 'always', - png: 'always', - md: 'always', - }, - ], - // Ensure all imports appear before other statements - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/first.md - 'import/first': 'error', - // Prefer named exports to be grouped together in a single export declaration - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/group-exports.md - 'import/group-exports': 'error', - // Limit the maximum number of dependencies a module can have - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/max-dependencies.md - // Do not want to limit - 'import/max-dependencies': ['off', { max: 10, ignoreTypeImports: true }], - // Ensure named imports correspond to a named export in the remote file - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/named.md - 'import/named': 'error', - // Ensure imported namespaces contain dereferenced properties as they are dereferenced - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/namespace.md - 'import/namespace': ['error', { allowComputed: false }], - // Enforce a newline after import statements - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/newline-after-import.md - 'import/newline-after-import': 'error', - // Report AMD `require` and `define` calls - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-amd.md - 'import/no-amd': 'error', - // Forbid anonymous values as default exports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-anonymous-default-export.md - 'import/no-anonymous-default-export': [ - 'error', - { - allowArray: false, - allowArrowFunction: false, - allowAnonymousClass: false, - allowAnonymousFunction: false, - allowCallExpression: true, // The true value here is for backward compatibility - allowLiteral: false, - allowObject: false, - }, - ], - // Forbid import of modules using absolute paths - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-absolute-path.md - 'import/no-absolute-path': ['error', { esmodule: true, commonjs: true, amd: false }], - // Report CommonJS `require` calls and `module.exports` or `exports.*` - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-commonjs.md - // Off due to some files requiring commonjs currently - 'import/no-commonjs': [ - 'off', - { allowRequire: true, allowConditionalRequire: true, allowPrimitiveModules: true }, - ], - // Forbid a module from importing a module with a dependency path back to itself - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-cycle.md - 'import/no-cycle': [ - 'error', - { commonjs: false, amd: false, maxDepth: Infinity, ignoreExternal: true }, - ], - // Forbid default exports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-default-export.md - // Do not want to disallow default exports - 'import/no-default-export': 'error', - // Report imported names marked with `@deprecated` documentation tag - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-deprecated.md - 'import/no-deprecated': 'warn', - // Report repeated `import` of the same module in multiple places - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-duplicates.md - 'import/no-duplicates': ['error', { considerQueryString: true }], - // Forbid `require()` calls with expressions - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-dynamic-require.md - 'import/no-dynamic-require': 'error', - // Forbid the use of extraneous packages - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md - // FIXME: Turn on? Turned off as wasn't resolving workspace deps correctly - Use Globs instead? - 'import/no-extraneous-dependencies': [ - 'off', - { - devDependencies: true, - optionalDependencies: true, - peerDependencies: true, - bundledDependencies: true, - }, - ], - // Forbid imports with CommonJS exports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-import-module-exports.md - 'import/no-import-module-exports': ['error', { exceptions: [] }], - // Prevent importing the submodules of other modules - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-internal-modules.md - // Don't need to prevent imports currently - 'import/no-internal-modules': ['off', { allow: [], forbid: [] }], - // Forbid the use of mutable exports with `var` or `let` - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-mutable-exports.md - 'import/no-mutable-exports': ['error'], - // Forbid named default exports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-default.md - 'import/no-named-default': 'error', - // Forbid named exports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-export.md - // Do not want to disallow named exports - 'import/no-named-export': 'off', - // Report use of exported name as identifier of default export - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-as-default.md - 'import/no-named-as-default': 'error', - // Report use of exported name as property of default export - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-as-default-member.md - 'import/no-named-as-default-member': 'error', - // Forbid namespace (a.k.a. "wildcard" `*`) imports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-namespace.md - 'import/no-namespace': ['error', { ignore: [] }], - // No Node.js builtin modules - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-nodejs-modules.md - // Not really an issue in our project - 'import/no-nodejs-modules': ['off', { allow: ['fs', 'path'] }], - // Prevent importing packages through relative paths - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-relative-packages.md - 'import/no-relative-packages': 'off', - // Forbid importing modules from parent directories - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-relative-parent-imports.md - // Do not want to restrict importing from parent paths - 'import/no-relative-parent-imports': 'off', - // Restrict which files can be imported in a given folder - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-restricted-paths.md - // Not currently needing to be enforced - 'import/no-restricted-paths': ['off', { zones: [], basePath: '.' }], - // Forbid a module from importing itself - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-self-import.md - 'import/no-self-import': 'error', - // Forbid unassigned imports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unassigned-import.md - 'import/no-unassigned-import': [ - 'error', - { - allow: [ - '**/commands', - '**/*.css', - '@testing-library/**', - 'cross-fetch/polyfill', - 'jest-fetch-mock', - 'setimmediate', - ], - }, - ], - // Ensure imports point to a file/module that can be resolved - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unresolved.md - // Off for now as reporting false positives - imports that are resolved in Typescript, - 'import/no-unresolved': ['off', { commonjs: false, amd: false }], - // Report modules without exports, or exports without matching import in another module - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unused-modules.md - 'import/no-unused-modules': [ - 'off', - { missingExports: false, unusedExports: true, src: [process.cwd()] }, - ], - // Prevent unnecessary path segments in import and require statements - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-useless-path-segments.md - 'import/no-useless-path-segments': ['error', { noUselessIndex: false, commonjs: true }], - // Forbid webpack loader syntax in imports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-webpack-loader-syntax.md - 'import/no-webpack-loader-syntax': 'error', - // Enforce a convention in module import order - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md - 'import/order': [ - 'error', - { - groups: [ - 'builtin', - 'external', - 'internal', - 'parent', - 'sibling', - 'index', - 'object', - 'type', - 'unknown', - ], - pathGroups: [], - pathGroupsExcludedImportTypes: [], - 'newlines-between': 'always-and-inside-groups', - alphabetize: { order: 'asc', caseInsensitive: true }, - warnOnUnassignedImports: true, - }, - ], - // Prefer a default export if module exports a single name - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/prefer-default-export.md - // Off as named exports can be better to ensure items are identifiable by name - 'import/prefer-default-export': 'off', - // Report potentially ambiguous parse goal (`script` vs. `module`) - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/unambiguous.md - 'import/unambiguous': 'error', - }, -}; diff --git a/config/eslint/repo/rules/importPlugin.js b/config/eslint/repo/rules/importPlugin.js new file mode 100644 index 0000000..b8128d1 --- /dev/null +++ b/config/eslint/repo/rules/importPlugin.js @@ -0,0 +1,167 @@ +export default { + settings: { + 'import-x/ignore': ['node_modules'], + 'import-x/resolver': { node: { extensions: ['.js', '.jsx', '.d.ts', '.ts', '.tsx', '.md'] } }, + }, + rules: { + // Ensure a default export is present, given a default import + 'import-x/default': 'error', + // Enforce a leading comment with the webpackChunkName for dynamic imports + 'import-x/dynamic-import-chunkname': [ + 'error', + { importFunctions: [], webpackChunknameFormat: '.*' }, + ], + // Report any invalid exports, i.e. re-export of the same name + 'import-x/export': 'error', + // Ensure all exports appear after other statements + 'import-x/exports-last': 'error', + // Ensure consistent use of file extension within the import path + 'import-x/extensions': [ + 'error', + { + js: 'never', + jsx: 'never', + ts: 'always', + tsx: 'always', + css: 'always', + json: 'always', + png: 'always', + md: 'always', + }, + ], + // Ensure all imports appear before other statements + 'import-x/first': 'error', + // Prefer named exports to be grouped together in a single export declaration + 'import-x/group-exports': 'error', + // Limit the maximum number of dependencies a module can have + 'import-x/max-dependencies': ['off', { max: 10, ignoreTypeImports: true }], + // Ensure named imports correspond to a named export in the remote file + 'import-x/named': 'error', + // Ensure imported namespaces contain dereferenced properties as they are dereferenced + 'import-x/namespace': ['error', { allowComputed: false }], + // Enforce a newline after import statements + 'import-x/newline-after-import': 'error', + // Report AMD `require` and `define` calls + 'import-x/no-amd': 'error', + // Forbid anonymous values as default exports + 'import-x/no-anonymous-default-export': [ + 'error', + { + allowArray: false, + allowArrowFunction: false, + allowAnonymousClass: false, + allowAnonymousFunction: false, + allowCallExpression: true, + allowLiteral: false, + allowObject: false, + }, + ], + // Forbid import of modules using absolute paths + 'import-x/no-absolute-path': ['error', { esmodule: true, commonjs: true, amd: false }], + // Report CommonJS `require` calls and `module.exports` or `exports.*` + 'import-x/no-commonjs': [ + 'off', + { allowRequire: true, allowConditionalRequire: true, allowPrimitiveModules: true }, + ], + // Forbid a module from importing a module with a dependency path back to itself + 'import-x/no-cycle': [ + 'error', + { commonjs: false, amd: false, maxDepth: Infinity, ignoreExternal: true }, + ], + // Forbid default exports + 'import-x/no-default-export': 'error', + // Report imported names marked with `@deprecated` documentation tag + 'import-x/no-deprecated': 'warn', + // Report repeated `import` of the same module in multiple places + 'import-x/no-duplicates': ['error', { considerQueryString: true }], + // Forbid `require()` calls with expressions + 'import-x/no-dynamic-require': 'error', + // Forbid the use of extraneous packages + 'import-x/no-extraneous-dependencies': [ + 'off', + { + devDependencies: true, + optionalDependencies: true, + peerDependencies: true, + bundledDependencies: true, + }, + ], + // Forbid imports with CommonJS exports + 'import-x/no-import-module-exports': ['error', { exceptions: [] }], + // Prevent importing the submodules of other modules + 'import-x/no-internal-modules': ['off', { allow: [], forbid: [] }], + // Forbid the use of mutable exports with `var` or `let` + 'import-x/no-mutable-exports': ['error'], + // Forbid named default exports + 'import-x/no-named-default': 'error', + // Forbid named exports + 'import-x/no-named-export': 'off', + // Report use of exported name as identifier of default export + 'import-x/no-named-as-default': 'error', + // Report use of exported name as property of default export + 'import-x/no-named-as-default-member': 'error', + // Forbid namespace (a.k.a. "wildcard" `*`) imports + 'import-x/no-namespace': ['error', { ignore: [] }], + // No Node.js builtin modules + 'import-x/no-nodejs-modules': ['off', { allow: ['fs', 'path'] }], + // Prevent importing packages through relative paths + 'import-x/no-relative-packages': 'off', + // Forbid importing modules from parent directories + 'import-x/no-relative-parent-imports': 'off', + // Restrict which files can be imported in a given folder + 'import-x/no-restricted-paths': ['off', { zones: [], basePath: '.' }], + // Forbid a module from importing itself + 'import-x/no-self-import': 'error', + // Forbid unassigned imports + 'import-x/no-unassigned-import': [ + 'error', + { + allow: [ + '**/commands', + '**/*.css', + '@testing-library/**', + 'cross-fetch/polyfill', + 'jest-fetch-mock', + 'setimmediate', + ], + }, + ], + // Ensure imports point to a file/module that can be resolved + 'import-x/no-unresolved': ['off', { commonjs: false, amd: false }], + // Report modules without exports, or exports without matching import in another module + 'import-x/no-unused-modules': [ + 'off', + { missingExports: false, unusedExports: true, src: [process.cwd()] }, + ], + // Prevent unnecessary path segments in import and require statements + 'import-x/no-useless-path-segments': ['error', { noUselessIndex: false, commonjs: true }], + // Forbid webpack loader syntax in imports + 'import-x/no-webpack-loader-syntax': 'error', + // Enforce a convention in module import order + 'import-x/order': [ + 'error', + { + groups: [ + 'builtin', + 'external', + 'internal', + 'parent', + 'sibling', + 'index', + 'object', + 'type', + 'unknown', + ], + pathGroups: [], + pathGroupsExcludedImportTypes: [], + 'newlines-between': 'always-and-inside-groups', + alphabetize: { order: 'asc', caseInsensitive: true }, + warnOnUnassignedImports: true, + }, + ], + // Prefer a default export if module exports a single name + 'import-x/prefer-default-export': 'off', + // Report potentially ambiguous parse goal (`script` vs. `module`) + 'import-x/unambiguous': 'error', + }, +}; diff --git a/config/eslint/repo/rules/jestPlugin.cjs b/config/eslint/repo/rules/jestPlugin.cjs deleted file mode 100644 index bd4bcab..0000000 --- a/config/eslint/repo/rules/jestPlugin.cjs +++ /dev/null @@ -1,172 +0,0 @@ -module.exports = { - plugins: ['jest'], - settings: { - jest: { version: 27 }, - }, - rules: {}, - overrides: [ - { - files: ['*.{spec,test}.{js,jsx,ts,tsx}'], - plugins: ['jest'], - globals: { jsdom: 'readonly' }, - env: { jest: true, 'jest/globals': true, node: true }, - rules: { - // Turn off other rules - 'max-classes-per-file': 'off', - 'no-magic-numbers': 'off', - 'sort-keys': 'off', - - // Have control over test and it usages - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/consistent-test-it.md - 'jest/consistent-test-it': ['error', { fn: 'it', withinDescribe: 'it' }], - // Enforce assertion to be made in a test body - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/expect-expect.md - 'jest/expect-expect': [ - 'error', - { assertFunctionNames: ['expect'], additionalTestBlockFunctions: [] }, - ], - // Enforces a maximum depth to nested describe calls - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/max-nested-describe.md - // Do not want to enforce at this stage - 'jest/max-nested-describe': ['off', { max: 5 }], - // Disallow alias methods - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-alias-methods.md - 'jest/no-alias-methods': 'error', - // Disallow commented out tests - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-commented-out-tests.md - 'jest/no-commented-out-tests': 'warn', - // Prevent calling expect conditionally - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-conditional-expect.md - 'jest/no-conditional-expect': 'error', - // Disallow use of deprecated functions - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-deprecated-functions.md - 'jest/no-deprecated-functions': 'error', - // Disallow disabled tests - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-disabled-tests.md - 'jest/no-disabled-tests': 'error', - // Avoid using a callback in asynchronous tests and hooks - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-done-callback.md - 'jest/no-done-callback': 'error', - // Disallow duplicate setup and teardown hooks - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-duplicate-hooks.md - 'jest/no-duplicate-hooks': 'error', - // Disallow using exports in files containing tests - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-export.md - 'jest/no-export': 'error', - // Disallow focused tests - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-focused-tests.md - 'jest/no-focused-tests': 'error', - // Disallow setup and teardown hooks - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-hooks.md - // Do not want to restrict setup and teardown hooks - 'jest/no-hooks': ['off', { allow: [] }], - // Disallow identical titles - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-identical-title.md - 'jest/no-identical-title': 'error', - // Disallow conditional logic - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-if.md - 'jest/no-if': 'error', - // Disallow string interpolation inside snapshots - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-interpolation-in-snapshots.md - 'jest/no-interpolation-in-snapshots': 'error', - // Disallow Jasmine globals - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-jasmine-globals.md - 'jest/no-jasmine-globals': 'error', - // Disallow importing Jest - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-jest-import.md - // Rule removed from plugin - // 'jest/no-jest-import': 'error', - // Disallow large snapshots - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-large-snapshots.md - 'jest/no-large-snapshots': ['error', { maxSize: 15, inlineMaxSize: 15 }], - // Disallow manually importing from `__mocks__` - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-mocks-import.md - 'jest/no-mocks-import': 'error', - // Disallow specific matchers & modifiers - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-restricted-matchers.md - 'jest/no-restricted-matchers': ['error', {}], - // Disallow using `expect` outside of `it` or `test` blocks - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-standalone-expect.md - 'jest/no-standalone-expect': ['error', { additionalTestBlockFunctions: [] }], - // Use `.only `and `.skip` over `f` and `x` - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-test-prefixes.md - 'jest/no-test-prefixes': 'error', - // Disallow explicitly returning from tests - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-test-return-statement.md - 'jest/no-test-return-statement': 'error', - // Suggest using `toBeCalledWith()` or `toHaveBeenCalledWith()` - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-called-with.md - 'jest/prefer-called-with': 'error', - // Suggest using `expect.assertions()` OR `expect.hasAssertions() - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-expect-assertions.md - 'jest/prefer-expect-assertions': [ - 'error', - { - onlyFunctionsWithAsyncKeyword: false, - onlyFunctionsWithExpectInCallback: false, - onlyFunctionsWithExpectInLoop: false, - }, - ], - // Prefer `await expect(...).resolves` over `expect(await ...)` syntax - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-expect-resolves.md - 'jest/prefer-expect-resolves': 'error', - // Suggest having hooks before any test cases - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-hooks-on-top.md - 'jest/prefer-hooks-on-top': 'error', - // Enforce lowercase test names - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-lowercase-title.md - // Do not want to enforce lowercase titles - 'jest/prefer-lowercase-title': [ - 'off', - { - ignore: ['describe', 'test', 'it'], - allowedPrefixes: [], - ignoreTopLevelDescribe: false, - }, - ], - // Suggest using `jest.spyOn()` - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-spy-on.md - 'jest/prefer-spy-on': 'error', - // Suggest using `toStrictEqual()` - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-strict-equal.md - 'jest/prefer-strict-equal': 'error', - // Suggest using `toBe()` for primitive literals - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-to-be.md - 'jest/prefer-to-be': 'error', - // Suggest using `toContain()` - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-to-contain.md - 'jest/prefer-to-contain': 'error', - // Suggest using `toHaveLength()` - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-to-have-length.md - 'jest/prefer-to-have-length': 'error', - // Suggest using `test.todo` - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/prefer-todo.md - 'jest/prefer-todo': 'error', - // Require setup and teardown code to be within a hook - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/require-hook.md - 'jest/require-hook': ['error', { allowedFunctionCalls: [] }], - // Require a message for `toThrow()` - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/require-to-throw-message.md - 'jest/require-to-throw-message': 'error', - // Require test cases and hooks to be inside a `describe` block - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/require-top-level-describe.md - 'jest/require-top-level-describe': ['error', { maxNumberOfTopLevelDescribes: 1 }], - // Enforce valid `describe()` callback - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/valid-describe-callback.md - 'jest/valid-describe-callback': 'error', - // Enforce valid `expect() `usage - // https://github.com/jest-community/eslint-plugin-jest - 'jest/valid-expect': ['error', { alwaysAwait: false, minArgs: 1, maxArgs: 1 }], - // Ensure promises that have expectations in their chain are valid - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/valid-expect-in-promise.md - 'jest/valid-expect-in-promise': 'error', - // Enforce valid titles - // https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/valid-title.md - 'jest/valid-title': [ - 'error', - { ignoreTypeOfDescribeName: false, disallowedWords: [], mustNotMatch: {}, mustMatch: {} }, - ], - }, - }, - ], -}; diff --git a/config/eslint/repo/rules/jestPlugin.js b/config/eslint/repo/rules/jestPlugin.js new file mode 100644 index 0000000..0ca5ef1 --- /dev/null +++ b/config/eslint/repo/rules/jestPlugin.js @@ -0,0 +1,135 @@ +export default { + settings: { + jest: { version: 30 }, + }, + rules: { + // Ban expect.hasAssertions() in favor of expect.assertions(n) + // (replaces eslint-plugin-ban) + 'no-restricted-syntax': [ + 'error', + { + selector: 'ForInStatement', + message: + 'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.', + }, + { + selector: 'LabeledStatement', + message: + 'Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.', + }, + { + selector: 'WithStatement', + message: + '`with` is disallowed in strict mode because it makes code impossible to predict and optimize.', + }, + { + selector: 'CallExpression[callee.object.name="expect"][callee.property.name="hasAssertions"]', + message: 'Please use `expect.assertions(n)` instead of `expect.hasAssertions()`.', + }, + ], + + // Turn off other rules + 'max-classes-per-file': 'off', + 'no-magic-numbers': 'off', + 'sort-keys': 'off', + + // Have control over test and it usages + 'jest/consistent-test-it': ['error', { fn: 'it', withinDescribe: 'it' }], + // Enforce assertion to be made in a test body + 'jest/expect-expect': [ + 'error', + { assertFunctionNames: ['expect'], additionalTestBlockFunctions: [] }, + ], + // Enforces a maximum depth to nested describe calls + 'jest/max-nested-describe': ['off', { max: 5 }], + // Disallow alias methods + 'jest/no-alias-methods': 'error', + // Disallow commented out tests + 'jest/no-commented-out-tests': 'warn', + // Prevent calling expect conditionally + 'jest/no-conditional-expect': 'error', + // Disallow use of deprecated functions + 'jest/no-deprecated-functions': 'error', + // Disallow disabled tests + 'jest/no-disabled-tests': 'error', + // Avoid using a callback in asynchronous tests and hooks + 'jest/no-done-callback': 'error', + // Disallow duplicate setup and teardown hooks + 'jest/no-duplicate-hooks': 'error', + // Disallow focused tests + 'jest/no-focused-tests': 'error', + // Disallow setup and teardown hooks + 'jest/no-hooks': ['off', { allow: [] }], + // Disallow identical titles + 'jest/no-identical-title': 'error', + // Disallow string interpolation inside snapshots + 'jest/no-interpolation-in-snapshots': 'error', + // Disallow Jasmine globals + 'jest/no-jasmine-globals': 'error', + // Disallow large snapshots + 'jest/no-large-snapshots': ['error', { maxSize: 15, inlineMaxSize: 15 }], + // Disallow manually importing from `__mocks__` + 'jest/no-mocks-import': 'error', + // Disallow specific matchers & modifiers + 'jest/no-restricted-matchers': ['error', {}], + // Disallow using `expect` outside of `it` or `test` blocks + 'jest/no-standalone-expect': ['error', { additionalTestBlockFunctions: [] }], + // Use `.only `and `.skip` over `f` and `x` + 'jest/no-test-prefixes': 'error', + // Disallow explicitly returning from tests + 'jest/no-test-return-statement': 'error', + // Suggest using `toBeCalledWith()` or `toHaveBeenCalledWith()` + 'jest/prefer-called-with': 'error', + // Suggest using `expect.assertions()` OR `expect.hasAssertions() + 'jest/prefer-expect-assertions': [ + 'error', + { + onlyFunctionsWithAsyncKeyword: false, + onlyFunctionsWithExpectInCallback: false, + onlyFunctionsWithExpectInLoop: false, + }, + ], + // Prefer `await expect(...).resolves` over `expect(await ...)` syntax + 'jest/prefer-expect-resolves': 'error', + // Suggest having hooks before any test cases + 'jest/prefer-hooks-on-top': 'error', + // Enforce lowercase test names + 'jest/prefer-lowercase-title': [ + 'off', + { + ignore: ['describe', 'test', 'it'], + allowedPrefixes: [], + ignoreTopLevelDescribe: false, + }, + ], + // Suggest using `jest.spyOn()` + 'jest/prefer-spy-on': 'error', + // Suggest using `toStrictEqual()` + 'jest/prefer-strict-equal': 'error', + // Suggest using `toBe()` for primitive literals + 'jest/prefer-to-be': 'error', + // Suggest using `toContain()` + 'jest/prefer-to-contain': 'error', + // Suggest using `toHaveLength()` + 'jest/prefer-to-have-length': 'error', + // Suggest using `test.todo` + 'jest/prefer-todo': 'error', + // Require setup and teardown code to be within a hook + 'jest/require-hook': ['error', { allowedFunctionCalls: [] }], + // Require a message for `toThrow()` + 'jest/require-to-throw-message': 'error', + // Require test cases and hooks to be inside a `describe` block + 'jest/require-top-level-describe': ['error', { maxNumberOfTopLevelDescribes: 1 }], + // Enforce valid `describe()` callback + 'jest/valid-describe-callback': 'error', + // Enforce valid `expect() `usage + 'jest/valid-expect': ['error', { alwaysAwait: false, minArgs: 1, maxArgs: 1 }], + // Ensure promises that have expectations in their chain are valid + 'jest/valid-expect-in-promise': 'error', + // Enforce valid titles + 'jest/valid-title': [ + 'error', + { ignoreTypeOfDescribeName: false, disallowedWords: [], mustNotMatch: {}, mustMatch: {} }, + ], + }, +}; diff --git a/config/eslint/repo/rules/testingLibraryPlugin.cjs b/config/eslint/repo/rules/testingLibraryPlugin.cjs deleted file mode 100644 index 368b942..0000000 --- a/config/eslint/repo/rules/testingLibraryPlugin.cjs +++ /dev/null @@ -1,100 +0,0 @@ -module.exports = { - plugins: ['testing-library'], - settings: {}, - rules: {}, - overrides: [ - { - files: ['*.test.*', '*.spec.*'], - rules: { - // Enforce promises from async queries to be handled - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/await-async-queries.md - 'testing-library/await-async-queries': 'error', - // Enforce promises from async utils to be awaited properly - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/await-async-utils.md - 'testing-library/await-async-utils': 'error', - // Enforce promises from `fireEvent` methods to be handled - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/await-fire-event.md - // Only used for Vue - 'testing-library/await-fire-event': 'off', - // Ensures consistent usage of `data-testid` - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/consistent-data-testid.md - 'testing-library/consistent-data-testid': [ - 'error', - { testIdPattern: '', testIdAttribute: ['data-testid'] }, - ], - // Disallow unnecessary `await` for sync events - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-await-sync-events.md - 'testing-library/no-await-sync-events': 'error', - // Disallow unnecessary `await` for sync queries - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-await-sync-queries.md - 'testing-library/no-await-sync-queries': 'error', - // Disallow the use of `container` methods - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-container.md - 'testing-library/no-container': 'error', - // Disallow the use of debugging utilities like `debug` - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-debugging-utils.md - 'testing-library/no-debugging-utils': [ - 'error', - { - utilsToCheckFor: { - debug: true, - logDOM: true, - logRoles: true, - logTestingPlaygroundURL: true, - prettyDOM: true, - prettyFormat: true, - }, - }, - ], - // Disallow importing from DOM Testing Library - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-dom-import.md - 'testing-library/no-dom-import': ['error', 'react'], - // Disallow the use of `cleanup` - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-manual-cleanup.md - 'testing-library/no-manual-cleanup': 'error', - // Disallow direct Node access - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-node-access.md - 'testing-library/no-node-access': 'error', - // Disallow the use of promises passed to a `fireEvent` method - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-promise-in-fire-event.md - 'testing-library/no-promise-in-fire-event': 'error', - // Disallow the use of `render` in testing frameworks setup functions - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-render-in-lifecycle.md - 'testing-library/no-render-in-lifecycle': ['error', {}], - // Disallow wrapping Testing Library utils or empty callbacks in `act` - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-unnecessary-act.md - 'testing-library/no-unnecessary-act': ['error', { isStrict: false }], - // Disallow the use of multiple `expect` calls inside `waitFor` - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-wait-for-multiple-assertions.md - 'testing-library/no-wait-for-multiple-assertions': 'error', - // Disallow the use of side effects in `waitFor` - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-wait-for-side-effects.md - 'testing-library/no-wait-for-side-effects': 'error', - // Ensures no snapshot is generated inside of a waitFor call - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-wait-for-snapshot.md - 'testing-library/no-wait-for-snapshot': 'error', - // Suggest using explicit assertions rather than standalone queries - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/prefer-explicit-assert.md - 'testing-library/prefer-explicit-assert': ['off', {}], - // Suggest using `find(All)By*` query instead of `waitFor` + `get(All)By*` to wait for elements - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/prefer-find-by.md - 'testing-library/prefer-find-by': 'error', - // Ensure appropriate `get*`/`query*` queries are used with their respective matchers - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/prefer-presence-queries.md - 'testing-library/prefer-presence-queries': 'error', - // Suggest using `queryBy* `queries when waiting for disappearance - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/prefer-query-by-disappearance.md - 'testing-library/prefer-query-by-disappearance': 'error', - // Suggest using `screen` while querying - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/prefer-screen-queries.md - 'testing-library/prefer-screen-queries': 'error', - // Suggest using `userEvent` over `fireEvent` for simulating user interactions - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/prefer-user-event.md - 'testing-library/prefer-user-event': ['error', { allowedMethods: [] }], - // Enforce a valid naming for return value from `render` - // https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/render-result-naming-convention.md - 'testing-library/render-result-naming-convention': 'error', - }, - }, - ], -}; diff --git a/config/eslint/repo/rules/testingLibraryPlugin.js b/config/eslint/repo/rules/testingLibraryPlugin.js new file mode 100644 index 0000000..2bc8898 --- /dev/null +++ b/config/eslint/repo/rules/testingLibraryPlugin.js @@ -0,0 +1,68 @@ +export default { + rules: { + // Enforce promises from async queries to be handled + 'testing-library/await-async-queries': 'error', + // Enforce promises from async utils to be awaited properly + 'testing-library/await-async-utils': 'error', + // Enforce promises from `fireEvent` methods to be handled + // Only used for Vue + 'testing-library/await-fire-event': 'off', + // Ensures consistent usage of `data-testid` + 'testing-library/consistent-data-testid': [ + 'error', + { testIdPattern: '', testIdAttribute: ['data-testid'] }, + ], + // Disallow unnecessary `await` for sync events + 'testing-library/no-await-sync-events': 'error', + // Disallow unnecessary `await` for sync queries + 'testing-library/no-await-sync-queries': 'error', + // Disallow the use of `container` methods + 'testing-library/no-container': 'error', + // Disallow the use of debugging utilities like `debug` + 'testing-library/no-debugging-utils': [ + 'error', + { + utilsToCheckFor: { + debug: true, + logDOM: true, + logRoles: true, + logTestingPlaygroundURL: true, + prettyDOM: true, + prettyFormat: true, + }, + }, + ], + // Disallow importing from DOM Testing Library + 'testing-library/no-dom-import': ['error', 'react'], + // Disallow the use of `cleanup` + 'testing-library/no-manual-cleanup': 'error', + // Disallow direct Node access + 'testing-library/no-node-access': 'error', + // Disallow the use of promises passed to a `fireEvent` method + 'testing-library/no-promise-in-fire-event': 'error', + // Disallow the use of `render` in testing frameworks setup functions + 'testing-library/no-render-in-lifecycle': ['error', {}], + // Disallow wrapping Testing Library utils or empty callbacks in `act` + 'testing-library/no-unnecessary-act': ['error', { isStrict: false }], + // Disallow the use of multiple `expect` calls inside `waitFor` + 'testing-library/no-wait-for-multiple-assertions': 'error', + // Disallow the use of side effects in `waitFor` + 'testing-library/no-wait-for-side-effects': 'error', + // Ensures no snapshot is generated inside of a waitFor call + 'testing-library/no-wait-for-snapshot': 'error', + // Suggest using explicit assertions rather than standalone queries + 'testing-library/prefer-explicit-assert': ['off', {}], + // Suggest using `find(All)By*` query instead of `waitFor` + `get(All)By*` to wait for elements + 'testing-library/prefer-find-by': 'error', + // Ensure appropriate `get*`/`query*` queries are used with their respective matchers + 'testing-library/prefer-presence-queries': 'error', + // Suggest using `queryBy* `queries when waiting for disappearance + 'testing-library/prefer-query-by-disappearance': 'error', + // Suggest using `screen` while querying + 'testing-library/prefer-screen-queries': 'error', + // Suggest using `userEvent` over `fireEvent` for simulating user interactions + 'testing-library/prefer-user-event': ['error', { allowedMethods: [] }], + // Enforce a valid naming for return value from `render` + 'testing-library/render-result-naming-convention': 'error', + }, +}; diff --git a/config/eslint/repo/rules/unicornPlugin.cjs b/config/eslint/repo/rules/unicornPlugin.js similarity index 50% rename from config/eslint/repo/rules/unicornPlugin.cjs rename to config/eslint/repo/rules/unicornPlugin.js index 83d6374..780df63 100644 --- a/config/eslint/repo/rules/unicornPlugin.cjs +++ b/config/eslint/repo/rules/unicornPlugin.js @@ -1,33 +1,22 @@ -module.exports = { - plugins: ['unicorn'], - settings: {}, +export default { rules: { // Improve regexes by making them shorter, consistent, and safer - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/better-regex.md 'unicorn/better-regex': ['error', { sortCharacterClasses: true }], // Enforce a specific parameter name in catch clauses - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/catch-error-name.md 'unicorn/catch-error-name': ['error', { name: 'error', ignore: [] }], // Use destructured variables over properties - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-destructuring.md 'unicorn/consistent-destructuring': 'error', // Move function definitions to the highest possible scope - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md 'unicorn/consistent-function-scoping': ['error', { checkArrowFunctions: true }], // Enforce correct `Error` subclassing - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/custom-error-definition.md 'unicorn/custom-error-definition': 'error', // Enforce no spaces between braces - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/empty-brace-spaces.md 'unicorn/empty-brace-spaces': 'error', // Enforce passing a `message` value when creating a built-in error - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/error-message.md 'unicorn/error-message': 'error', // Require escape sequences to use uppercase values - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/escape-case.md 'unicorn/escape-case': 'error', // Add expiration conditions to `TODO` comments - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/expiring-todo-comments.md 'unicorn/expiring-todo-comments': [ 'error', { @@ -38,137 +27,87 @@ module.exports = { }, ], // Enforce explicitly comparing the `length` or `size` property of a value - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/explicit-length-check.md 'unicorn/explicit-length-check': ['error', { 'non-zero': 'greater-than' }], // Enforce a case style for filenames - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/filename-case.md 'unicorn/filename-case': ['error', { cases: { kebabCase: true }, ignore: [] }], - // Enforce importing index files with `.` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/import-index.md - 'unicorn/import-index': ['error', { ignoreImports: false }], // Enforce specific import styles per module - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/import-style.md - // Do not want to enforce an import style at this stage 'unicorn/import-style': 'off', // Enforce the use of new for all builtins, except `String`, `Number`, `Boolean`, `Symbol` // and `BigInt` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/new-for-builtins.md 'unicorn/new-for-builtins': 'error', // Enforce specifying rules to disable in eslint-disable comments - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-abusive-eslint-disable.md 'unicorn/no-abusive-eslint-disable': 'error', // Prevent passing a function reference directly to iterator methods - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-callback-reference.md 'unicorn/no-array-callback-reference': 'off', // Prefer `for…of` over `Array#forEach(…)` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-for-each.md 'unicorn/no-array-for-each': 'error', // Disallow using the `this` argument in array methods - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-method-this-argument.md 'unicorn/no-array-method-this-argument': 'error', // Enforce combining multiple `Array#push()` into one call - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-push-push.md - 'unicorn/no-array-push-push': ['error', { ignore: ['stream', 'this', 'this.stream'] }], + // (renamed from unicorn/no-array-push-push in v59) + 'unicorn/prefer-single-call': ['error', { ignore: ['stream', 'this', 'this.stream'] }], // Disallow `Array#reduce()` and `Array#reduceRight()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-reduce.md 'unicorn/no-array-reduce': ['off', { allowSimpleOperations: true }], // Forbid member access from await expression - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-await-expression-member.md 'unicorn/no-await-expression-member': 'error', // Do not use leading/trailing space between `console.log` parameters - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-console-spaces.md 'unicorn/no-console-spaces': 'error', // Do not use `document.cookie` directly - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-document-cookie.md 'unicorn/no-document-cookie': 'error', // Disallow empty files - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-empty-file.md 'unicorn/no-empty-file': 'error', // Do not use a `for` loop that can be replaced with a `for-of` loop - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-for-loop.md 'unicorn/no-for-loop': 'error', // Enforce the use of Unicode escapes instead of hexadecimal escapes - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-hex-escape.md 'unicorn/no-hex-escape': 'error', // Require `Array.isArray()` instead of `instanceof Array` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-instanceof-array.md 'unicorn/no-instanceof-array': 'error', // Prevent calling `EventTarget#removeEventListener()` with the result of an expression - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-invalid-remove-event-listener.md 'unicorn/no-invalid-remove-event-listener': 'error', // Disallow identifiers starting with `new` or `class` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-keyword-prefix.md 'unicorn/no-keyword-prefix': [ 'error', { disallowedPrefixes: [], checkProperties: true, onlyCamelCase: true }, ], // Disallow `if` statements as the only statement in `if` blocks without `else` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-lonely-if.md 'unicorn/no-lonely-if': 'error', // Disallow nested ternary expressions - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-nested-ternary.md // Off as conflicts with prettier 'unicorn/no-nested-ternary': 'off', // Disallow `new Array()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-new-array.md 'unicorn/no-new-array': 'error', - // Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-new-buffer.md - 'unicorn/no-new-buffer': 'error', // Disallow the use of the `null` literal - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-null.md // Off as causes issues with react returning null 'unicorn/no-null': ['off', { checkStrictEquality: false }], // Disallow the use of objects as default parameters - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-object-as-default-parameter.md 'unicorn/no-object-as-default-parameter': 'error', - // Disallow `process.exit()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-process-exit.md - // Off as an extension to a deprecated rule - 'unicorn/no-process-exit': 'off', // Forbid classes that only have static members. - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-static-only-class.md 'unicorn/no-static-only-class': 'error', // Disallow `then` property - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-thenable.md 'unicorn/no-thenable': 'error', // Disallow assigning `this` to a variable - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-this-assignment.md 'unicorn/no-this-assignment': 'error', // Disallow unreadable array destructuring - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unreadable-array-destructuring.md // Off as want to prefer destructuring 'unicorn/no-unreadable-array-destructuring': 'off', - // Disallow unsafe regular expressions - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unsafe-regex.md - 'unicorn/no-unsafe-regex': 'error', // Disallow unused object properties - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unused-properties.md 'unicorn/no-unused-properties': 'error', // Forbid useless fallback when spreading in object literals - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-fallback-in-spread.md 'unicorn/no-useless-fallback-in-spread': 'error', // Disallow useless array length check - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-length-check.md 'unicorn/no-useless-length-check': 'error', // Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-promise-resolve-reject.md 'unicorn/no-useless-promise-resolve-reject': 'error', // Disallow unnecessary spread - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-spread.md 'unicorn/no-useless-spread': 'error', // Disallow useless `undefined` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-undefined.md 'unicorn/no-useless-undefined': ['error', { checkArguments: true }], // Disallow number literals with zero fractions or dangling dots - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-zero-fractions.md 'unicorn/no-zero-fractions': 'error', // Enforce proper case for numeric literals - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/number-literal-case.md // Off as conflicts with prettier 'unicorn/number-literal-case': 'off', // Enforce the style of numeric separators by correctly grouping digits - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/numeric-separators-style.md 'unicorn/numeric-separators-style': [ 'error', { @@ -192,138 +131,89 @@ module.exports = { }, ], // Prefer `.addEventListener()` and `.removeEventListener()` over on-functions - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-add-event-listener.md 'unicorn/prefer-add-event-listener': ['error', { excludedPackages: ['koa', 'sax'] }], // Prefer `.find(…)` over the first element from `.filter(…)` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-find.md 'unicorn/prefer-array-find': 'error', // Prefer `Array#flat()` over legacy techniques to flatten arrays - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-flat.md - // Off as not targeting ES2019 'unicorn/prefer-array-flat': ['off', { functions: [] }], // Prefer `.flatMap(…)` over `.map(…).flat()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-flat-map.md - 'unicorn/prefer-flat-map': 'error', + // (renamed from unicorn/prefer-flat-map in recent versions) + 'unicorn/prefer-array-flat-map': 'error', // Prefer `Array#indexOf()` over `Array#findIndex()` when looking for the index of an item - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-index-of.md 'unicorn/prefer-array-index-of': 'error', // Prefer `.some(…)` over `.filter(…).length` check and `.find(…)` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-array-some.md 'unicorn/prefer-array-some': 'error', // Prefer `.at()` method for index access and `String#charAt()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-at.md 'unicorn/prefer-at': ['error', { checkAllIndexAccess: false, getLastElementFunctions: [] }], // Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` // over `String.fromCharCode(…)` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-code-point.md 'unicorn/prefer-code-point': 'error', // Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-date-now.md 'unicorn/prefer-date-now': 'error', // Prefer default parameters over reassignment - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-default-parameters.md 'unicorn/prefer-default-parameters': 'error', // Prefer `Node#append()` over `Node#appendChild()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-dom-node-append.md 'unicorn/prefer-dom-node-append': 'error', // Prefer using `.dataset` on DOM elements over calling attribute methods - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-dom-node-dataset.md 'unicorn/prefer-dom-node-dataset': 'error', // Prefer `childNode.remove()` over `parentNode.removeChild(childNode)` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-dom-node-remove.md 'unicorn/prefer-dom-node-remove': 'error', // Prefer `.textContent` over `.innerText` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-dom-node-text-content.md 'unicorn/prefer-dom-node-text-content': 'error', // Prefer `export…from` when re-exporting - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-export-from.md 'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: false }], // Prefer `.includes()` over `.indexOf()` and `Array#some()` when checking for existence // or non-existence - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-includes.md 'unicorn/prefer-includes': 'error', // Prefer reading a JSON file as a buffer - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-json-parse-buffer.md 'unicorn/prefer-json-parse-buffer': 'error', // Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-keyboard-event-key.md 'unicorn/prefer-keyboard-event-key': 'error', // Enforce the use of `Math.trunc` instead of bitwise operators - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-math-trunc.md 'unicorn/prefer-math-trunc': 'error', - // Prefer `.before() `over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, - // prefer one of `.before()`, ``.after()`, `.append()` or `.prepend()` over - // `insertAdjacentText()` and `insertAdjacentElement()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-modern-dom-apis.md + // Prefer `.before() `over `.insertBefore()`, `.replaceWith()` over `.replaceChild()` 'unicorn/prefer-modern-dom-apis': 'error', // Prefer JavaScript modules (ESM) over CommonJS - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-module.md 'unicorn/prefer-module': 'error', - // Prefer negative index over `.length - index` for `{String,Array,TypedArray}#slice()`, - // `Array#splice()` and `Array#at()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-negative-index.md + // Prefer negative index over `.length - index` 'unicorn/prefer-negative-index': 'error', // Prefer using the `node:` protocol when importing Node.js builtin modules - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-node-protocol.md 'unicorn/prefer-node-protocol': 'error', // Prefer `Number` static properties over global ones - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-number-properties.md - // TODO: Convert this to error once fixed 'unicorn/prefer-number-properties': 'error', // Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-object-from-entries.md 'unicorn/prefer-object-from-entries': ['error', { functions: [] }], // Prefer omitting the `catch` binding parameter - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-optional-catch-binding.md 'unicorn/prefer-optional-catch-binding': 'error', // Prefer borrowing methods from the prototype instead of the instance - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-prototype-methods.md 'unicorn/prefer-prototype-methods': 'error', - // Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over - // `.getElementsByClassName()` and `.getElementsByTagName()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-query-selector.md + // Prefer `.querySelector()` over `.getElementById()` 'unicorn/prefer-query-selector': 'error', - // Prefer `Reflect.apply()` over F`unction#apply()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-reflect-apply.md + // Prefer `Reflect.apply()` over `Function#apply()` 'unicorn/prefer-reflect-apply': 'error', // Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-regexp-test.md 'unicorn/prefer-regexp-test': 'error', // Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-set-has.md 'unicorn/prefer-set-has': 'error', // Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` - // and `String#split('')` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-spread.md 'unicorn/prefer-spread': 'error', // Prefer `String#replaceAll()` over regex searches with the global flag - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-replace-all.md - // Off as targetting ES2019 and not included until ES2021 'unicorn/prefer-string-replace-all': 'off', // Prefer `String#slice()` over `String#substr()` and `String#substring()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-slice.md 'unicorn/prefer-string-slice': 'error', // Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-starts-ends-with.md 'unicorn/prefer-string-starts-ends-with': 'error', // Prefer `String#trimStart()`/`String#trimEnd()` over `String#trimLeft()`/`String#trimRight()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-trim-start-end.md 'unicorn/prefer-string-trim-start-end': 'error', // Prefer `switch` over multiple `else-if` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-switch.md 'unicorn/prefer-switch': ['error', { minimumCases: 3, emptyDefaultCase: 'no-default-comment' }], // Prefer ternary expressions over simple `if-else` statements - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-ternary.md 'unicorn/prefer-ternary': ['error', 'always'], // Prefer top-level await over top-level promises and async function calls - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-top-level-await.md 'unicorn/prefer-top-level-await': 'error', // Enforce throwing `TypeError` in type checking conditions - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-type-error.md 'unicorn/prefer-type-error': 'error', // Prevent abbreviations - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prevent-abbreviations.md - // Don't want to prevent abbrev. currently 'unicorn/prevent-abbreviations': [ 'off', { @@ -341,23 +231,16 @@ module.exports = { }, ], // Enforce consistent relative URL style - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/relative-url-style.md 'unicorn/relative-url-style': ['error', 'always'], // Enforce using the separator argument with `Array#join()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-array-join-separator.md 'unicorn/require-array-join-separator': 'error', // Enforce using the digits argument with `Number#toFixed()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-number-to-fixed-digits-argument.md 'unicorn/require-number-to-fixed-digits-argument': 'error', // Enforce using the `targetOrigin` argument with `window.postMessage()` - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/require-post-message-target-origin.md 'unicorn/require-post-message-target-origin': 'error', // Enforce better string content - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/string-content.md - // Turned off until understand the replacements more clearly 'unicorn/string-content': ['off', { patterns: {} }], // Fix whitespace-insensitive template indentation - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/template-indent.md 'unicorn/template-indent': [ 'warn', { @@ -368,7 +251,6 @@ module.exports = { }, ], // Require `new` when throwing an error - // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/throw-new-error.md 'unicorn/throw-new-error': 'error', }, }; diff --git a/context/CHANGELOG.md b/context/CHANGELOG.md index 904f939..84a1c5b 100644 --- a/context/CHANGELOG.md +++ b/context/CHANGELOG.md @@ -5,6 +5,25 @@ When this file grows large, use grep to search — don't read linearly. --- +## [2026-04-08] — ESLint 10 Migration + Dependency Upgrades + +### Overview +Migrated ESLint from v8 (legacy `.eslintrc.cjs`) to v10 (flat config `eslint.config.js`). Upgraded the full ESLint plugin ecosystem, Jest to v30, and other tooling. Resolved CVE-2026-26996 (minimatch ReDoS vulnerability). Fixed pre-existing `fastedge-build` integration test failures caused by TypeScript `moduleResolution: node` deprecation. + +### Changes +- **ESLint 8 → 10:** Converted config from `.eslintrc.cjs` to `eslint.config.js` (flat config, ESM). Kept modular rule file structure (7 files in `config/eslint/repo/rules/`), converted all from CJS to ESM. +- **Package replacements:** `@typescript-eslint/eslint-plugin` v7 → `typescript-eslint` v8 (unified package); `eslint-plugin-import` → `eslint-plugin-import-x` (all rules renamed `import/` → `import-x/`); `eslint-plugin-ban` → native `no-restricted-syntax` AST selector +- **Removed unused deps:** `eslint-config-standard`, `eslint-plugin-n`, `eslint-plugin-only-warn`, `eslint-plugin-promise`, `ts-jest` (project uses `babel-jest`) +- **New deps:** `@stylistic/eslint-plugin` (formatting rules removed from ESLint core), `globals` (flat config environment globals) +- **Rule migrations:** ~62 formatting rules → `@stylistic/` prefix; `no-new-symbol` → `no-new-native-nonconstructor`; `no-new-object` → `no-object-constructor`; `no-return-await` → disabled (requires typed linting); `unicorn/no-array-push-push` → `unicorn/prefer-single-call` +- **Jest 29 → 30:** Upgraded `jest`, `babel-jest`, `@jest/transform`, `@types/jest`. Fixed `jest.SpyInstance` → `jest.Spied` (3 test files). Resolved existing `@jest/globals` v30 / `jest` v29 version mismatch. +- **Other upgrades:** `esbuild` 0.27 → 0.28, `globals` 16 → 17, `@stylistic/eslint-plugin` 4 → 5, `eslint-plugin-jest` 28 → 29, `eslint-plugin-unicorn` 58 → 64 +- **Stale eslint-disable comments:** Updated `import/` → `import-x/`, `@typescript-eslint/no-var-requires` → `@typescript-eslint/no-require-imports`, `quote-props` → `@stylistic/quote-props`, removed obsolete directives +- **Syntax checker fix:** Added `--ignoreDeprecations` flag (version-aware: `5.0` for TS 5.x, `6.0` for TS 6.x) to suppress `moduleResolution: node` deprecation warning. See CONTEXT_INDEX.md "Known Issues" for the long-term fix needed before TS 7. +- **CVE-2026-26996 resolved:** `minimatch` 9.0.5 eliminated from dependency tree by upgrading from `@typescript-eslint` v7 to `typescript-eslint` v8 + +--- + ## [2026-03-31] — Examples and Terminology Conventions ### Overview diff --git a/context/CONTEXT_INDEX.md b/context/CONTEXT_INDEX.md index eed715f..63d3718 100644 --- a/context/CONTEXT_INDEX.md +++ b/context/CONTEXT_INDEX.md @@ -123,6 +123,26 @@ --- +## Known Issues / Future Work + +Items that need attention. Surface these when asked "what's next" or "what needs work". + +### `moduleResolution: node` deprecation in syntax checker (HIGH PRIORITY) +- **File:** `src/utils/syntax-checker.ts` (lines 71-80) +- **Problem:** The `fastedge-build` CLI passes `--moduleResolution node` to `tsc` when validating user TypeScript files. `node` resolves to `node10`, which is deprecated since TS 5.0 and will be **removed in TypeScript 7.0**. +- **Current workaround:** We detect the user's TypeScript major version and pass `--ignoreDeprecations 5.0` (TS 5.x) or `--ignoreDeprecations 6.0` (TS 6.x). This suppresses the deprecation error but **will break when TS 7 removes `node10` entirely**. +- **Proper fix needed:** Migrate to a non-deprecated `moduleResolution` value (`bundler` or `nodenext`). This requires careful analysis because: + - `bundler` requires explicit file extensions for relative imports — may cause false type errors for users whose code uses extensionless imports + - `nodenext` requires `--module nodenext` and enforces strict ESM conventions (`.js` extensions) — more restrictive than current behavior + - The syntax checker is user-facing build tooling (not internal config) — changing resolution semantics affects all FastEdge developers +- **Decision needed:** What module resolution strategy is correct for FastEdge developer code? Consider: what do most users' tsconfigs look like? Should we match esbuild's resolution behavior (which is closest to `bundler`)? + +### Deferred package upgrades +- **semantic-release** 23 → 25: Two major versions, needs CI pipeline testing. Upgrade with `conventional-changelog-eslint` 5 → 6. +- **TypeScript** 5.8 → 6.0: High risk, wait for ecosystem (`typescript-eslint`, tooling) to stabilize. Run `npx @andrewbranch/ts5to6` migration tool when ready. + +--- + ## Search Tips - **Don't** read `CHANGELOG.md` linearly — grep for keywords diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..e96a7ba --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,140 @@ +import globals from 'globals'; +import tseslint from 'typescript-eslint'; +import stylisticPlugin from '@stylistic/eslint-plugin'; +import importXPlugin from 'eslint-plugin-import-x'; +import jestPlugin from 'eslint-plugin-jest'; +import unicornPlugin from 'eslint-plugin-unicorn'; +import testingLibrary from 'eslint-plugin-testing-library'; + +import formattingRules from './config/eslint/repo/rules/baseFormattingRules.js'; +import logicRules from './config/eslint/repo/rules/baseLogicRules.js'; +import styleRules from './config/eslint/repo/rules/baseStyleRules.js'; +import importRules from './config/eslint/repo/rules/importPlugin.js'; +import jestRules from './config/eslint/repo/rules/jestPlugin.js'; +import testingLibRules from './config/eslint/repo/rules/testingLibraryPlugin.js'; +import unicornRules from './config/eslint/repo/rules/unicornPlugin.js'; + +export default [ + // 1. Global ignores (replaces ignorePatterns) + { + ignores: [ + '**/node_modules/**', + 'config/eslint/**', + 'config/jest/**', + 'docs/**', + 'esbuild/**', + 'dist/**', + 'build/**', + '**/build/**', + 'types/**', + 'integration-tests/**', + 'bin/**', + 'lib/**', + '**/runtime/fastedge/**', + '**/runtime/StarlingMonkey/**', + 'github-pages/**', + 'eslint.config.js', + '.github/**', + '.releaserc.cjs', + ], + }, + + // 2. TypeScript-ESLint recommended (includes parser setup) + ...tseslint.configs.recommended, + + // 3. Base config for all files + { + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + globals: { + ...globals.browser, + ...globals.es2021, + global: 'readonly', + process: 'readonly', + fastedge: 'readonly', + }, + parserOptions: { + warnOnUnsupportedTypeScriptVersion: false, + }, + }, + plugins: { + '@stylistic': stylisticPlugin, + 'import-x': importXPlugin, + unicorn: unicornPlugin, + }, + settings: { + ...importRules.settings, + }, + rules: { + ...logicRules.rules, + ...styleRules.rules, + ...formattingRules.rules, + ...importRules.rules, + ...unicornRules.rules, + // Override tseslint recommended: allow ternary and short-circuit expressions as statements + '@typescript-eslint/no-unused-expressions': [ + 'error', + { + allowShortCircuit: true, + allowTernary: true, + allowTaggedTemplates: false, + enforceForJSX: true, + }, + ], + }, + }, + + // 4. Test file overrides + { + files: ['**/*.{spec,test}.{js,jsx,ts,tsx}'], + plugins: { + jest: jestPlugin, + 'testing-library': testingLibrary, + }, + languageOptions: { + globals: { + ...globals.jest, + ...globals.node, + jsdom: 'readonly', + }, + }, + settings: { + jest: jestRules.settings.jest, + }, + rules: { + ...jestRules.rules, + ...testingLibRules.rules, + '@typescript-eslint/no-explicit-any': 'off', + }, + }, + + // 5. Examples override — relaxed rules + { + files: ['examples/**/*.{js,ts,tsx}'], + languageOptions: { + globals: { + FetchEvent: 'readonly', + }, + }, + rules: { + 'import-x/extensions': 'off', + 'import-x/group-exports': 'off', + 'import-x/exports-last': 'off', + 'import-x/no-default-export': 'off', + 'import-x/unambiguous': 'off', + 'no-console': 'off', + 'prefer-destructuring': 'off', + '@typescript-eslint/no-unused-vars': 'off', + }, + }, + + // 6. Type definition files override + { + files: ['**/*.d.ts'], + rules: { + '@typescript-eslint/no-magic-numbers': 'off', + 'no-undef': ['error', { typeof: false }], + }, + }, +]; diff --git a/package.json b/package.json index 4b31a8b..03101a1 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "build:types": "tsc -p ./tsconfig.build.json", "generate:docs": "./fastedge-plugin-source/generate-docs.sh", "generate:wit-world": "npm-run-all -s wit:merge wit:bindings", - "lint": "npx eslint -c ./config/eslint/repo/.eslintrc.cjs .", + "lint": "eslint .", "prepare": "husky", "semantic-release": "semantic-release", "test:solo": "NODE_ENV=test jest -c ./config/jest/jest.config.js --", @@ -61,30 +61,27 @@ "@babel/preset-typescript": "^7.27.1", "@gmrchk/cli-testing-library": "^0.1.2", "@jest/globals": "^30.1.2", - "@jest/transform": "^29.7.0", + "@jest/transform": "^30.3.0", "@semantic-release/changelog": "^6.0.3", - "@types/jest": "^29.5.14", + "@stylistic/eslint-plugin": "^5.10.0", + "@types/jest": "^30.0.0", "@types/node": "^25.0.3", - "@typescript-eslint/eslint-plugin": "^7.18.0", - "babel-jest": "^29.7.0", + "babel-jest": "^30.3.0", "babel-plugin-transform-import-meta": "^2.3.3", "conventional-changelog-eslint": "^5.0.0", + "esbuild": "^0.28.0", "esbuild-plugin-polyfill-node": "^0.3.0", - "eslint": "^8.56.0", - "eslint-config-standard": "^17.1.0", - "eslint-plugin-ban": "^1.6.0", - "eslint-plugin-import": "^2.32.0", - "eslint-plugin-jest": "^27.6.3", - "eslint-plugin-n": "^16.6.2", - "eslint-plugin-only-warn": "^1.1.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-testing-library": "^6.2.0", - "eslint-plugin-unicorn": "^50.0.1", + "eslint": "^10.2.0", + "eslint-plugin-import-x": "^4.16.2", + "eslint-plugin-jest": "^29.15.1", + "eslint-plugin-testing-library": "^7.16.2", + "eslint-plugin-unicorn": "^64.0.0", + "globals": "^17.4.0", "husky": "^9.0.11", - "jest": "^29.7.0", + "jest": "^30.3.0", "semantic-release": "^23.0.7", - "ts-jest": "^29.4.4", - "typescript": "^5.8.2" + "typescript": "^5.8.2", + "typescript-eslint": "^8.58.1" }, "dependencies": { "@bytecodealliance/jco": "^1.2.4", @@ -93,7 +90,6 @@ "acorn-walk": "^8.2.0", "arg": "^5.0.2", "enquirer": "^2.4.1", - "esbuild": "^0.27.3", "event-target-polyfill": "^0.0.4", "magic-string": "^0.30.19", "npm-run-all": "^4.1.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10976e2..49432c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,9 +26,6 @@ importers: enquirer: specifier: ^2.4.1 version: 2.4.1 - esbuild: - specifier: ^0.27.3 - version: 0.27.3 event-target-polyfill: specifier: ^0.0.4 version: 0.0.4 @@ -61,77 +58,68 @@ importers: specifier: ^30.1.2 version: 30.2.0 '@jest/transform': - specifier: ^29.7.0 - version: 29.7.0 + specifier: ^30.3.0 + version: 30.3.0 '@semantic-release/changelog': specifier: ^6.0.3 version: 6.0.3(semantic-release@23.1.1(typescript@5.9.3)) + '@stylistic/eslint-plugin': + specifier: ^5.10.0 + version: 5.10.0(eslint@10.2.0) '@types/jest': - specifier: ^29.5.14 - version: 29.5.14 + specifier: ^30.0.0 + version: 30.0.0 '@types/node': specifier: ^25.0.3 version: 25.0.3 - '@typescript-eslint/eslint-plugin': - specifier: ^7.18.0 - version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) babel-jest: - specifier: ^29.7.0 - version: 29.7.0(@babel/core@7.28.5) + specifier: ^30.3.0 + version: 30.3.0(@babel/core@7.28.5) babel-plugin-transform-import-meta: specifier: ^2.3.3 version: 2.3.3(@babel/core@7.28.5) conventional-changelog-eslint: specifier: ^5.0.0 version: 5.0.0 + esbuild: + specifier: ^0.28.0 + version: 0.28.0 esbuild-plugin-polyfill-node: specifier: ^0.3.0 - version: 0.3.0(esbuild@0.27.3) + version: 0.3.0(esbuild@0.28.0) eslint: - specifier: ^8.56.0 - version: 8.57.1 - eslint-config-standard: - specifier: ^17.1.0 - version: 17.1.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint-plugin-n@16.6.2(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-ban: - specifier: ^1.6.0 - version: 1.6.0 - eslint-plugin-import: - specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1) + specifier: ^10.2.0 + version: 10.2.0 + eslint-plugin-import-x: + specifier: ^4.16.2 + version: 4.16.2(@typescript-eslint/utils@8.58.1(eslint@10.2.0)(typescript@5.9.3))(eslint@10.2.0) eslint-plugin-jest: - specifier: ^27.6.3 - version: 27.9.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(jest@29.7.0(@types/node@25.0.3))(typescript@5.9.3) - eslint-plugin-n: - specifier: ^16.6.2 - version: 16.6.2(eslint@8.57.1) - eslint-plugin-only-warn: - specifier: ^1.1.0 - version: 1.1.0 - eslint-plugin-promise: - specifier: ^6.1.1 - version: 6.6.0(eslint@8.57.1) + specifier: ^29.15.1 + version: 29.15.1(@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@5.9.3))(eslint@10.2.0)(typescript@5.9.3))(eslint@10.2.0)(jest@30.3.0(@types/node@25.0.3))(typescript@5.9.3) eslint-plugin-testing-library: - specifier: ^6.2.0 - version: 6.5.0(eslint@8.57.1)(typescript@5.9.3) + specifier: ^7.16.2 + version: 7.16.2(eslint@10.2.0)(typescript@5.9.3) eslint-plugin-unicorn: - specifier: ^50.0.1 - version: 50.0.1(eslint@8.57.1) + specifier: ^64.0.0 + version: 64.0.0(eslint@10.2.0) + globals: + specifier: ^17.4.0 + version: 17.4.0 husky: specifier: ^9.0.11 version: 9.1.7 jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@25.0.3) + specifier: ^30.3.0 + version: 30.3.0(@types/node@25.0.3) semantic-release: specifier: ^23.0.7 version: 23.1.1(typescript@5.9.3) - ts-jest: - specifier: ^29.4.4 - version: 29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@30.2.0)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.27.3)(jest-util@30.2.0)(jest@29.7.0(@types/node@25.0.3))(typescript@5.9.3) typescript: specifier: ^5.8.2 version: 5.9.3 + typescript-eslint: + specifier: ^8.58.1 + version: 8.58.1(eslint@10.2.0)(typescript@5.9.3) examples/ab-testing: dependencies: @@ -968,6 +956,12 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.28.0': + resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==} + 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'} @@ -980,6 +974,12 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.28.0': + resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} @@ -992,6 +992,12 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-arm@0.28.0': + resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} @@ -1004,6 +1010,12 @@ packages: cpu: [x64] os: [android] + '@esbuild/android-x64@0.28.0': + resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} @@ -1016,6 +1028,12 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.28.0': + resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} @@ -1028,6 +1046,12 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.28.0': + resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} @@ -1040,6 +1064,12 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.28.0': + resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} @@ -1052,6 +1082,12 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.28.0': + resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} @@ -1064,6 +1100,12 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.28.0': + resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} @@ -1076,6 +1118,12 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.28.0': + resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==} + 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'} @@ -1088,6 +1136,12 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.28.0': + resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==} + 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'} @@ -1100,6 +1154,12 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.28.0': + resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} @@ -1112,6 +1172,12 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.28.0': + resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} @@ -1124,6 +1190,12 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.28.0': + resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} @@ -1136,6 +1208,12 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.28.0': + resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} @@ -1148,6 +1226,12 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.28.0': + resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} @@ -1160,6 +1244,12 @@ packages: cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.28.0': + resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} @@ -1172,6 +1262,12 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.28.0': + resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} @@ -1184,6 +1280,12 @@ packages: cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.28.0': + resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} @@ -1196,6 +1298,12 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.28.0': + resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} @@ -1208,6 +1316,12 @@ packages: cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.28.0': + resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} @@ -1220,6 +1334,12 @@ packages: cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.28.0': + resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} @@ -1232,6 +1352,12 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.28.0': + resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} @@ -1244,6 +1370,12 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.28.0': + resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} @@ -1256,6 +1388,12 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.28.0': + resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} @@ -1268,8 +1406,14 @@ packages: cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.9.0': - resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + '@esbuild/win32-x64@0.28.0': + resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -1278,13 +1422,25 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/config-helpers@0.5.5': + resolution: {integrity: sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/plugin-kit@0.7.1': + resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@expressive-code/core@0.41.5': resolution: {integrity: sha512-II5TEy5eOoXiqPwqtpSqwamUd7lZS3YH3ofxR1ZyQMmygqORZn8/7SzgfF8G0kB7uKCBzFZT6RgKgCuHcJuPpA==} @@ -1320,18 +1476,21 @@ packages: peerDependencies: hono: ^4 - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@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/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead + '@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==} @@ -1470,6 +1629,10 @@ packages: cpu: [x64] os: [win32] + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + '@istanbuljs/load-nyc-config@1.1.0': resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -1478,13 +1641,13 @@ packages: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} - '@jest/console@29.7.0': - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/console@30.3.0': + resolution: {integrity: sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/core@29.7.0': - resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/core@30.3.0': + resolution: {integrity: sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -1495,67 +1658,67 @@ packages: resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/environment@29.7.0': - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/diff-sequences@30.3.0': + resolution: {integrity: sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/environment@30.2.0': resolution: {integrity: sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/expect-utils@29.7.0': - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/environment@30.3.0': + resolution: {integrity: sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/expect-utils@30.2.0': resolution: {integrity: sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/expect@29.7.0': - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect-utils@30.3.0': + resolution: {integrity: sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/expect@30.2.0': resolution: {integrity: sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/fake-timers@29.7.0': - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect@30.3.0': + resolution: {integrity: sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/fake-timers@30.2.0': resolution: {integrity: sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/fake-timers@30.3.0': + resolution: {integrity: sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/get-type@30.1.0': resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/globals@29.7.0': - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/globals@30.2.0': resolution: {integrity: sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/globals@30.3.0': + resolution: {integrity: sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/pattern@30.0.1': resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/reporters@29.7.0': - resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/reporters@30.3.0': + resolution: {integrity: sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/schemas@30.0.5': resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -1564,34 +1727,38 @@ packages: resolution: {integrity: sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/source-map@29.6.3': - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/snapshot-utils@30.3.0': + resolution: {integrity: sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/test-result@29.7.0': - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/source-map@30.0.1': + resolution: {integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/test-sequencer@29.7.0': - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-result@30.3.0': + resolution: {integrity: sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/transform@29.7.0': - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-sequencer@30.3.0': + resolution: {integrity: sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/transform@30.2.0': resolution: {integrity: sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/types@29.6.3': - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/transform@30.3.0': + resolution: {integrity: sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/types@30.2.0': resolution: {integrity: sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/types@30.3.0': + resolution: {integrity: sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1791,6 +1958,9 @@ packages: '@oxc-project/types@0.76.0': resolution: {integrity: sha512-CH3THIrSViKal8yV/Wh3FK0pFhp40nzW1MUDCik9fNuid2D/7JJXKJnfFOAvMxInGXDlvmgT6ACAzrl47TqzkQ==} + '@package-json/types@0.0.12': + resolution: {integrity: sha512-uu43FGU34B5VM9mCNjXCwLaGHYjXdNincqKLaraaCW+7S2+SmiBg1Nv8bPnmschrIfZmfKNY9f3fC376MRrObw==} + '@pagefind/darwin-arm64@1.4.0': resolution: {integrity: sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ==} cpu: [arm64] @@ -1824,6 +1994,10 @@ packages: cpu: [x64] os: [win32] + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@pkgr/core@0.2.9': resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -1974,9 +2148,6 @@ packages: cpu: [x64] os: [win32] - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} @@ -2039,9 +2210,6 @@ packages: '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - '@sinclair/typebox@0.34.45': resolution: {integrity: sha512-qJcFVfCa5jxBFSuv7S5WYbA8XdeCPmhnaVVfX/2Y6L8WYg8sk3XY2+6W0zH+3mq1Cz+YC7Ki66HfqX6IHAwnkg==} @@ -2060,12 +2228,18 @@ packages: '@sinonjs/commons@3.0.1': resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - '@sinonjs/fake-timers@10.3.0': - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - '@sinonjs/fake-timers@13.0.5': resolution: {integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==} + '@sinonjs/fake-timers@15.3.0': + resolution: {integrity: sha512-m2xozxSfCIxjDdvbhIWazlP2i2aha/iUmbl94alpsIbd3iLTfeXgfBVbwyWogB6l++istyGZqamgA/EcqYf+Bg==} + + '@stylistic/eslint-plugin@5.10.0': + resolution: {integrity: sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^9.0.0 || ^10.0.0 + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -2084,15 +2258,15 @@ packages: '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/graceful-fs@4.1.9': - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -2105,8 +2279,8 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - '@types/jest@29.5.14': - resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + '@types/jest@30.0.0': + resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==} '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} @@ -2114,9 +2288,6 @@ packages: '@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==} @@ -2141,9 +2312,6 @@ packages: '@types/sax@1.2.7': resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} - '@types/semver@7.7.1': - resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} - '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -2159,94 +2327,163 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript-eslint/eslint-plugin@7.18.0': - resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/eslint-plugin@8.58.1': + resolution: {integrity: sha512-eSkwoemjo76bdXl2MYqtxg51HNwUSkWfODUOQ3PaTLZGh9uIWWFZIjyjaJnex7wXDu+TRx+ATsnSxdN9YWfRTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser': ^8.58.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@7.18.0': - resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/parser@8.58.1': + resolution: {integrity: sha512-gGkiNMPqerb2cJSVcruigx9eHBlLG14fSdPdqMoOcBfh+vvn4iCq2C8MzUB89PrxOXk0y3GZ1yIWb9aOzL93bw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@5.62.0': - resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@typescript-eslint/scope-manager@7.18.0': - resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/type-utils@7.18.0': - resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/project-service@8.58.1': + resolution: {integrity: sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/types@5.62.0': - resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@7.18.0': - resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/scope-manager@8.58.1': + resolution: {integrity: sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@5.62.0': - resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/tsconfig-utils@8.58.1': + resolution: {integrity: sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/typescript-estree@7.18.0': - resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/type-utils@8.58.1': + resolution: {integrity: sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@5.62.0': - resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@typescript-eslint/types@8.58.1': + resolution: {integrity: sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/utils@7.18.0': - resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/typescript-estree@8.58.1': + resolution: {integrity: sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.56.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@5.62.0': - resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/utils@8.58.1': + resolution: {integrity: sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@7.18.0': - resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/visitor-keys@8.58.1': + resolution: {integrity: sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@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] + JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -2269,6 +2506,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -2289,8 +2531,8 @@ packages: ajv: optional: true - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} @@ -2364,29 +2606,9 @@ packages: array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} - array-includes@3.1.9: - resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} - engines: {node: '>= 0.4'} - array-iterate@2.0.1: resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - - 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'} - arraybuffer.prototype.slice@1.0.4: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} @@ -2417,23 +2639,19 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} - babel-jest@29.7.0: - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-jest@30.3.0: + resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.8.0 - - babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} + '@babel/core': ^7.11.0 || ^8.0.0-0 babel-plugin-istanbul@7.0.1: resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} engines: {node: '>=12'} - babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-jest-hoist@30.3.0: + resolution: {integrity: sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} babel-plugin-polyfill-corejs2@0.4.14: resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} @@ -2460,11 +2678,11 @@ packages: peerDependencies: '@babel/core': ^7.0.0 || ^8.0.0-0 - babel-preset-jest@29.6.3: - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-preset-jest@30.3.0: + resolution: {integrity: sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.11.0 || ^8.0.0-beta.1 bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -2472,6 +2690,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + base-64@1.0.0: resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} @@ -2509,8 +2731,12 @@ packages: brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@2.0.3: + resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==} + + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -2521,22 +2747,15 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - bs-logger@0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} - bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - builtin-modules@3.3.0: - resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} - engines: {node: '>=6'} - - builtins@5.1.0: - resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==} + builtin-modules@5.0.0: + resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==} + engines: {node: '>=18.20'} bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} @@ -2588,6 +2807,9 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -2608,16 +2830,16 @@ packages: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - ci-info@4.3.1: resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} engines: {node: '>=8'} - cjs-module-lexer@1.4.3: - resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} @@ -2700,6 +2922,10 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + comment-parser@1.4.6: + resolution: {integrity: sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==} + engines: {node: '>= 12.0.0'} + common-ancestor-path@1.0.1: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} @@ -2767,6 +2993,9 @@ packages: core-js-compat@3.47.0: resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} + core-js-compat@3.49.0: + resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} + core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -2783,11 +3012,6 @@ packages: typescript: optional: true - create-jest@29.7.0: - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - cross-spawn@6.0.6: resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} engines: {node: '>=4.8'} @@ -2842,14 +3066,6 @@ packages: 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'} @@ -2921,10 +3137,6 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - diff@8.0.3: resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} engines: {node: '>=0.3.1'} @@ -2940,14 +3152,6 @@ packages: dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -2976,6 +3180,9 @@ packages: duplexer2@0.1.4: resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -2992,6 +3199,9 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + emojilib@2.4.0: resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} @@ -3049,10 +3259,6 @@ packages: 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'} @@ -3078,6 +3284,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.28.0: + resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -3101,145 +3312,103 @@ packages: 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-standard@17.1.0: - resolution: {integrity: sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==} - engines: {node: '>=12.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: - eslint: ^8.0.1 - eslint-plugin-import: ^2.25.2 - eslint-plugin-n: '^15.0.0 || ^16.0.0 ' - eslint-plugin-promise: ^6.0.0 - - eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + unrs-resolver: ^1.0.0 + peerDependenciesMeta: + unrs-resolver: + optional: true - eslint-module-utils@2.12.1: - resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} - engines: {node: '>=4'} + eslint-plugin-import-x@4.16.2: + resolution: {integrity: sha512-rM9K8UBHcWKpzQzStn1YRN2T5NvdeIfSVoKu/lKF41znQXHAUcBbYXe5wd6GNjZjTrP7viQ49n1D83x/2gYgIw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' + '@typescript-eslint/utils': ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: + '@typescript-eslint/utils': optional: true eslint-import-resolver-node: optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - - eslint-plugin-ban@1.6.0: - resolution: {integrity: sha512-gZptoV+SFHOHO57/5lmPvizMvSXrjFatP9qlVQf3meL/WHo9TxSoERygrMlESl19CPh95U86asTxohT8OprwDw==} - engines: {node: '>=0.10.0'} - - 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@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@27.9.0: - resolution: {integrity: sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + eslint-plugin-jest@29.15.1: + resolution: {integrity: sha512-6BjyErCQauz3zfJvzLw/kAez2lf4LEpbHLvWBfEcG4EI0ZiRSwjoH2uZulMouU8kRkBH+S0rhqn11IhTvxKgKw==} + engines: {node: ^20.12.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@typescript-eslint/eslint-plugin': ^5.0.0 || ^6.0.0 || ^7.0.0 - eslint: ^7.0.0 || ^8.0.0 + '@typescript-eslint/eslint-plugin': ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 jest: '*' + typescript: '>=4.8.4 <7.0.0' peerDependenciesMeta: '@typescript-eslint/eslint-plugin': optional: true jest: optional: true + typescript: + optional: true - eslint-plugin-n@16.6.2: - resolution: {integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==} - engines: {node: '>=16.0.0'} - peerDependencies: - eslint: '>=7.0.0' - - eslint-plugin-only-warn@1.1.0: - resolution: {integrity: sha512-2tktqUAT+Q3hCAU0iSf4xAN1k9zOpjK5WO8104mB0rT/dGhOa09582HN5HlbxNbPRZ0THV7nLGvzugcNOSjzfA==} - engines: {node: '>=6'} - - eslint-plugin-promise@6.6.0: - resolution: {integrity: sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - - eslint-plugin-testing-library@6.5.0: - resolution: {integrity: sha512-Ls5TUfLm5/snocMAOlofSOJxNN0aKqwTlco7CrNtMjkTdQlkpSMaeTCDHCuXfzrI97xcx2rSCNeKeJjtpkNC1w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6'} + eslint-plugin-testing-library@7.16.2: + resolution: {integrity: sha512-8gleGnQXK2ZA3hHwjCwpYTZvM+9VsrJ+/9kDI8CjqAQGAdMQOdn/rJNu7ZySENuiWlGKQWyZJ4ZjEg2zamaRHw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - eslint-plugin-unicorn@50.0.1: - resolution: {integrity: sha512-KxenCZxqSYW0GWHH18okDlOQcpezcitm5aOSz6EnobyJ6BIByiPDviQRjJIUAjG/tMN11958MxaQ+qCoU6lfDA==} - engines: {node: '>=16'} + eslint-plugin-unicorn@64.0.0: + resolution: {integrity: sha512-rNZwalHh8i0UfPlhNwg5BTUO1CMdKNmjqe+TgzOTZnpKoi8VBgsW7u9qCHIdpxEzZ1uwrJrPF0uRb7l//K38gA==} + engines: {node: ^20.10.0 || >=21.0.0} peerDependencies: - eslint: '>=8.56.0' - - eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} + eslint: '>=9.38.0' - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 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@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + 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-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@10.2.0: + resolution: {integrity: sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} - estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -3302,18 +3471,18 @@ packages: resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} - exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + exit-x@0.2.2: + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} engines: {node: '>= 0.8.0'} - expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - expect@30.2.0: resolution: {integrity: sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + expect@30.3.0: + resolution: {integrity: sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + express-rate-limit@8.3.0: resolution: {integrity: sha512-KJzBawY6fB9FiZGdE/0aftepZ91YlaGIrV8vgblRM3J8X+dHx/aiowJWwkx6LIGyuqGiANsjSwwrbb8mifOJ4Q==} engines: {node: '>= 16'} @@ -3372,9 +3541,9 @@ packages: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + 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==} @@ -3404,12 +3573,12 @@ packages: resolution: {integrity: sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==} engines: {node: '>=18'} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + 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==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} flattie@1.1.1: resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} @@ -3426,6 +3595,10 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -3511,8 +3684,8 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-tsconfig@4.13.7: + resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} git-log-parser@1.2.1: resolution: {integrity: sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==} @@ -3528,22 +3701,23 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} + globals@17.4.0: + resolution: {integrity: sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==} + engines: {node: '>=18'} globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - globby@14.1.0: resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} engines: {node: '>=18'} @@ -3558,9 +3732,6 @@ packages: 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==} - h3@1.15.5: resolution: {integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==} @@ -3834,9 +4005,9 @@ packages: 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-builtin-module@5.0.0: + resolution: {integrity: sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==} + engines: {node: '>=18.20'} is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} @@ -3918,10 +4089,6 @@ packages: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} @@ -4010,10 +4177,6 @@ packages: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} - istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - istanbul-lib-instrument@6.0.3: resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} engines: {node: '>=10'} @@ -4022,29 +4185,32 @@ packages: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} - istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} engines: {node: '>=10'} istanbul-reports@3.2.0: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + java-properties@1.0.2: resolution: {integrity: sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==} engines: {node: '>= 0.6.0'} - jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-changed-files@30.3.0: + resolution: {integrity: sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-circus@30.3.0: + resolution: {integrity: sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-cli@29.7.0: - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-cli@30.3.0: + resolution: {integrity: sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -4052,78 +4218,77 @@ packages: node-notifier: optional: true - jest-config@29.7.0: - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-config@30.3.0: + resolution: {integrity: sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: '@types/node': '*' + esbuild-register: '>=3.4.0' ts-node: '>=9.0.0' peerDependenciesMeta: '@types/node': optional: true + esbuild-register: + optional: true ts-node: optional: true - jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-diff@30.2.0: resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-diff@30.3.0: + resolution: {integrity: sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-docblock@30.2.0: + resolution: {integrity: sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-each@30.3.0: + resolution: {integrity: sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-environment-node@30.3.0: + resolution: {integrity: sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-haste-map@30.2.0: resolution: {integrity: sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-haste-map@30.3.0: + resolution: {integrity: sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-leak-detector@30.3.0: + resolution: {integrity: sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-matcher-utils@30.2.0: resolution: {integrity: sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-matcher-utils@30.3.0: + resolution: {integrity: sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-message-util@30.2.0: resolution: {integrity: sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-message-util@30.3.0: + resolution: {integrity: sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-mock@30.2.0: resolution: {integrity: sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-mock@30.3.0: + resolution: {integrity: sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-pnp-resolver@1.2.3: resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} engines: {node: '>=6'} @@ -4133,65 +4298,61 @@ packages: jest-resolve: optional: true - jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-regex-util@30.0.1: resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve-dependencies@30.3.0: + resolution: {integrity: sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve@30.3.0: + resolution: {integrity: sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runner@30.3.0: + resolution: {integrity: sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runtime@30.3.0: + resolution: {integrity: sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-snapshot@30.2.0: resolution: {integrity: sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-snapshot@30.3.0: + resolution: {integrity: sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-util@30.2.0: resolution: {integrity: sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@30.3.0: + resolution: {integrity: sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-validate@30.3.0: + resolution: {integrity: sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-watcher@30.3.0: + resolution: {integrity: sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-worker@30.2.0: resolution: {integrity: sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest@29.7.0: - resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-worker@30.3.0: + resolution: {integrity: sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest@30.3.0: + resolution: {integrity: sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -4246,10 +4407,6 @@ packages: json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -4321,12 +4478,6 @@ packages: lodash.isstring@4.0.1: resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} - lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.uniqby@4.7.0: resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==} @@ -4364,9 +4515,6 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -4612,20 +4760,24 @@ packages: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} - min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + mkdirp@3.0.1: resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} engines: {node: '>=10'} @@ -4646,6 +4798,11 @@ packages: 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==} @@ -4810,18 +4967,6 @@ packages: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} 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'} - ofetch@1.5.1: resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} @@ -4937,6 +5082,9 @@ packages: 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==} + package-manager-detector@1.6.0: resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} @@ -5013,6 +5161,10 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -5093,14 +5245,14 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - pretty-format@30.2.0: resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + pretty-format@30.3.0: + resolution: {integrity: sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + pretty-ms@9.3.0: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} @@ -5130,8 +5282,8 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + pure-rand@7.0.1: + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} qs@6.15.0: resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} @@ -5167,18 +5319,10 @@ packages: engines: {node: '>=18'} deprecated: Renamed to read-package-up - read-pkg-up@7.0.1: - resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} - engines: {node: '>=8'} - read-pkg@3.0.0: resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} engines: {node: '>=4'} - read-pkg@5.2.0: - resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} - engines: {node: '>=8'} - read-pkg@9.0.1: resolution: {integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==} engines: {node: '>=18'} @@ -5247,10 +5391,6 @@ packages: regjsgen@0.8.0: resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} - regjsparser@0.10.0: - resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} - hasBin: true - regjsparser@0.13.0: resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} hasBin: true @@ -5310,10 +5450,6 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - requireindex@1.2.0: - resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} - engines: {node: '>=0.10.5'} - resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} @@ -5329,10 +5465,6 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve.exports@2.0.3: - resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} - engines: {node: '>=10'} - resolve@1.22.11: resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} @@ -5358,11 +5490,6 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rollup@4.55.1: resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -5422,6 +5549,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + send@1.2.1: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} @@ -5569,6 +5701,10 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + stable-hash-x@0.2.0: + resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} + engines: {node: '>=12.0.0'} + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -5599,6 +5735,10 @@ packages: 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-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} @@ -5653,9 +5793,9 @@ packages: resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} engines: {node: '>=18'} - strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} + strip-indent@4.1.1: + resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} + engines: {node: '>=12'} strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} @@ -5725,9 +5865,6 @@ packages: resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} engines: {node: '>=8'} - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -5777,38 +5914,11 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - ts-api-utils@1.4.3: - resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' - - ts-jest@29.4.6: - resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==} - engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} - hasBin: true + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/transform': ^29.0.0 || ^30.0.0 - '@jest/types': ^29.0.0 || ^30.0.0 - babel-jest: ^29.0.0 || ^30.0.0 - esbuild: '*' - jest: ^29.0.0 || ^30.0.0 - jest-util: ^29.0.0 || ^30.0.0 - typescript: '>=4.3 <6' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/transform': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true - jest-util: - optional: true + typescript: '>=4.8.4' tsconfck@3.1.6: resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} @@ -5820,21 +5930,9 @@ packages: typescript: optional: true - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsutils@3.21.0: - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -5843,22 +5941,10 @@ packages: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - 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@1.4.0: resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} engines: {node: '>=10'} @@ -5891,6 +5977,13 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typescript-eslint@8.58.1: + resolution: {integrity: sha512-gf6/oHChByg9HJvhMO1iBexJh12AqqTfnuxscMDOVqfJW3htsdRJI/GfPpHTTcyeB8cSTUY2JcZmVgoyPqcrDg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -5996,6 +6089,9 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + unstorage@1.17.4: resolution: {integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==} peerDependencies: @@ -6195,6 +6291,10 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + wrap-ansi@9.0.2: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} @@ -6202,10 +6302,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - write-file-atomic@5.0.1: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -7220,178 +7316,263 @@ snapshots: '@esbuild/aix-ppc64@0.27.3': optional: true + '@esbuild/aix-ppc64@0.28.0': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true '@esbuild/android-arm64@0.27.3': optional: true + '@esbuild/android-arm64@0.28.0': + optional: true + '@esbuild/android-arm@0.25.12': optional: true '@esbuild/android-arm@0.27.3': optional: true + '@esbuild/android-arm@0.28.0': + optional: true + '@esbuild/android-x64@0.25.12': optional: true '@esbuild/android-x64@0.27.3': optional: true + '@esbuild/android-x64@0.28.0': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true '@esbuild/darwin-arm64@0.27.3': optional: true + '@esbuild/darwin-arm64@0.28.0': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true '@esbuild/darwin-x64@0.27.3': optional: true + '@esbuild/darwin-x64@0.28.0': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true '@esbuild/freebsd-arm64@0.27.3': optional: true + '@esbuild/freebsd-arm64@0.28.0': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true '@esbuild/freebsd-x64@0.27.3': optional: true + '@esbuild/freebsd-x64@0.28.0': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true '@esbuild/linux-arm64@0.27.3': optional: true + '@esbuild/linux-arm64@0.28.0': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true '@esbuild/linux-arm@0.27.3': optional: true + '@esbuild/linux-arm@0.28.0': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true '@esbuild/linux-ia32@0.27.3': optional: true + '@esbuild/linux-ia32@0.28.0': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true '@esbuild/linux-loong64@0.27.3': optional: true + '@esbuild/linux-loong64@0.28.0': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true '@esbuild/linux-mips64el@0.27.3': optional: true + '@esbuild/linux-mips64el@0.28.0': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true '@esbuild/linux-ppc64@0.27.3': optional: true + '@esbuild/linux-ppc64@0.28.0': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true '@esbuild/linux-riscv64@0.27.3': optional: true + '@esbuild/linux-riscv64@0.28.0': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true '@esbuild/linux-s390x@0.27.3': optional: true + '@esbuild/linux-s390x@0.28.0': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true '@esbuild/linux-x64@0.27.3': optional: true + '@esbuild/linux-x64@0.28.0': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true '@esbuild/netbsd-arm64@0.27.3': optional: true + '@esbuild/netbsd-arm64@0.28.0': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true '@esbuild/netbsd-x64@0.27.3': optional: true + '@esbuild/netbsd-x64@0.28.0': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true '@esbuild/openbsd-arm64@0.27.3': optional: true + '@esbuild/openbsd-arm64@0.28.0': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true '@esbuild/openbsd-x64@0.27.3': optional: true + '@esbuild/openbsd-x64@0.28.0': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true '@esbuild/openharmony-arm64@0.27.3': optional: true + '@esbuild/openharmony-arm64@0.28.0': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true '@esbuild/sunos-x64@0.27.3': optional: true + '@esbuild/sunos-x64@0.28.0': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true '@esbuild/win32-arm64@0.27.3': optional: true + '@esbuild/win32-arm64@0.28.0': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true '@esbuild/win32-ia32@0.27.3': optional: true + '@esbuild/win32-ia32@0.28.0': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true '@esbuild/win32-x64@0.27.3': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@8.57.1)': + '@esbuild/win32-x64@0.28.0': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@10.2.0)': dependencies: - eslint: 8.57.1 + eslint: 10.2.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/eslintrc@2.1.4': + '@eslint/config-array@0.23.5': dependencies: - ajv: 6.12.6 + '@eslint/object-schema': 3.0.5 debug: 4.4.3 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 + minimatch: 10.2.5 transitivePeerDependencies: - supports-color - '@eslint/js@8.57.1': {} + '@eslint/config-helpers@0.5.5': + dependencies: + '@eslint/core': 1.2.1 + + '@eslint/core@1.2.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/object-schema@3.0.5': {} + + '@eslint/plugin-kit@0.7.1': + dependencies: + '@eslint/core': 1.2.1 + levn: 0.4.1 '@expressive-code/core@0.41.5': dependencies: @@ -7449,17 +7630,16 @@ snapshots: dependencies: hono: 4.12.5 - '@humanwhocodes/config-array@0.13.0': + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.3 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@2.0.3': {} + '@humanwhocodes/retry@0.4.3': {} '@img/colour@1.0.0': {} @@ -7557,6 +7737,15 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true + '@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 + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 @@ -7567,58 +7756,53 @@ snapshots: '@istanbuljs/schema@0.1.3': {} - '@jest/console@29.7.0': + '@jest/console@30.3.0': dependencies: - '@jest/types': 29.6.3 + '@jest/types': 30.3.0 '@types/node': 25.0.3 chalk: 4.1.2 - jest-message-util: 29.7.0 - jest-util: 29.7.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 slash: 3.0.0 - '@jest/core@29.7.0': + '@jest/core@30.3.0': dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.3.0 + '@jest/pattern': 30.0.1 + '@jest/reporters': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 '@types/node': 25.0.3 ansi-escapes: 4.3.2 chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 + ci-info: 4.4.0 + exit-x: 0.2.2 graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@25.0.3) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 + jest-changed-files: 30.3.0 + jest-config: 30.3.0(@types/node@25.0.3) + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-resolve-dependencies: 30.3.0 + jest-runner: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + jest-watcher: 30.3.0 + pretty-format: 30.3.0 slash: 3.0.0 - strip-ansi: 6.0.1 transitivePeerDependencies: - babel-plugin-macros + - esbuild-register - supports-color - ts-node '@jest/diff-sequences@30.0.1': {} - '@jest/environment@29.7.0': - dependencies: - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 25.0.3 - jest-mock: 29.7.0 + '@jest/diff-sequences@30.3.0': {} '@jest/environment@30.2.0': dependencies: @@ -7627,20 +7811,20 @@ snapshots: '@types/node': 25.0.3 jest-mock: 30.2.0 - '@jest/expect-utils@29.7.0': + '@jest/environment@30.3.0': dependencies: - jest-get-type: 29.6.3 + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 25.0.3 + jest-mock: 30.3.0 '@jest/expect-utils@30.2.0': dependencies: '@jest/get-type': 30.1.0 - '@jest/expect@29.7.0': + '@jest/expect-utils@30.3.0': dependencies: - expect: 29.7.0 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color + '@jest/get-type': 30.1.0 '@jest/expect@30.2.0': dependencies: @@ -7649,14 +7833,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@jest/fake-timers@29.7.0': + '@jest/expect@30.3.0': dependencies: - '@jest/types': 29.6.3 - '@sinonjs/fake-timers': 10.3.0 - '@types/node': 25.0.3 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-util: 29.7.0 + expect: 30.3.0 + jest-snapshot: 30.3.0 + transitivePeerDependencies: + - supports-color '@jest/fake-timers@30.2.0': dependencies: @@ -7667,16 +7849,16 @@ snapshots: jest-mock: 30.2.0 jest-util: 30.2.0 - '@jest/get-type@30.1.0': {} - - '@jest/globals@29.7.0': + '@jest/fake-timers@30.3.0': dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/types': 29.6.3 - jest-mock: 29.7.0 - transitivePeerDependencies: - - supports-color + '@jest/types': 30.3.0 + '@sinonjs/fake-timers': 15.3.0 + '@types/node': 25.0.3 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + + '@jest/get-type@30.1.0': {} '@jest/globals@30.2.0': dependencies: @@ -7687,44 +7869,48 @@ snapshots: transitivePeerDependencies: - supports-color + '@jest/globals@30.3.0': + dependencies: + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/types': 30.3.0 + jest-mock: 30.3.0 + transitivePeerDependencies: + - supports-color + '@jest/pattern@30.0.1': dependencies: '@types/node': 25.0.3 jest-regex-util: 30.0.1 - '@jest/reporters@29.7.0': + '@jest/reporters@30.3.0': dependencies: '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 '@jridgewell/trace-mapping': 0.3.31 '@types/node': 25.0.3 chalk: 4.1.2 collect-v8-coverage: 1.0.3 - exit: 0.1.2 - glob: 7.2.3 + exit-x: 0.2.2 + glob: 10.5.0 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 istanbul-lib-instrument: 6.0.3 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 + istanbul-lib-source-maps: 5.0.6 istanbul-reports: 3.2.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - jest-worker: 29.7.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + jest-worker: 30.3.0 slash: 3.0.0 string-length: 4.0.2 - strip-ansi: 6.0.1 v8-to-istanbul: 9.3.0 transitivePeerDependencies: - supports-color - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.8 - '@jest/schemas@30.0.5': dependencies: '@sinclair/typebox': 0.34.45 @@ -7736,76 +7922,83 @@ snapshots: graceful-fs: 4.2.11 natural-compare: 1.4.0 - '@jest/source-map@29.6.3': + '@jest/snapshot-utils@30.3.0': + dependencies: + '@jest/types': 30.3.0 + chalk: 4.1.2 + graceful-fs: 4.2.11 + natural-compare: 1.4.0 + + '@jest/source-map@30.0.1': dependencies: '@jridgewell/trace-mapping': 0.3.31 callsites: 3.1.0 graceful-fs: 4.2.11 - '@jest/test-result@29.7.0': + '@jest/test-result@30.3.0': dependencies: - '@jest/console': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.3.0 + '@jest/types': 30.3.0 '@types/istanbul-lib-coverage': 2.0.6 collect-v8-coverage: 1.0.3 - '@jest/test-sequencer@29.7.0': + '@jest/test-sequencer@30.3.0': dependencies: - '@jest/test-result': 29.7.0 + '@jest/test-result': 30.3.0 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 + jest-haste-map: 30.3.0 slash: 3.0.0 - '@jest/transform@29.7.0': + '@jest/transform@30.2.0': dependencies: '@babel/core': 7.28.5 - '@jest/types': 29.6.3 + '@jest/types': 30.2.0 '@jridgewell/trace-mapping': 0.3.31 - babel-plugin-istanbul: 6.1.1 + babel-plugin-istanbul: 7.0.1 chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 + jest-haste-map: 30.2.0 + jest-regex-util: 30.0.1 + jest-util: 30.2.0 micromatch: 4.0.8 pirates: 4.0.7 slash: 3.0.0 - write-file-atomic: 4.0.2 + write-file-atomic: 5.0.1 transitivePeerDependencies: - supports-color - '@jest/transform@30.2.0': + '@jest/transform@30.3.0': dependencies: '@babel/core': 7.28.5 - '@jest/types': 30.2.0 + '@jest/types': 30.3.0 '@jridgewell/trace-mapping': 0.3.31 babel-plugin-istanbul: 7.0.1 chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 - jest-haste-map: 30.2.0 + jest-haste-map: 30.3.0 jest-regex-util: 30.0.1 - jest-util: 30.2.0 - micromatch: 4.0.8 + jest-util: 30.3.0 pirates: 4.0.7 slash: 3.0.0 write-file-atomic: 5.0.1 transitivePeerDependencies: - supports-color - '@jest/types@29.6.3': + '@jest/types@30.2.0': dependencies: - '@jest/schemas': 29.6.3 + '@jest/pattern': 30.0.1 + '@jest/schemas': 30.0.5 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 '@types/node': 25.0.3 '@types/yargs': 17.0.35 chalk: 4.1.2 - '@jest/types@30.2.0': + '@jest/types@30.3.0': dependencies: '@jest/pattern': 30.0.1 '@jest/schemas': 30.0.5 @@ -8028,6 +8221,8 @@ snapshots: '@oxc-project/types@0.76.0': {} + '@package-json/types@0.0.12': {} + '@pagefind/darwin-arm64@1.4.0': optional: true @@ -8048,6 +8243,9 @@ snapshots: '@pagefind/windows-x64@1.4.0': optional: true + '@pkgjs/parseargs@0.11.0': + optional: true + '@pkgr/core@0.2.9': {} '@pnpm/config.env-replace@1.1.0': {} @@ -8145,8 +8343,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.55.1': optional: true - '@rtsao/scc@1.1.0': {} - '@sec-ant/readable-stream@0.4.1': {} '@semantic-release/changelog@6.0.3(semantic-release@23.1.1(typescript@5.9.3))': @@ -8262,8 +8458,6 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} - '@sinclair/typebox@0.27.8': {} - '@sinclair/typebox@0.34.45': {} '@sindresorhus/is@4.6.0': {} @@ -8276,14 +8470,24 @@ snapshots: dependencies: type-detect: 4.0.8 - '@sinonjs/fake-timers@10.3.0': + '@sinonjs/fake-timers@13.0.5': dependencies: '@sinonjs/commons': 3.0.1 - '@sinonjs/fake-timers@13.0.5': + '@sinonjs/fake-timers@15.3.0': dependencies: '@sinonjs/commons': 3.0.1 + '@stylistic/eslint-plugin@5.10.0(eslint@10.2.0)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0) + '@typescript-eslint/types': 8.58.1 + eslint: 10.2.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + estraverse: 5.3.0 + picomatch: 4.0.3 + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -8314,16 +8518,14 @@ snapshots: dependencies: '@types/ms': 2.1.0 + '@types/esrecurse@4.3.1': {} + '@types/estree-jsx@1.0.5': dependencies: '@types/estree': 1.0.8 '@types/estree@1.0.8': {} - '@types/graceful-fs@4.1.9': - dependencies: - '@types/node': 25.0.3 - '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -8338,17 +8540,15 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 - '@types/jest@29.5.14': + '@types/jest@30.0.0': dependencies: - expect: 29.7.0 - pretty-format: 29.7.0 + expect: 30.2.0 + pretty-format: 30.2.0 '@types/js-yaml@4.0.9': {} '@types/json-schema@7.0.15': {} - '@types/json5@0.0.29': {} - '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -8373,8 +8573,6 @@ snapshots: dependencies: '@types/node': 25.0.3 - '@types/semver@7.7.1': {} - '@types/stack-utils@2.0.3': {} '@types/unist@2.0.11': {} @@ -8387,129 +8585,157 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@5.9.3))(eslint@10.2.0)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/type-utils': 7.18.0(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 7.18.0 - eslint: 8.57.1 - graphemer: 1.4.0 - ignore: 5.3.2 + '@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.58.1 + '@typescript-eslint/type-utils': 8.58.1(eslint@10.2.0)(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.58.1 + eslint: 10.2.0 + ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 1.4.3(typescript@5.9.3) - optionalDependencies: + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 7.18.0 + '@typescript-eslint/scope-manager': 8.58.1 + '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.58.1 debug: 4.4.3 - eslint: 8.57.1 - optionalDependencies: + eslint: 10.2.0 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@5.62.0': - dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - - '@typescript-eslint/scope-manager@7.18.0': + '@typescript-eslint/project-service@8.58.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 - - '@typescript-eslint/type-utils@7.18.0(eslint@8.57.1)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.9.3) - '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@5.9.3) + '@typescript-eslint/types': 8.58.1 debug: 4.4.3 - eslint: 8.57.1 - ts-api-utils: 1.4.3(typescript@5.9.3) - optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@5.62.0': {} + '@typescript-eslint/scope-manager@8.58.1': + dependencies: + '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/visitor-keys': 8.58.1 - '@typescript-eslint/types@7.18.0': {} + '@typescript-eslint/tsconfig-utils@8.58.1(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 - '@typescript-eslint/typescript-estree@5.62.0(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.58.1(eslint@10.2.0)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 + '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@5.9.3) debug: 4.4.3 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.7.3 - tsutils: 3.21.0(typescript@5.9.3) - optionalDependencies: + eslint: 10.2.0 + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.18.0(typescript@5.9.3)': + '@typescript-eslint/types@8.58.1': {} + + '@typescript-eslint/typescript-estree@8.58.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 + '@typescript-eslint/project-service': 8.58.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@5.9.3) + '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/visitor-keys': 8.58.1 debug: 4.4.3 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.5 + minimatch: 10.2.5 semver: 7.7.3 - ts-api-utils: 1.4.3(typescript@5.9.3) - optionalDependencies: + tinyglobby: 0.2.15 + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/utils@8.58.1(eslint@10.2.0)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) - '@types/json-schema': 7.0.15 - '@types/semver': 7.7.1 - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.3) - eslint: 8.57.1 - eslint-scope: 5.1.1 - semver: 7.7.3 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0) + '@typescript-eslint/scope-manager': 8.58.1 + '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) + eslint: 10.2.0 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - - typescript - '@typescript-eslint/utils@7.18.0(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/visitor-keys@8.58.1': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.9.3) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript + '@typescript-eslint/types': 8.58.1 + eslint-visitor-keys: 5.0.1 - '@typescript-eslint/visitor-keys@5.62.0': - dependencies: - '@typescript-eslint/types': 5.62.0 - eslint-visitor-keys: 3.4.3 + '@ungap/structured-clone@1.3.0': {} + + '@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 - '@typescript-eslint/visitor-keys@7.18.0': + '@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: - '@typescript-eslint/types': 7.18.0 - eslint-visitor-keys: 3.4.3 + '@napi-rs/wasm-runtime': 0.2.12 + optional: true - '@ungap/structured-clone@1.3.0': {} + '@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 JSONStream@1.3.5: dependencies: @@ -8525,12 +8751,18 @@ snapshots: dependencies: acorn: 8.15.0 + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + acorn-walk@8.3.4: dependencies: acorn: 8.15.0 acorn@8.15.0: {} + acorn@8.16.0: {} + agent-base@7.1.4: {} aggregate-error@3.1.0: @@ -8547,7 +8779,7 @@ snapshots: optionalDependencies: ajv: 8.18.0 - ajv@6.12.6: + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 @@ -8617,45 +8849,8 @@ snapshots: array-ify@1.0.0: {} - 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.1 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - is-string: 1.1.1 - math-intrinsics: 1.1.0 - array-iterate@2.0.1: {} - array-union@2.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.1 - 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.1 - 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.1 - es-shim-unscopables: 1.1.0 - arraybuffer.prototype.slice@1.0.4: dependencies: array-buffer-byte-length: 1.0.2 @@ -8783,29 +8978,19 @@ snapshots: axobject-query@4.1.0: {} - babel-jest@29.7.0(@babel/core@7.28.5): + babel-jest@30.3.0(@babel/core@7.28.5): dependencies: '@babel/core': 7.28.5 - '@jest/transform': 29.7.0 + '@jest/transform': 30.3.0 '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.28.5) + babel-plugin-istanbul: 7.0.1 + babel-preset-jest: 30.3.0(@babel/core@7.28.5) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 transitivePeerDependencies: - supports-color - babel-plugin-istanbul@6.1.1: - dependencies: - '@babel/helper-plugin-utils': 7.27.1 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - babel-plugin-istanbul@7.0.1: dependencies: '@babel/helper-plugin-utils': 7.27.1 @@ -8816,12 +9001,9 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-jest-hoist@29.6.3: + babel-plugin-jest-hoist@30.3.0: dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.28.0 babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5): dependencies: @@ -8872,16 +9054,18 @@ snapshots: '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.5) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.5) - babel-preset-jest@29.6.3(@babel/core@7.28.5): + babel-preset-jest@30.3.0(@babel/core@7.28.5): dependencies: '@babel/core': 7.28.5 - babel-plugin-jest-hoist: 29.6.3 + babel-plugin-jest-hoist: 30.3.0 babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.5) bail@2.0.2: {} balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + base-64@1.0.0: {} baseline-browser-mapping@2.9.11: {} @@ -8932,10 +9116,14 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.2: + brace-expansion@2.0.3: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -8948,21 +9136,13 @@ snapshots: node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) - bs-logger@0.2.6: - dependencies: - fast-json-stable-stringify: 2.1.0 - bser@2.1.1: dependencies: node-int64: 0.4.0 buffer-from@1.1.2: {} - builtin-modules@3.3.0: {} - - builtins@5.1.0: - dependencies: - semver: 7.7.3 + builtin-modules@5.0.0: {} bytes@3.1.2: {} @@ -9008,6 +9188,8 @@ snapshots: chalk@5.6.2: {} + change-case@5.4.4: {} + char-regex@1.0.2: {} character-entities-html4@2.1.0: {} @@ -9022,11 +9204,11 @@ snapshots: dependencies: readdirp: 5.0.0 - ci-info@3.9.0: {} - ci-info@4.3.1: {} - cjs-module-lexer@1.4.3: {} + ci-info@4.4.0: {} + + cjs-module-lexer@2.2.0: {} clean-regexp@1.0.0: dependencies: @@ -9101,6 +9283,8 @@ snapshots: commander@2.20.3: {} + comment-parser@1.4.6: {} + common-ancestor-path@1.0.1: {} compare-func@2.0.0: @@ -9159,6 +9343,10 @@ snapshots: dependencies: browserslist: 4.28.1 + core-js-compat@3.49.0: + dependencies: + browserslist: 4.28.1 + core-util-is@1.0.3: {} cors@2.8.6: @@ -9175,21 +9363,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - create-jest@29.7.0(@types/node@25.0.3): - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@25.0.3) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - cross-spawn@6.0.6: dependencies: nice-try: 1.0.5 @@ -9258,10 +9431,6 @@ snapshots: 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 @@ -9312,8 +9481,6 @@ snapshots: dependencies: dequal: 2.0.3 - diff-sequences@29.6.3: {} - diff@8.0.3: {} dir-glob@3.0.1: @@ -9324,14 +9491,6 @@ snapshots: dlv@1.1.3: {} - doctrine@2.1.0: - dependencies: - esutils: 2.0.3 - - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -9366,6 +9525,8 @@ snapshots: dependencies: readable-stream: 2.3.8 + eastasianwidth@0.2.0: {} + ee-first@1.1.1: {} electron-to-chromium@1.5.267: {} @@ -9376,6 +9537,8 @@ snapshots: emoji-regex@8.0.0: {} + emoji-regex@9.2.2: {} + emojilib@2.4.0: {} encodeurl@2.0.0: {} @@ -9476,10 +9639,6 @@ snapshots: 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 @@ -9500,10 +9659,10 @@ snapshots: esast-util-from-estree: 2.0.0 vfile-message: 4.0.3 - esbuild-plugin-polyfill-node@0.3.0(esbuild@0.27.3): + esbuild-plugin-polyfill-node@0.3.0(esbuild@0.28.0): dependencies: '@jspm/core': 2.1.0 - esbuild: 0.27.3 + esbuild: 0.28.0 import-meta-resolve: 3.1.1 esbuild@0.25.12: @@ -9564,6 +9723,35 @@ snapshots: '@esbuild/win32-ia32': 0.27.3 '@esbuild/win32-x64': 0.27.3 + esbuild@0.28.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.0 + '@esbuild/android-arm': 0.28.0 + '@esbuild/android-arm64': 0.28.0 + '@esbuild/android-x64': 0.28.0 + '@esbuild/darwin-arm64': 0.28.0 + '@esbuild/darwin-x64': 0.28.0 + '@esbuild/freebsd-arm64': 0.28.0 + '@esbuild/freebsd-x64': 0.28.0 + '@esbuild/linux-arm': 0.28.0 + '@esbuild/linux-arm64': 0.28.0 + '@esbuild/linux-ia32': 0.28.0 + '@esbuild/linux-loong64': 0.28.0 + '@esbuild/linux-mips64el': 0.28.0 + '@esbuild/linux-ppc64': 0.28.0 + '@esbuild/linux-riscv64': 0.28.0 + '@esbuild/linux-s390x': 0.28.0 + '@esbuild/linux-x64': 0.28.0 + '@esbuild/netbsd-arm64': 0.28.0 + '@esbuild/netbsd-x64': 0.28.0 + '@esbuild/openbsd-arm64': 0.28.0 + '@esbuild/openbsd-x64': 0.28.0 + '@esbuild/openharmony-arm64': 0.28.0 + '@esbuild/sunos-x64': 0.28.0 + '@esbuild/win32-arm64': 0.28.0 + '@esbuild/win32-ia32': 0.28.0 + '@esbuild/win32-x64': 0.28.0 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -9576,202 +9764,134 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-compat-utils@0.5.1(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - semver: 7.7.3 - - eslint-config-standard@17.1.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint-plugin-n@16.6.2(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1) - eslint-plugin-n: 16.6.2(eslint@8.57.1) - eslint-plugin-promise: 6.6.0(eslint@8.57.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-module-utils@2.12.1(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): + eslint-import-context@0.1.9(unrs-resolver@1.11.1): dependencies: - debug: 3.2.7 + get-tsconfig: 4.13.7 + stable-hash-x: 0.2.0 optionalDependencies: - '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.9.3) - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color + unrs-resolver: 1.11.1 - eslint-plugin-ban@1.6.0: + eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.58.1(eslint@10.2.0)(typescript@5.9.3))(eslint@10.2.0): dependencies: - requireindex: 1.2.0 - - eslint-plugin-es-x@7.8.0(eslint@8.57.1): - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.2 - eslint: 8.57.1 - eslint-compat-utils: 0.5.1(eslint@8.57.1) - - eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.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: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) - hasown: 2.0.2 - is-core-module: 2.16.1 + '@package-json/types': 0.0.12 + '@typescript-eslint/types': 8.58.1 + comment-parser: 1.4.6 + debug: 4.4.3 + eslint: 10.2.0 + eslint-import-context: 0.1.9(unrs-resolver@1.11.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 + minimatch: 10.2.5 + semver: 7.7.3 + stable-hash-x: 0.2.0 + unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@5.9.3) transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - supports-color - eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(jest@29.7.0(@types/node@25.0.3))(typescript@5.9.3): + eslint-plugin-jest@29.15.1(@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@5.9.3))(eslint@10.2.0)(typescript@5.9.3))(eslint@10.2.0)(jest@30.3.0(@types/node@25.0.3))(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.9.3) - eslint: 8.57.1 + '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@5.9.3) + eslint: 10.2.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) - jest: 29.7.0(@types/node@25.0.3) - transitivePeerDependencies: - - supports-color - - typescript - - eslint-plugin-n@16.6.2(eslint@8.57.1): - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) - builtins: 5.1.0 - eslint: 8.57.1 - eslint-plugin-es-x: 7.8.0(eslint@8.57.1) - get-tsconfig: 4.13.0 - globals: 13.24.0 - ignore: 5.3.2 - is-builtin-module: 3.2.1 - is-core-module: 2.16.1 - minimatch: 3.1.2 - resolve: 1.22.11 - semver: 7.7.3 - - eslint-plugin-only-warn@1.1.0: {} - - eslint-plugin-promise@6.6.0(eslint@8.57.1): - dependencies: - eslint: 8.57.1 + '@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@5.9.3))(eslint@10.2.0)(typescript@5.9.3) + jest: 30.3.0(@types/node@25.0.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color - eslint-plugin-testing-library@6.5.0(eslint@8.57.1)(typescript@5.9.3): + eslint-plugin-testing-library@7.16.2(eslint@10.2.0)(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.9.3) - eslint: 8.57.1 + '@typescript-eslint/scope-manager': 8.58.1 + '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@5.9.3) + eslint: 10.2.0 transitivePeerDependencies: - supports-color - typescript - eslint-plugin-unicorn@50.0.1(eslint@8.57.1): + eslint-plugin-unicorn@64.0.0(eslint@10.2.0): dependencies: '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) - '@eslint/eslintrc': 2.1.4 - ci-info: 4.3.1 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0) + change-case: 5.4.4 + ci-info: 4.4.0 clean-regexp: 1.0.0 - core-js-compat: 3.47.0 - eslint: 8.57.1 - esquery: 1.6.0 - indent-string: 4.0.0 - is-builtin-module: 3.2.1 + core-js-compat: 3.49.0 + eslint: 10.2.0 + find-up-simple: 1.0.1 + globals: 17.4.0 + indent-string: 5.0.0 + is-builtin-module: 5.0.0 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 - transitivePeerDependencies: - - supports-color - - eslint-scope@5.1.1: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 + regjsparser: 0.13.0 + semver: 7.7.4 + strip-indent: 4.1.1 - eslint-scope@7.2.2: + eslint-scope@9.1.2: dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.8 esrecurse: 4.3.0 estraverse: 5.3.0 eslint-visitor-keys@3.4.3: {} - eslint@8.57.1: + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@10.2.0: dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0) '@eslint-community/regexpp': 4.12.2 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.5.5 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.1 + '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.3.0 - ajv: 6.12.6 - chalk: 4.1.2 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.14.0 cross-spawn: 7.0.6 debug: 4.4.3 - doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.6.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 + file-entry-cache: 8.0.0 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.1 json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 10.2.5 natural-compare: 1.4.0 optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 transitivePeerDependencies: - supports-color - espree@9.6.1: + espree@10.4.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 3.4.3 + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 4.2.1 + + espree@11.2.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 5.0.1 esprima@4.0.1: {} - esquery@1.6.0: + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -9779,8 +9899,6 @@ snapshots: dependencies: estraverse: 5.3.0 - estraverse@4.3.0: {} - estraverse@5.3.0: {} estree-util-attach-comments@3.0.0: @@ -9871,15 +9989,7 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.2 - exit@0.1.2: {} - - expect@29.7.0: - dependencies: - '@jest/expect-utils': 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 + exit-x@0.2.2: {} expect@30.2.0: dependencies: @@ -9890,6 +10000,15 @@ snapshots: jest-mock: 30.2.0 jest-util: 30.2.0 + expect@30.3.0: + dependencies: + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + express-rate-limit@8.3.0(express@5.2.1): dependencies: express: 5.2.1 @@ -9975,9 +10094,9 @@ snapshots: dependencies: is-unicode-supported: 2.1.0 - file-entry-cache@6.0.1: + file-entry-cache@8.0.0: dependencies: - flat-cache: 3.2.0 + flat-cache: 4.0.1 fill-range@7.1.1: dependencies: @@ -10015,13 +10134,12 @@ snapshots: semver-regex: 4.0.5 super-regex: 1.1.0 - flat-cache@3.2.0: + flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.4.2 keyv: 4.5.4 - rimraf: 3.0.2 - flatted@3.3.3: {} + flatted@3.4.2: {} flattie@1.1.1: {} @@ -10037,6 +10155,11 @@ snapshots: dependencies: is-callable: 1.2.7 + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + forwarded@0.2.0: {} fresh@2.0.0: {} @@ -10117,7 +10240,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-tsconfig@4.13.0: + get-tsconfig@4.13.7: dependencies: resolve-pkg-maps: 1.0.0 @@ -10140,6 +10263,15 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -10149,24 +10281,13 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 - globals@13.24.0: - dependencies: - type-fest: 0.20.2 + globals@17.4.0: {} globalthis@1.0.4: dependencies: define-properties: 1.2.1 gopd: 1.2.0 - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - globby@14.1.0: dependencies: '@sindresorhus/merge-streams': 2.3.0 @@ -10182,8 +10303,6 @@ snapshots: graceful-fs@4.2.11: {} - graphemer@1.4.0: {} - h3@1.15.5: dependencies: cookie-es: 1.2.2 @@ -10575,9 +10694,9 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 - is-builtin-module@3.2.1: + is-builtin-module@5.0.0: dependencies: - builtin-modules: 3.3.0 + builtin-modules: 5.0.0 is-callable@1.2.7: {} @@ -10643,8 +10762,6 @@ snapshots: is-obj@2.0.0: {} - is-path-inside@3.0.3: {} - is-plain-obj@4.1.0: {} is-promise@4.0.0: {} @@ -10722,23 +10839,13 @@ snapshots: istanbul-lib-coverage@3.2.2: {} - istanbul-lib-instrument@5.2.1: - dependencies: - '@babel/core': 7.28.5 - '@babel/parser': 7.28.5 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - istanbul-lib-instrument@6.0.3: dependencies: '@babel/core': 7.28.5 '@babel/parser': 7.28.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.7.3 + semver: 7.7.4 transitivePeerDependencies: - supports-color @@ -10748,11 +10855,11 @@ snapshots: make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@4.0.1: + istanbul-lib-source-maps@5.0.6: dependencies: + '@jridgewell/trace-mapping': 0.3.31 debug: 4.4.3 istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 transitivePeerDependencies: - supports-color @@ -10761,81 +10868,88 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + java-properties@1.0.2: {} - jest-changed-files@29.7.0: + jest-changed-files@30.3.0: dependencies: execa: 5.1.1 - jest-util: 29.7.0 + jest-util: 30.3.0 p-limit: 3.1.0 - jest-circus@29.7.0: + jest-circus@30.3.0: dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 '@types/node': 25.0.3 chalk: 4.1.2 co: 4.6.0 dedent: 1.7.1 is-generator-fn: 2.1.0 - jest-each: 29.7.0 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 + jest-each: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 p-limit: 3.1.0 - pretty-format: 29.7.0 - pure-rand: 6.1.0 + pretty-format: 30.3.0 + pure-rand: 7.0.1 slash: 3.0.0 stack-utils: 2.0.6 transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@25.0.3): + jest-cli@30.3.0(@types/node@25.0.3): dependencies: - '@jest/core': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 + '@jest/core': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@25.0.3) - exit: 0.1.2 + exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@25.0.3) - jest-util: 29.7.0 - jest-validate: 29.7.0 + jest-config: 30.3.0(@types/node@25.0.3) + jest-util: 30.3.0 + jest-validate: 30.3.0 yargs: 17.7.2 transitivePeerDependencies: - '@types/node' - babel-plugin-macros + - esbuild-register - supports-color - ts-node - jest-config@29.7.0(@types/node@25.0.3): + jest-config@30.3.0(@types/node@25.0.3): dependencies: '@babel/core': 7.28.5 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.28.5) + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.0.1 + '@jest/test-sequencer': 30.3.0 + '@jest/types': 30.3.0 + babel-jest: 30.3.0(@babel/core@7.28.5) chalk: 4.1.2 - ci-info: 3.9.0 + ci-info: 4.4.0 deepmerge: 4.3.1 - glob: 7.2.3 + glob: 10.5.0 graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 + jest-circus: 30.3.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-runner: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 parse-json: 5.2.0 - pretty-format: 29.7.0 + pretty-format: 30.3.0 slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: @@ -10844,13 +10958,6 @@ snapshots: - babel-plugin-macros - supports-color - jest-diff@29.7.0: - dependencies: - chalk: 4.1.2 - diff-sequences: 29.6.3 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - jest-diff@30.2.0: dependencies: '@jest/diff-sequences': 30.0.1 @@ -10858,71 +10965,69 @@ snapshots: chalk: 4.1.2 pretty-format: 30.2.0 - jest-docblock@29.7.0: + jest-diff@30.3.0: + dependencies: + '@jest/diff-sequences': 30.3.0 + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + pretty-format: 30.3.0 + + jest-docblock@30.2.0: dependencies: detect-newline: 3.1.0 - jest-each@29.7.0: + jest-each@30.3.0: dependencies: - '@jest/types': 29.6.3 + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 chalk: 4.1.2 - jest-get-type: 29.6.3 - jest-util: 29.7.0 - pretty-format: 29.7.0 + jest-util: 30.3.0 + pretty-format: 30.3.0 - jest-environment-node@29.7.0: + jest-environment-node@30.3.0: dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 '@types/node': 25.0.3 - jest-mock: 29.7.0 - jest-util: 29.7.0 - - jest-get-type@29.6.3: {} + jest-mock: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 - jest-haste-map@29.7.0: + jest-haste-map@30.2.0: dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.9 + '@jest/types': 30.2.0 '@types/node': 25.0.3 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 + jest-regex-util: 30.0.1 + jest-util: 30.2.0 + jest-worker: 30.2.0 micromatch: 4.0.8 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 - jest-haste-map@30.2.0: + jest-haste-map@30.3.0: dependencies: - '@jest/types': 30.2.0 + '@jest/types': 30.3.0 '@types/node': 25.0.3 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 jest-regex-util: 30.0.1 - jest-util: 30.2.0 - jest-worker: 30.2.0 - micromatch: 4.0.8 + jest-util: 30.3.0 + jest-worker: 30.3.0 + picomatch: 4.0.3 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 - jest-leak-detector@29.7.0: - dependencies: - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - - jest-matcher-utils@29.7.0: + jest-leak-detector@30.3.0: dependencies: - chalk: 4.1.2 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 + '@jest/get-type': 30.1.0 + pretty-format: 30.3.0 jest-matcher-utils@30.2.0: dependencies: @@ -10931,17 +11036,12 @@ snapshots: jest-diff: 30.2.0 pretty-format: 30.2.0 - jest-message-util@29.7.0: + jest-matcher-utils@30.3.0: dependencies: - '@babel/code-frame': 7.27.1 - '@jest/types': 29.6.3 - '@types/stack-utils': 2.0.3 + '@jest/get-type': 30.1.0 chalk: 4.1.2 - graceful-fs: 4.2.11 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - stack-utils: 2.0.6 + jest-diff: 30.3.0 + pretty-format: 30.3.0 jest-message-util@30.2.0: dependencies: @@ -10955,11 +11055,17 @@ snapshots: slash: 3.0.0 stack-utils: 2.0.6 - jest-mock@29.7.0: + jest-message-util@30.3.0: dependencies: - '@jest/types': 29.6.3 - '@types/node': 25.0.3 - jest-util: 29.7.0 + '@babel/code-frame': 7.27.1 + '@jest/types': 30.3.0 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + picomatch: 4.0.3 + pretty-format: 30.3.0 + slash: 3.0.0 + stack-utils: 2.0.6 jest-mock@30.2.0: dependencies: @@ -10967,111 +11073,90 @@ snapshots: '@types/node': 25.0.3 jest-util: 30.2.0 - jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - optionalDependencies: - jest-resolve: 29.7.0 + jest-mock@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 25.0.3 + jest-util: 30.3.0 - jest-regex-util@29.6.3: {} + jest-pnp-resolver@1.2.3(jest-resolve@30.3.0): + optionalDependencies: + jest-resolve: 30.3.0 jest-regex-util@30.0.1: {} - jest-resolve-dependencies@29.7.0: + jest-resolve-dependencies@30.3.0: dependencies: - jest-regex-util: 29.6.3 - jest-snapshot: 29.7.0 + jest-regex-util: 30.0.1 + jest-snapshot: 30.3.0 transitivePeerDependencies: - supports-color - jest-resolve@29.7.0: + jest-resolve@30.3.0: dependencies: chalk: 4.1.2 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - resolve: 1.22.11 - resolve.exports: 2.0.3 + jest-haste-map: 30.3.0 + jest-pnp-resolver: 1.2.3(jest-resolve@30.3.0) + jest-util: 30.3.0 + jest-validate: 30.3.0 slash: 3.0.0 + unrs-resolver: 1.11.1 - jest-runner@29.7.0: + jest-runner@30.3.0: dependencies: - '@jest/console': 29.7.0 - '@jest/environment': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.3.0 + '@jest/environment': 30.3.0 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 '@types/node': 25.0.3 chalk: 4.1.2 emittery: 0.13.1 + exit-x: 0.2.2 graceful-fs: 4.2.11 - jest-docblock: 29.7.0 - jest-environment-node: 29.7.0 - jest-haste-map: 29.7.0 - jest-leak-detector: 29.7.0 - jest-message-util: 29.7.0 - jest-resolve: 29.7.0 - jest-runtime: 29.7.0 - jest-util: 29.7.0 - jest-watcher: 29.7.0 - jest-worker: 29.7.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-haste-map: 30.3.0 + jest-leak-detector: 30.3.0 + jest-message-util: 30.3.0 + jest-resolve: 30.3.0 + jest-runtime: 30.3.0 + jest-util: 30.3.0 + jest-watcher: 30.3.0 + jest-worker: 30.3.0 p-limit: 3.1.0 source-map-support: 0.5.13 transitivePeerDependencies: - supports-color - jest-runtime@29.7.0: + jest-runtime@30.3.0: dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/globals': 29.7.0 - '@jest/source-map': 29.6.3 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/globals': 30.3.0 + '@jest/source-map': 30.0.1 + '@jest/test-result': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 '@types/node': 25.0.3 chalk: 4.1.2 - cjs-module-lexer: 1.4.3 + cjs-module-lexer: 2.2.0 collect-v8-coverage: 1.0.3 - glob: 7.2.3 + glob: 10.5.0 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 slash: 3.0.0 strip-bom: 4.0.0 transitivePeerDependencies: - supports-color - jest-snapshot@29.7.0: - dependencies: - '@babel/core': 7.28.5 - '@babel/generator': 7.28.5 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) - '@babel/types': 7.28.5 - '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.5) - chalk: 4.1.2 - expect: 29.7.0 - graceful-fs: 4.2.11 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - natural-compare: 1.4.0 - pretty-format: 29.7.0 - semver: 7.7.3 - transitivePeerDependencies: - - supports-color - jest-snapshot@30.2.0: dependencies: '@babel/core': 7.28.5 @@ -11098,14 +11183,31 @@ snapshots: transitivePeerDependencies: - supports-color - jest-util@29.7.0: + jest-snapshot@30.3.0: dependencies: - '@jest/types': 29.6.3 - '@types/node': 25.0.3 + '@babel/core': 7.28.5 + '@babel/generator': 7.28.5 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + '@babel/types': 7.28.5 + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + '@jest/snapshot-utils': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.5) chalk: 4.1.2 - ci-info: 3.9.0 + expect: 30.3.0 graceful-fs: 4.2.11 - picomatch: 2.3.1 + jest-diff: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + pretty-format: 30.3.0 + semver: 7.7.4 + synckit: 0.11.11 + transitivePeerDependencies: + - supports-color jest-util@30.2.0: dependencies: @@ -11116,50 +11218,61 @@ snapshots: graceful-fs: 4.2.11 picomatch: 4.0.3 - jest-validate@29.7.0: + jest-util@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 25.0.3 + chalk: 4.1.2 + ci-info: 4.4.0 + graceful-fs: 4.2.11 + picomatch: 4.0.3 + + jest-validate@30.3.0: dependencies: - '@jest/types': 29.6.3 + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 camelcase: 6.3.0 chalk: 4.1.2 - jest-get-type: 29.6.3 leven: 3.1.0 - pretty-format: 29.7.0 + pretty-format: 30.3.0 - jest-watcher@29.7.0: + jest-watcher@30.3.0: dependencies: - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 + '@jest/test-result': 30.3.0 + '@jest/types': 30.3.0 '@types/node': 25.0.3 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 - jest-util: 29.7.0 + jest-util: 30.3.0 string-length: 4.0.2 - jest-worker@29.7.0: + jest-worker@30.2.0: dependencies: '@types/node': 25.0.3 - jest-util: 29.7.0 + '@ungap/structured-clone': 1.3.0 + jest-util: 30.2.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest-worker@30.2.0: + jest-worker@30.3.0: dependencies: '@types/node': 25.0.3 '@ungap/structured-clone': 1.3.0 - jest-util: 30.2.0 + jest-util: 30.3.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@25.0.3): + jest@30.3.0(@types/node@25.0.3): dependencies: - '@jest/core': 29.7.0 - '@jest/types': 29.6.3 + '@jest/core': 30.3.0 + '@jest/types': 30.3.0 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@25.0.3) + jest-cli: 30.3.0(@types/node@25.0.3) transitivePeerDependencies: - '@types/node' - babel-plugin-macros + - esbuild-register - supports-color - ts-node @@ -11196,10 +11309,6 @@ snapshots: json-stringify-safe@5.0.1: {} - json5@1.0.2: - dependencies: - minimist: 1.2.8 - json5@2.2.3: {} jsonfile@6.2.0: @@ -11261,10 +11370,6 @@ snapshots: lodash.isstring@4.0.1: {} - lodash.memoize@4.1.2: {} - - lodash.merge@4.6.2: {} - lodash.uniqby@4.7.0: {} lodash@4.17.21: {} @@ -11302,9 +11407,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.3 - - make-error@1.3.6: {} + semver: 7.7.4 makeerror@1.0.12: dependencies: @@ -11821,18 +11924,22 @@ snapshots: mimic-function@5.0.1: {} - min-indent@1.0.1: {} + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.5 minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 - minimatch@9.0.5: + minimatch@9.0.9: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 2.0.3 minimist@1.2.8: {} + minipass@7.1.3: {} + mkdirp@3.0.1: {} mrmime@2.0.1: {} @@ -11847,6 +11954,8 @@ snapshots: nanoid@3.3.11: {} + napi-postinstall@0.3.4: {} + natural-compare@1.4.0: {} negotiator@1.0.0: {} @@ -11941,26 +12050,6 @@ snapshots: has-symbols: 1.1.0 object-keys: 1.1.1 - object.fromentries@2.0.8: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.1 - 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.1 - - 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 - ofetch@1.5.1: dependencies: destr: 2.0.5 @@ -12099,6 +12188,8 @@ snapshots: p-try@2.2.0: {} + package-json-from-dist@1.0.1: {} + package-manager-detector@1.6.0: {} pagefind@1.4.0: @@ -12181,6 +12272,11 @@ snapshots: path-parse@1.0.7: {} + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + path-to-regexp@8.3.0: {} path-type@3.0.0: @@ -12238,13 +12334,13 @@ snapshots: prelude-ls@1.2.1: {} - pretty-format@29.7.0: + pretty-format@30.2.0: dependencies: - '@jest/schemas': 29.6.3 + '@jest/schemas': 30.0.5 ansi-styles: 5.2.0 react-is: 18.3.1 - pretty-format@30.2.0: + pretty-format@30.3.0: dependencies: '@jest/schemas': 30.0.5 ansi-styles: 5.2.0 @@ -12274,7 +12370,7 @@ snapshots: punycode@2.3.1: {} - pure-rand@6.1.0: {} + pure-rand@7.0.1: {} qs@6.15.0: dependencies: @@ -12314,25 +12410,12 @@ snapshots: read-pkg: 9.0.1 type-fest: 4.41.0 - read-pkg-up@7.0.1: - dependencies: - find-up: 4.1.0 - read-pkg: 5.2.0 - type-fest: 0.8.1 - read-pkg@3.0.0: dependencies: load-json-file: 4.0.0 normalize-package-data: 2.5.0 path-type: 3.0.0 - 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 - read-pkg@9.0.1: dependencies: '@types/normalize-package-data': 2.4.4 @@ -12444,10 +12527,6 @@ snapshots: regjsgen@0.8.0: {} - regjsparser@0.10.0: - dependencies: - jsesc: 0.5.0 - regjsparser@0.13.0: dependencies: jsesc: 3.1.0 @@ -12559,8 +12638,6 @@ snapshots: require-from-string@2.0.2: {} - requireindex@1.2.0: {} - resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 @@ -12571,8 +12648,6 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve.exports@2.0.3: {} - resolve@1.22.11: dependencies: is-core-module: 2.16.1 @@ -12611,10 +12686,6 @@ snapshots: reusify@1.1.0: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - rollup@4.55.1: dependencies: '@types/estree': 1.0.8 @@ -12732,6 +12803,8 @@ snapshots: semver@7.7.3: {} + semver@7.7.4: {} + send@1.2.1: dependencies: debug: 4.4.3 @@ -12936,6 +13009,8 @@ snapshots: sprintf-js@1.0.3: {} + stable-hash-x@0.2.0: {} + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -12967,6 +13042,12 @@ snapshots: 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-width@7.2.0: dependencies: emoji-regex: 10.6.0 @@ -13030,9 +13111,7 @@ snapshots: strip-final-newline@4.0.0: {} - strip-indent@3.0.0: - dependencies: - min-indent: 1.0.1 + strip-indent@4.1.1: {} strip-json-comments@2.0.1: {} @@ -13109,8 +13188,6 @@ snapshots: text-extensions@2.4.0: {} - text-table@0.2.0: {} - thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -13153,65 +13230,24 @@ snapshots: trough@2.2.0: {} - ts-api-utils@1.4.3(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - - ts-jest@29.4.6(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@30.2.0)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.27.3)(jest-util@30.2.0)(jest@29.7.0(@types/node@25.0.3))(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - handlebars: 4.7.8 - jest: 29.7.0(@types/node@25.0.3) - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.7.3 - type-fest: 4.41.0 typescript: 5.9.3 - yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.28.5 - '@jest/transform': 29.7.0 - '@jest/types': 30.2.0 - babel-jest: 29.7.0(@babel/core@7.28.5) - esbuild: 0.27.3 - jest-util: 30.2.0 tsconfck@3.1.6(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 - 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@1.14.1: {} - tslib@2.8.1: {} - tsutils@3.21.0(typescript@5.9.3): - dependencies: - tslib: 1.14.1 - typescript: 5.9.3 - type-check@0.4.0: dependencies: prelude-ls: 1.2.1 type-detect@4.0.8: {} - type-fest@0.20.2: {} - type-fest@0.21.3: {} - type-fest@0.6.0: {} - - type-fest@0.8.1: {} - type-fest@1.4.0: {} type-fest@2.19.0: {} @@ -13257,6 +13293,17 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typescript-eslint@8.58.1(eslint@10.2.0)(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@5.9.3))(eslint@10.2.0)(typescript@5.9.3) + '@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@5.9.3) + eslint: 10.2.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + typescript@5.9.3: {} ufo@1.6.3: {} @@ -13366,6 +13413,30 @@ snapshots: unpipe@1.0.0: {} + 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 + unstorage@1.17.4: dependencies: anymatch: 3.1.3 @@ -13509,6 +13580,12 @@ snapshots: 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 + wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 @@ -13517,11 +13594,6 @@ snapshots: wrappy@1.0.2: {} - write-file-atomic@4.0.2: - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - write-file-atomic@5.0.1: dependencies: imurmurhash: 0.1.4 diff --git a/src/componentize/types/bytecodealliance-wizer.d.ts b/src/componentize/types/bytecodealliance-wizer.d.ts index 17aefb3..8ed1f35 100644 --- a/src/componentize/types/bytecodealliance-wizer.d.ts +++ b/src/componentize/types/bytecodealliance-wizer.d.ts @@ -1,5 +1,5 @@ -/* eslint-disable import/no-default-export */ -/* eslint-disable import/unambiguous */ +/* eslint-disable import-x/no-default-export */ +/* eslint-disable import-x/unambiguous */ declare module '@bytecodealliance/wizer' { const wizer: string; diff --git a/src/componentize/types/regexpu-core-regexpuc.d.ts b/src/componentize/types/regexpu-core-regexpuc.d.ts index b048dcc..9b6c6c3 100644 --- a/src/componentize/types/regexpu-core-regexpuc.d.ts +++ b/src/componentize/types/regexpu-core-regexpuc.d.ts @@ -1,5 +1,5 @@ -/* eslint-disable import/no-default-export */ -/* eslint-disable import/unambiguous */ +/* eslint-disable import-x/no-default-export */ +/* eslint-disable import-x/unambiguous */ declare module 'regexpu-core' { const regexpuc: (pattern: string, flags: string, options: Record) => string; export default regexpuc; diff --git a/src/server/static-assets/asset-loader/inline-asset/inline-asset.ts b/src/server/static-assets/asset-loader/inline-asset/inline-asset.ts index 062bb7e..0dfce6d 100644 --- a/src/server/static-assets/asset-loader/inline-asset/inline-asset.ts +++ b/src/server/static-assets/asset-loader/inline-asset/inline-asset.ts @@ -81,7 +81,6 @@ const createWasmInlineAsset = (metadata: StaticAssetMetadata): StaticAsset => { return createEmbeddedStoreEntry(source, contentEncoding, hash, size); }; - // eslint-disable-next-line capitalized-comments const getText = (): string => { if (!_metadata.isText) { throw new Error("Can't getText() for non-text content"); diff --git a/src/server/static-assets/asset-manifest/__tests__/create-manifest-file-map.test.ts b/src/server/static-assets/asset-manifest/__tests__/create-manifest-file-map.test.ts index 61fc31a..e6bdef7 100644 --- a/src/server/static-assets/asset-manifest/__tests__/create-manifest-file-map.test.ts +++ b/src/server/static-assets/asset-manifest/__tests__/create-manifest-file-map.test.ts @@ -15,7 +15,7 @@ jest.mock('~utils/color-log', () => ({ colorLog: (...args: any[]) => mockColorLog(...args), })); jest.mock('~utils/file-system', () => { - // eslint-disable-next-line unicorn/prefer-module, @typescript-eslint/no-var-requires + // eslint-disable-next-line unicorn/prefer-module, @typescript-eslint/no-require-imports const path = require('node:path'); return { getFilesRecursively: (...args: any[]) => mockGetFilesRecursively(...args), diff --git a/src/server/static-assets/asset-manifest/__tests__/create-manifest.test.ts b/src/server/static-assets/asset-manifest/__tests__/create-manifest.test.ts index 0f40df1..056b960 100644 --- a/src/server/static-assets/asset-manifest/__tests__/create-manifest.test.ts +++ b/src/server/static-assets/asset-manifest/__tests__/create-manifest.test.ts @@ -20,7 +20,7 @@ jest.mock('../create-manifest-file-map', () => ({ prettierObjectString: (...args: any[]) => mockPrettierObjectString(...args), })); jest.mock('~utils/file-system', () => { - // eslint-disable-next-line unicorn/prefer-module, @typescript-eslint/no-var-requires + // eslint-disable-next-line unicorn/prefer-module, @typescript-eslint/no-require-imports const path = require('node:path'); return { createOutputDirectory: (...args: any[]) => mockCreateOutputDirectory(...args), diff --git a/src/utils/__tests__/color-log.test.ts b/src/utils/__tests__/color-log.test.ts index 190f37c..23580ec 100644 --- a/src/utils/__tests__/color-log.test.ts +++ b/src/utils/__tests__/color-log.test.ts @@ -2,8 +2,8 @@ import { colorLog } from '../color-log.ts'; describe('color-log', () => { - let consoleInfoSpy: jest.SpyInstance; - let consoleErrorSpy: jest.SpyInstance; + let consoleInfoSpy: jest.Spied; + let consoleErrorSpy: jest.Spied; beforeEach(() => { consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(); diff --git a/src/utils/__tests__/config-helpers.test.ts b/src/utils/__tests__/config-helpers.test.ts index 6fe0c21..47d8b1b 100644 --- a/src/utils/__tests__/config-helpers.test.ts +++ b/src/utils/__tests__/config-helpers.test.ts @@ -12,7 +12,7 @@ const createNormalizationMapping = () => ({ describe('config-helpers', () => { // Mock console.warn to avoid output during tests - let consoleWarnSpy: jest.SpyInstance; + let consoleWarnSpy: jest.Spied; beforeEach(() => { consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(); diff --git a/src/utils/__tests__/content-types.test.ts b/src/utils/__tests__/content-types.test.ts index e944554..a2f4128 100644 --- a/src/utils/__tests__/content-types.test.ts +++ b/src/utils/__tests__/content-types.test.ts @@ -374,7 +374,7 @@ describe('content-types', () => { }); describe('getKnownContentTypes', () => { - let consoleSpy: jest.SpyInstance; + let consoleSpy: jest.Spied; beforeEach(() => { // Mock console methods to capture logging diff --git a/src/utils/__tests__/deep-copy.test.ts b/src/utils/__tests__/deep-copy.test.ts index 4fdae58..46e1838 100644 --- a/src/utils/__tests__/deep-copy.test.ts +++ b/src/utils/__tests__/deep-copy.test.ts @@ -646,7 +646,7 @@ describe('deep-copy', () => { const original = { 1: 'one', 2: 'two', - // eslint-disable-next-line quote-props + // eslint-disable-next-line @stylistic/quote-props '3': 'three', normal: 'normal', }; diff --git a/src/utils/__tests__/file-info.test.ts b/src/utils/__tests__/file-info.test.ts index f122b8b..3975ea2 100644 --- a/src/utils/__tests__/file-info.test.ts +++ b/src/utils/__tests__/file-info.test.ts @@ -1,5 +1,5 @@ /* eslint-disable unicorn/prefer-module */ -/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable @typescript-eslint/no-require-imports */ import crypto from 'node:crypto'; import { existsSync, mkdirSync, unlinkSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; diff --git a/src/utils/__tests__/file-system.test.ts b/src/utils/__tests__/file-system.test.ts index 01732de..cfd05a6 100644 --- a/src/utils/__tests__/file-system.test.ts +++ b/src/utils/__tests__/file-system.test.ts @@ -113,7 +113,6 @@ describe('file-system utilities', () => { { input: './current/dir', expected: 'current/dir' }, ]; - // eslint-disable-next-line unicorn/no-array-for-each testCases.forEach(({ input, expected }) => { const result = resolveOsPath(input); const expectedResult = path.normalize(path.resolve(expected)); @@ -614,7 +613,7 @@ describe('file-system utilities', () => { }); // Helper function for creating symlinks (not available in original implementation) function symlinkSync(target: string, path: string): void { - // eslint-disable-next-line @typescript-eslint/no-var-requires, unicorn/prefer-module + // eslint-disable-next-line @typescript-eslint/no-require-imports, unicorn/prefer-module const fs = require('node:fs'); fs.symlinkSync(target, path); } diff --git a/src/utils/syntax-checker.ts b/src/utils/syntax-checker.ts index 66de3f8..062f318 100644 --- a/src/utils/syntax-checker.ts +++ b/src/utils/syntax-checker.ts @@ -29,10 +29,10 @@ function containsJavascriptSyntaxErrors(jsInput: string): boolean { } /** - * Checks if TypeScript is installed. - * @returns `true` if TypeScript is installed, otherwise `false`. + * Gets the installed TypeScript major version. + * @returns The major version number, or `null` if TypeScript is not installed. */ -function isTypeScriptInstalled(): boolean { +function getTypeScriptMajorVersion(): number | null { const result: SpawnSyncReturns = spawnSync('npx', ['tsc', '--version'], { stdio: [null, null, null], shell: true, @@ -40,12 +40,13 @@ function isTypeScriptInstalled(): boolean { }); if (result.status === 0) { - return true; + const match = result.stdout.trim().match(/Version\s+(\d+)/u); + return match ? Number(match[1]) : null; } colorLog('error', 'TypeScript is not installed.'); colorLog('error', 'Please run "npm install typescript"'); - return false; + return null; } /** @@ -55,12 +56,17 @@ function isTypeScriptInstalled(): boolean { * @returns `true` if the file contains syntax errors, otherwise `false`. */ function containsTypeScriptSyntaxErrors(tsInput: string, tsConfigPath?: string): boolean { - if (isTypeScriptInstalled()) { + const tsMajor = getTypeScriptMajorVersion(); + if (tsMajor !== null) { const includeFastEdgeTypes = process.env.NODE_ENV === 'test' ? [] : ['--types', './node_modules/@gcoredev/fastedge-sdk-js']; + // moduleResolution 'node' (node10) is deprecated since TS 5.0; + // the ignoreDeprecations value must match the TS major version + const ignoreDeprecations = tsMajor >= 6 ? '6.0' : '5.0'; + const defaultTscBuildFlags = [ '--noEmit', '--skipLibCheck', @@ -70,6 +76,8 @@ function containsTypeScriptSyntaxErrors(tsInput: string, tsConfigPath?: string): 'esnext', '--moduleResolution', 'node', + '--ignoreDeprecations', + ignoreDeprecations, ...includeFastEdgeTypes, tsInput, ]; From 32842c6d30e9a3aa8c7e0d5878c4f6d982143484 Mon Sep 17 00:00:00 2001 From: Gordon Farquharson Date: Wed, 8 Apr 2026 13:25:56 +0100 Subject: [PATCH 2/8] copilot --- src/utils/syntax-checker.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/utils/syntax-checker.ts b/src/utils/syntax-checker.ts index 062f318..a4d25cf 100644 --- a/src/utils/syntax-checker.ts +++ b/src/utils/syntax-checker.ts @@ -64,8 +64,9 @@ function containsTypeScriptSyntaxErrors(tsInput: string, tsConfigPath?: string): : ['--types', './node_modules/@gcoredev/fastedge-sdk-js']; // moduleResolution 'node' (node10) is deprecated since TS 5.0; - // the ignoreDeprecations value must match the TS major version - const ignoreDeprecations = tsMajor >= 6 ? '6.0' : '5.0'; + // --ignoreDeprecations is only supported in TS >= 5 + const ignoreDeprecationsFlags = + tsMajor >= 5 ? ['--ignoreDeprecations', tsMajor >= 6 ? '6.0' : '5.0'] : []; const defaultTscBuildFlags = [ '--noEmit', @@ -76,13 +77,14 @@ function containsTypeScriptSyntaxErrors(tsInput: string, tsConfigPath?: string): 'esnext', '--moduleResolution', 'node', - '--ignoreDeprecations', - ignoreDeprecations, + ...ignoreDeprecationsFlags, ...includeFastEdgeTypes, tsInput, ]; - const tscBuildFlags = tsConfigPath ? ['--project', tsConfigPath] : defaultTscBuildFlags; + const tscBuildFlags = tsConfigPath + ? ['--project', tsConfigPath, ...ignoreDeprecationsFlags] + : defaultTscBuildFlags; const nodeProcess: SpawnSyncReturns = spawnSync('npx', ['tsc', ...tscBuildFlags], { stdio: [null, null, null], From 7fbd4e5ccd0c4ee30f64db0d9bf7e7c15e2b79a3 Mon Sep 17 00:00:00 2001 From: Gordon Farquharson Date: Wed, 8 Apr 2026 14:28:41 +0100 Subject: [PATCH 3/8] update workflows for pnpm --- .github/workflows/build-libs.yaml | 4 ++-- .github/workflows/code-validation.yaml | 2 +- .github/workflows/docs.yaml | 2 +- .github/workflows/unit-tests.yaml | 2 +- integration-tests/fastedge-build.test.js | 3 ++- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-libs.yaml b/.github/workflows/build-libs.yaml index 3aab8e4..66300b2 100644 --- a/.github/workflows/build-libs.yaml +++ b/.github/workflows/build-libs.yaml @@ -63,7 +63,7 @@ jobs: - name: Build Javascript libs if: steps.restore-build-cache.outputs.cache-hit != 'true' - run: npm run build:js + run: pnpm run build:js - name: Ensure bin files have execute permissions shell: bash @@ -71,7 +71,7 @@ jobs: chmod +x ./bin/*.js - name: Run Integration Tests - run: npm run test:integration + run: pnpm run test:integration - name: Save build cache id: save-build-cache diff --git a/.github/workflows/code-validation.yaml b/.github/workflows/code-validation.yaml index 6726b62..4cfdcf5 100644 --- a/.github/workflows/code-validation.yaml +++ b/.github/workflows/code-validation.yaml @@ -15,7 +15,7 @@ jobs: - name: ESlint run: | - npm run lint + pnpm run lint - name: File naming convention run: | diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index b733ef3..b0887b2 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -44,7 +44,7 @@ jobs: - name: Build with Astro run: | - npm run build -- \ + pnpm run build -- \ --site "${{ steps.pages.outputs.origin }}" \ --base "${{ steps.pages.outputs.base_path }}" working-directory: ${{ env.BUILD_PATH }} diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index e630007..5f9f5c7 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -22,4 +22,4 @@ jobs: - name: Unit Tests run: | - npm run test:unit + pnpm run test:unit diff --git a/integration-tests/fastedge-build.test.js b/integration-tests/fastedge-build.test.js index e7f9f98..7ab11fe 100644 --- a/integration-tests/fastedge-build.test.js +++ b/integration-tests/fastedge-build.test.js @@ -111,6 +111,7 @@ describe('fastedge-build', () => { expect(stdout[0]).toContain('Build success!!'); await cleanup(); }, + 30_000, ); it.each(['txt', 'wasm', 'pdf', 'xml', 'jpg'])( 'should exit with an error if the input is not a Javascript file ".%s"', @@ -170,7 +171,7 @@ describe('fastedge-build', () => { expect(stderr[0]).toContain('SyntaxError: Typescript code'); expect(stderr[1]).toContain('Error: "input.ts" contains Typescript errors'); expect(stdout[0]).toContain( - "input.ts(1,99): error TS2339: Property 'unknown' does not exist on type 'Test'.", + "error TS2339: Property 'unknown' does not exist on type 'Test'.", ); await cleanup(); }); From 44da21d893496f5fd4c572a86e243ef721df5a46 Mon Sep 17 00:00:00 2001 From: Gordon Farquharson Date: Wed, 8 Apr 2026 14:50:47 +0100 Subject: [PATCH 4/8] remove deprecated doctor workflows --- .github/workflows/collect.py | 959 ----------- .github/workflows/doctor-analyze.lock.yml | 1807 -------------------- .github/workflows/doctor-analyze.md | 503 ------ .github/workflows/doctor-analyze.prompt.md | 455 ----- .github/workflows/doctor.yml | 320 ---- 5 files changed, 4044 deletions(-) delete mode 100644 .github/workflows/collect.py delete mode 100644 .github/workflows/doctor-analyze.lock.yml delete mode 100644 .github/workflows/doctor-analyze.md delete mode 100644 .github/workflows/doctor-analyze.prompt.md delete mode 100644 .github/workflows/doctor.yml diff --git a/.github/workflows/collect.py b/.github/workflows/collect.py deleted file mode 100644 index ce1fb65..0000000 --- a/.github/workflows/collect.py +++ /dev/null @@ -1,959 +0,0 @@ -from __future__ import annotations - -import json -import os -import re -import subprocess -from datetime import datetime, timedelta, timezone -from pathlib import Path -from typing import Any - -SOURCE_BRANCH = "doctor-v1" -TOOLKIT_SOURCE_DIR = "toolkit" -RUNTIME_SOURCE_DIR = "workflows/runtime" -TOOLKIT_TARGET_ROOT = ".toolkit" -RUNTIME_TARGET_ROOT = ".github/workflows" -TOOLKIT_SOURCE_SHA_PATH = ".toolkit/SOURCE_SHA" -RUNTIME_SOURCE_SHA_PATH = ".toolkit/DOCTOR_RUNTIME_SHA" -TOOLKIT_REQUIRED_DIRECTORIES = { - "claude": ".toolkit/claude", - "scripts": ".toolkit/scripts", - "workflows": ".toolkit/workflows", - "examples": ".toolkit/examples", -} -RUNTIME_SOURCE_FILES = [ - # Closed-set allowlist: adding a new runtime file requires updating this list - # so doctor never silently ignores source bundle changes. - "doctor.yml", - "collect.py", - "doctor-analyze.md", - "doctor-analyze.prompt.md", - "doctor-analyze.lock.yml", -] -RUNTIME_BOOTSTRAP_FILES = [ - "doctor.yml", -] -RUNTIME_SYNC_FILES: list[str] = [] -STALE_RUNTIME_TARGET_FILES = sorted(set(RUNTIME_SOURCE_FILES) - set(RUNTIME_BOOTSTRAP_FILES)) -HYGIENE_EXCLUDED_FILE_NAMES = {".DS_Store"} -HYGIENE_EXCLUDED_DIR_NAMES = {"__pycache__"} -HYGIENE_EXCLUDED_SUFFIXES = {".pyc", ".pyo"} -_TRAILER_PATTERNS = { - "method": re.compile(r"^Method:\s*(.+)$", re.IGNORECASE), - "agent": re.compile(r"^Agent:\s*(.+)$", re.IGNORECASE), - "co_authored_by": re.compile(r"^Co-authored-by:\s*(.+)$", re.IGNORECASE), - "refs": re.compile(r"^Refs:\s*(.+)$", re.IGNORECASE), - "closes": re.compile(r"^Closes:\s*(.+)$", re.IGNORECASE), -} -PRESENCE_ONLY_PATHS = [ - "AGENTS.md", - "CLAUDE.md", - "DOCS.md", - ".specify/memory/constitution.md", - "docs/quickstart.md", -] - - -def _path_to_id(path: str) -> str: - return path.strip("./").replace("/", "_").replace(".", "_") - - -def _path_exists(repo_root: Path, relative_path: str) -> bool: - return (repo_root / relative_path).exists() - - -def _path_state(repo_root: Path, relative_path: str) -> str: - path = repo_root / relative_path - if path.exists(): - return "present" - if os.path.lexists(path): - return "broken_link" - return "missing" - - -def _path_present(repo_root: Path, relative_path: str) -> bool: - return _path_state(repo_root, relative_path) == "present" - - -def _is_hygiene_ignored(candidate: Path) -> bool: - return ( - candidate.name in HYGIENE_EXCLUDED_FILE_NAMES - or candidate.suffix in HYGIENE_EXCLUDED_SUFFIXES - or any(part in HYGIENE_EXCLUDED_DIR_NAMES for part in candidate.parts) - ) - - -def _is_managed_source_file(candidate: Path) -> bool: - return candidate.is_file() and not _is_hygiene_ignored(candidate) - - -def _new_finding( - finding_id: str, - *, - category: str, - severity: str, - path: str | None, - state: str, - auto_action: str, - message: str, - expected: str | None = None, - actual: str | None = None, -) -> dict[str, Any]: - return { - "id": finding_id, - "category": category, - "severity": severity, - "path": path, - "state": state, - "expected": expected, - "actual": actual, - "auto_action": auto_action, - "message": message, - } - - -def _read_text(path: Path) -> str: - return path.read_text(encoding="utf-8") - - -def load_required_runtime_files_from_source( - *, - source_root: Path, - selected_relative_paths: list[str] | tuple[str, ...] | None = None, -) -> dict[str, str]: - source_root = Path(source_root) - runtime_source_root = source_root / RUNTIME_SOURCE_DIR - if not runtime_source_root.exists(): - raise FileNotFoundError(f"Runtime source root is missing: {runtime_source_root}") - - actual_relative_paths = sorted( - candidate.relative_to(runtime_source_root).as_posix() - for candidate in runtime_source_root.rglob("*") - if _is_managed_source_file(candidate) - ) - actual_path_set = set(actual_relative_paths) - - missing_sources = [ - relative_path - for relative_path in RUNTIME_SOURCE_FILES - if relative_path not in actual_path_set - ] - if missing_sources: - missing_list = ", ".join(missing_sources) - raise FileNotFoundError(f"Required doctor runtime source files are missing: {missing_list}") - - unexpected_sources = [ - relative_path - for relative_path in actual_relative_paths - if relative_path not in RUNTIME_SOURCE_FILES - ] - if unexpected_sources: - unexpected_list = ", ".join(unexpected_sources) - raise RuntimeError( - "Unexpected doctor runtime source files found: " - f"{unexpected_list}. Update RUNTIME_SOURCE_FILES to manage them explicitly." - ) - - selected_relative_paths = list(RUNTIME_SYNC_FILES if selected_relative_paths is None else selected_relative_paths) - return { - f"{RUNTIME_TARGET_ROOT}/{relative_path}": _read_text(runtime_source_root / relative_path) - for relative_path in selected_relative_paths - } - - -def _read_sha_marker(repo_root: Path, relative_path: str) -> str | None: - marker_path = repo_root / relative_path - if not marker_path.exists(): - return None - - raw = marker_path.read_text(encoding="utf-8").strip() - return raw or None - - -def _resolve_source_sha(source_root: Path, explicit_source_sha: str | None) -> str: - if explicit_source_sha: - return explicit_source_sha.strip() - - result = subprocess.run( - ["git", "rev-parse", "HEAD"], - cwd=source_root, - text=True, - capture_output=True, - check=False, - ) - if result.returncode != 0: - raise RuntimeError(f"Unable to resolve source SHA from {source_root}") - - return result.stdout.strip() - - -def build_expected_manifest_stub() -> dict[str, Any]: - return { - "source_branch": SOURCE_BRANCH, - "source_sha": "", - "managed_root": TOOLKIT_TARGET_ROOT, - "managed_directories": list(TOOLKIT_REQUIRED_DIRECTORIES.values()), - "managed_files": {}, - "runtime_root": RUNTIME_TARGET_ROOT, - "runtime_files": {}, - "runtime_bootstrap_files": {}, - "presence_paths": list(PRESENCE_ONLY_PATHS), - } - - -def build_expected_manifest_from_source( - *, - source_root: Path, - source_sha: str | None = None, - source_branch: str = SOURCE_BRANCH, -) -> dict[str, Any]: - source_root = Path(source_root) - if not source_root.exists(): - raise FileNotFoundError(f"Source root is missing: {source_root}") - - resolved_source_sha = _resolve_source_sha(source_root, source_sha) - toolkit_source_root = source_root / TOOLKIT_SOURCE_DIR - runtime_source_root = source_root / RUNTIME_SOURCE_DIR - if not toolkit_source_root.exists(): - raise FileNotFoundError(f"Toolkit source root is missing: {toolkit_source_root}") - if not runtime_source_root.exists(): - raise FileNotFoundError(f"Runtime source root is missing: {runtime_source_root}") - - managed_files: dict[str, str] = {} - managed_directories = sorted( - f"{TOOLKIT_TARGET_ROOT}/{candidate.name}" - for candidate in toolkit_source_root.iterdir() - if candidate.is_dir() and candidate.name not in HYGIENE_EXCLUDED_FILE_NAMES - ) - - for source_file in sorted(candidate for candidate in toolkit_source_root.rglob("*") if _is_managed_source_file(candidate)): - relative_path = source_file.relative_to(toolkit_source_root).as_posix() - managed_files[f"{TOOLKIT_TARGET_ROOT}/{relative_path}"] = _read_text(source_file) - - managed_files[TOOLKIT_SOURCE_SHA_PATH] = f"{resolved_source_sha}\n" - managed_files[RUNTIME_SOURCE_SHA_PATH] = f"{resolved_source_sha}\n" - runtime_files = load_required_runtime_files_from_source( - source_root=source_root, - selected_relative_paths=RUNTIME_SYNC_FILES, - ) - runtime_bootstrap_files = load_required_runtime_files_from_source( - source_root=source_root, - selected_relative_paths=RUNTIME_BOOTSTRAP_FILES, - ) - - return { - "source_branch": source_branch, - "source_sha": resolved_source_sha, - "managed_root": TOOLKIT_TARGET_ROOT, - "managed_directories": managed_directories, - "managed_files": managed_files, - "runtime_root": RUNTIME_TARGET_ROOT, - "runtime_files": runtime_files, - "runtime_bootstrap_files": runtime_bootstrap_files, - "presence_paths": list(PRESENCE_ONLY_PATHS), - } - - -def build_compliance_checks(*, repo_root: Path) -> dict[str, dict[str, bool]]: - repo_root = Path(repo_root) - - return { - "required_paths": { - "agents_present": _path_present(repo_root, "AGENTS.md"), - "claude_present": _path_present(repo_root, "CLAUDE.md"), - "docs_md_present": _path_present(repo_root, "DOCS.md"), - "constitution_present": _path_present(repo_root, ".specify/memory/constitution.md"), - "quickstart_present": _path_present(repo_root, "docs/quickstart.md"), - }, - "toolkit": { - "root_present": (repo_root / TOOLKIT_TARGET_ROOT).is_dir(), - "source_sha_present": _path_exists(repo_root, TOOLKIT_SOURCE_SHA_PATH), - "runtime_sha_present": _path_exists(repo_root, RUNTIME_SOURCE_SHA_PATH), - "claude_present": (repo_root / TOOLKIT_REQUIRED_DIRECTORIES["claude"]).is_dir(), - "scripts_present": (repo_root / TOOLKIT_REQUIRED_DIRECTORIES["scripts"]).is_dir(), - "workflows_present": (repo_root / TOOLKIT_REQUIRED_DIRECTORIES["workflows"]).is_dir(), - "examples_present": (repo_root / TOOLKIT_REQUIRED_DIRECTORIES["examples"]).is_dir(), - }, - "doctor_runtime": { - "doctor_yml_present": _path_exists(repo_root, f"{RUNTIME_TARGET_ROOT}/doctor.yml"), - }, - } - - -def _iter_relative_entries(repo_root: Path, subtree_root: str) -> dict[str, str]: - root = repo_root / subtree_root - if not root.exists(): - return {} - - entries: dict[str, str] = {} - for candidate in root.rglob("*"): - if _is_hygiene_ignored(candidate): - continue - if candidate.is_file(): - entries[candidate.relative_to(repo_root).as_posix()] = "present" - continue - if candidate.is_symlink() and not candidate.exists(): - entries[candidate.relative_to(repo_root).as_posix()] = "broken_link" - return entries - - -def _compare_expected_files( - *, - repo_root: Path, - expected_files: dict[str, str], - category: str, - change_message_prefix: str, - auto_action: str = "act", - missing_severity: str = "error", - changed_severity: str = "warning", - broken_link_severity: str = "error", -) -> list[dict[str, Any]]: - findings: list[dict[str, Any]] = [] - - for relative_path, expected_content in expected_files.items(): - file_state = _path_state(repo_root, relative_path) - if file_state == "missing": - findings.append( - _new_finding( - f"{category}.{_path_to_id(relative_path)}.missing", - category=category, - severity=missing_severity, - path=relative_path, - state="missing", - auto_action=auto_action, - message=f"{change_message_prefix} is missing: {relative_path}", - expected=expected_content, - ) - ) - continue - if file_state == "broken_link": - findings.append( - _new_finding( - f"{category}.{_path_to_id(relative_path)}.broken_link", - category=category, - severity=broken_link_severity, - path=relative_path, - state="broken_link", - auto_action=auto_action, - message=f"{change_message_prefix} is a broken symlink: {relative_path}", - expected=expected_content, - ) - ) - continue - - file_path = repo_root / relative_path - actual_content = file_path.read_text(encoding="utf-8").rstrip("\n") - if actual_content != str(expected_content).rstrip("\n"): - findings.append( - _new_finding( - f"{category}.{_path_to_id(relative_path)}.changed", - category=category, - severity=changed_severity, - path=relative_path, - state="changed", - auto_action=auto_action, - message=f"{change_message_prefix} content differs: {relative_path}", - expected=str(expected_content), - actual=actual_content, - ) - ) - - return findings - - -def scan_repository_files(*, repo_root: Path, expected_manifest: dict[str, Any]) -> dict[str, Any]: - repo_root = Path(repo_root) - managed_files: dict[str, str] = dict(expected_manifest.get("managed_files", {})) - runtime_files: dict[str, str] = dict(expected_manifest.get("runtime_files", {})) - runtime_bootstrap_files: dict[str, str] = dict(expected_manifest.get("runtime_bootstrap_files", {})) - managed_root = str(expected_manifest.get("managed_root") or TOOLKIT_TARGET_ROOT) - presence_paths: list[str] = list(expected_manifest.get("presence_paths", PRESENCE_ONLY_PATHS)) - checks = build_compliance_checks(repo_root=repo_root) - - findings = [ - *_compare_expected_files( - repo_root=repo_root, - expected_files=managed_files, - category="managed", - change_message_prefix="Managed path", - ), - *_compare_expected_files( - repo_root=repo_root, - expected_files=runtime_files, - category="runtime", - change_message_prefix="Doctor runtime path", - ), - *_compare_expected_files( - repo_root=repo_root, - expected_files=runtime_bootstrap_files, - category="observed", - change_message_prefix="Doctor bootstrap", - auto_action="none", - missing_severity="warning", - changed_severity="warning", - broken_link_severity="warning", - ), - ] - - managed_expected_paths = set(managed_files) - managed_actual_entries = _iter_relative_entries(repo_root, managed_root) - for actual_path in sorted(set(managed_actual_entries) - managed_expected_paths): - actual_state = managed_actual_entries[actual_path] - if actual_state == "broken_link": - findings.append( - _new_finding( - f"managed.{_path_to_id(actual_path)}.broken_link", - category="managed", - severity="error", - path=actual_path, - state="broken_link", - auto_action="act", - message=f"Unexpected extra managed path is a broken symlink: {actual_path}", - ) - ) - continue - findings.append( - _new_finding( - f"managed.{_path_to_id(actual_path)}.unexpected_extra", - category="managed", - severity="warning", - path=actual_path, - state="unexpected_extra", - auto_action="act", - message=f"Unexpected extra managed path present: {actual_path}", - ) - ) - - for presence_path in presence_paths: - presence_state = _path_state(repo_root, presence_path) - if presence_state == "present": - continue - if presence_state == "broken_link": - findings.append( - _new_finding( - f"observed.{_path_to_id(presence_path)}.broken_link", - category="observed", - severity="warning", - path=presence_path, - state="broken_link", - auto_action="analyze", - message=f"Required path is a broken symlink: {presence_path}", - ) - ) - continue - findings.append( - _new_finding( - f"observed.{_path_to_id(presence_path)}.missing", - category="observed", - severity="warning", - path=presence_path, - state="missing", - auto_action="analyze", - message=f"Required path is missing: {presence_path}", - ) - ) - - for relative_name in STALE_RUNTIME_TARGET_FILES: - stale_path = f"{RUNTIME_TARGET_ROOT}/{relative_name}" - stale_state = _path_state(repo_root, stale_path) - if stale_state == "missing": - continue - if stale_state == "broken_link": - findings.append( - _new_finding( - f"observed.{_path_to_id(stale_path)}.broken_link", - category="observed", - severity="warning", - path=stale_path, - state="broken_link", - auto_action="none", - message=f"Stale doctor runtime path must be removed manually: {stale_path}", - ) - ) - continue - findings.append( - _new_finding( - f"observed.{_path_to_id(stale_path)}.stale", - category="observed", - severity="warning", - path=stale_path, - state="stale", - auto_action="none", - message=f"Stale doctor runtime path must be removed manually: {stale_path}", - ) - ) - - return { - "checks": checks, - "findings": findings, - "managed_drift_present": any(item["category"] == "managed" for item in findings), - "runtime_drift_present": any(item["category"] == "runtime" for item in findings), - "observed_findings_present": any(item["category"] == "observed" for item in findings), - } - - -def select_act_reason(flags: dict[str, bool]) -> str: - priority = [ - "toolkit_missing", - "source_sha_missing", - "runtime_sha_missing", - "managed_drift", - ] - - for reason in priority: - if flags.get(reason, False): - return reason - if flags.get("operational_error", False): - return "operational_error" - return "healthy" - - -def enrich_commit_record_with_trailers(commit_payload: dict[str, Any]) -> dict[str, Any]: - message = str(commit_payload.get("message", "")) - parse_message = message.replace("\\n", "\n") - - method: str | None = None - agent: str | None = None - co_authored_by: list[str] = [] - refs: list[str] = [] - closes: list[str] = [] - - for line in parse_message.splitlines(): - line = line.strip() - if not line: - continue - - method_match = _TRAILER_PATTERNS["method"].match(line) - if method_match: - method = method_match.group(1).strip() - continue - - agent_match = _TRAILER_PATTERNS["agent"].match(line) - if agent_match: - agent = agent_match.group(1).strip() - continue - - co_author_match = _TRAILER_PATTERNS["co_authored_by"].match(line) - if co_author_match: - co_authored_by.append(co_author_match.group(1).strip()) - continue - - refs_match = _TRAILER_PATTERNS["refs"].match(line) - if refs_match: - refs.append(refs_match.group(1).strip()) - continue - - closes_match = _TRAILER_PATTERNS["closes"].match(line) - if closes_match: - closes.append(closes_match.group(1).strip()) - - return { - "sha": commit_payload.get("sha"), - "author": commit_payload.get("author"), - "authored_at": commit_payload.get("authored_at"), - "message": message, - "method": method, - "agent": agent, - "co_authored_by": co_authored_by, - "refs": refs, - "closes": closes, - } - - -def build_activity_sections( - *, - daily_commits: list[dict[str, Any]], - daily_prs: list[dict[str, Any]], - daily_issues: list[dict[str, Any]], - snapshot_prs: list[dict[str, Any]], - snapshot_issues: list[dict[str, Any]], -) -> dict[str, Any]: - return { - "activity": { - "commits": list(daily_commits), - "prs": list(daily_prs), - "issues": list(daily_issues), - }, - "snapshot": { - "prs": list(snapshot_prs), - "issues": list(snapshot_issues), - }, - } - - -def _build_environment_findings(*, issues_enabled: bool) -> list[dict[str, Any]]: - if issues_enabled: - return [] - - return [ - _new_finding( - "operational.issues_disabled", - category="operational", - severity="warning", - path=None, - state="issues_disabled", - auto_action="none", - message="Issues are disabled in the target repository", - ) - ] - - -def _stringify_bool(value: bool) -> str: - return "true" if value else "false" - - -def _parse_bool(value: str | bool | None, *, default: bool = False) -> bool: - if isinstance(value, bool): - return value - if value is None: - return default - return value.strip().lower() in {"1", "true", "yes", "on"} - - -def _rfc3339_now() -> str: - return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z") - - -def _default_window(report_date: str) -> tuple[str, str]: - report_start = datetime.strptime(report_date, "%Y-%m-%d").replace(tzinfo=timezone.utc) - window_from = report_start - timedelta(days=1) - return ( - window_from.isoformat().replace("+00:00", "Z"), - report_start.isoformat().replace("+00:00", "Z"), - ) - - -def _load_json_source( - *, - env_var: str, - path_env_var: str, - default: Any, -) -> Any: - path_value = os.getenv(path_env_var) - if path_value: - return json.loads(Path(path_value).read_text(encoding="utf-8")) - - raw_value = os.getenv(env_var) - if raw_value: - return json.loads(raw_value) - - return default - - -def resolve_source_state(*, repo_root: Path, expected_manifest: dict[str, Any]) -> dict[str, Any]: - repo_root = Path(repo_root) - source_branch = str(expected_manifest.get("source_branch") or SOURCE_BRANCH) - source_sha = str(expected_manifest.get("source_sha") or "").strip() - findings: list[dict[str, Any]] = [] - - if not source_sha: - findings.append( - _new_finding( - "operational.source_manifest_unavailable", - category="operational", - severity="error", - path=None, - state="source_manifest_unavailable", - auto_action="none", - message="Collect did not receive a valid source manifest from the configured source ref", - ) - ) - - return { - "source_branch": source_branch, - "source_sha": source_sha, - "installed_source_sha": _read_sha_marker(repo_root, TOOLKIT_SOURCE_SHA_PATH), - "installed_runtime_sha": _read_sha_marker(repo_root, RUNTIME_SOURCE_SHA_PATH), - "fatal_error": not bool(source_sha), - "findings": findings, - } - - -def build_job_outputs( - *, - report_date: str, - source_sha: str | None, - installed_source_sha: str | None, - installed_runtime_sha: str | None, - should_act: bool, - act_reason: str, - issues_enabled: bool, - observed_findings_present: bool, - analyze_day: str | None = None, - report_tz: str | None = None, -) -> dict[str, str]: - outputs = { - "should_act": _stringify_bool(should_act), - "source_sha": source_sha or "", - "installed_source_sha": installed_source_sha or "", - "installed_runtime_sha": installed_runtime_sha or "", - "act_reason": act_reason, - "issues_enabled": _stringify_bool(issues_enabled), - "observed_findings_present": _stringify_bool(observed_findings_present), - "stats_artifact_name": f"doctor-stats-{report_date}", - "findings_artifact_name": f"doctor-findings-{report_date}", - } - - if analyze_day is not None: - outputs["analyze_day"] = analyze_day - if report_tz is not None: - outputs["report_tz"] = report_tz - - return outputs - - -def assemble_collect_result( - *, - repo_root: Path, - expected_manifest: dict[str, Any], - issues_enabled: bool, - repo_full_name: str, - repo_default_branch: str, - workflow_name: str, - workflow_run_id: int, - workflow_run_attempt: int, - workflow_event_name: str, - workflow_actor: str, - source_repo_full_name: str, - analyze_day: str | None, - report_tz: str | None, - collected_at: str, - report_date: str, - window_from: str, - window_to: str, - daily_commits: list[dict[str, Any]] | None = None, - daily_prs: list[dict[str, Any]] | None = None, - daily_issues: list[dict[str, Any]] | None = None, - snapshot_prs: list[dict[str, Any]] | None = None, - snapshot_issues: list[dict[str, Any]] | None = None, -) -> dict[str, Any]: - repo_root = Path(repo_root) - source_state = resolve_source_state(repo_root=repo_root, expected_manifest=expected_manifest) - scan_result = scan_repository_files(repo_root=repo_root, expected_manifest=expected_manifest) - environment_findings = _build_environment_findings(issues_enabled=issues_enabled) - - flags = { - "toolkit_missing": not (repo_root / TOOLKIT_TARGET_ROOT).is_dir(), - "source_sha_missing": not _path_exists(repo_root, TOOLKIT_SOURCE_SHA_PATH), - "runtime_sha_missing": not _path_exists(repo_root, RUNTIME_SOURCE_SHA_PATH), - "managed_drift": scan_result["managed_drift_present"], - "operational_error": source_state["fatal_error"], - } - - should_act = any( - flags[name] - for name in ( - "toolkit_missing", - "source_sha_missing", - "runtime_sha_missing", - "managed_drift", - ) - ) - if flags["operational_error"]: - should_act = False - - if should_act: - act_reason = select_act_reason(flags) - elif flags["operational_error"]: - act_reason = "operational_error" - else: - act_reason = "healthy" - - findings = [ - *source_state["findings"], - *scan_result["findings"], - *environment_findings, - ] - - normalized_commits = [ - enrich_commit_record_with_trailers(commit) - if any(field not in commit for field in ("method", "agent", "co_authored_by", "refs", "closes")) - else dict(commit) - for commit in (daily_commits or []) - ] - activity_sections = build_activity_sections( - daily_commits=normalized_commits, - daily_prs=list(daily_prs or []), - daily_issues=list(daily_issues or []), - snapshot_prs=list(snapshot_prs or []), - snapshot_issues=list(snapshot_issues or []), - ) - - job_outputs = build_job_outputs( - report_date=report_date, - source_sha=source_state["source_sha"], - installed_source_sha=source_state["installed_source_sha"], - installed_runtime_sha=source_state["installed_runtime_sha"], - should_act=should_act, - act_reason=act_reason, - issues_enabled=issues_enabled, - observed_findings_present=scan_result["observed_findings_present"], - analyze_day=analyze_day, - report_tz=report_tz, - ) - - contract_payload = { - "managed_root": str(expected_manifest.get("managed_root") or TOOLKIT_TARGET_ROOT), - "managed_directories": list( - expected_manifest.get("managed_directories", TOOLKIT_REQUIRED_DIRECTORIES.values()) - ), - "runtime_root": str(expected_manifest.get("runtime_root") or RUNTIME_TARGET_ROOT), - "runtime_files": sorted(expected_manifest.get("runtime_files", {}).keys()), - "presence_paths": list(expected_manifest.get("presence_paths", PRESENCE_ONLY_PATHS)), - } - - stats_payload: dict[str, Any] | None = None - if not source_state["fatal_error"]: - stats_payload = { - "schema_version": "doctor-stats/v3", - "collected_at": collected_at, - "report_date": report_date, - "window": { - "from": window_from, - "to": window_to, - }, - "repo": { - "full_name": repo_full_name, - "default_branch": repo_default_branch, - }, - "workflow": { - "name": workflow_name, - "run_id": workflow_run_id, - "run_attempt": workflow_run_attempt, - "event_name": workflow_event_name, - "actor": workflow_actor, - }, - "source_repo": { - "full_name": source_repo_full_name, - "source_branch": source_state["source_branch"], - "source_sha": source_state["source_sha"], - }, - "toolkit": { - "installed_source_sha": source_state["installed_source_sha"], - }, - "doctor_runtime": { - "installed_source_sha": source_state["installed_runtime_sha"], - }, - "contract": contract_payload, - **activity_sections, - } - - findings_payload = { - "schema_version": "doctor-findings/v4", - "collected_at": collected_at, - "report_date": report_date, - "repo": { - "full_name": repo_full_name, - "default_branch": repo_default_branch, - }, - "source_repo": { - "full_name": source_repo_full_name, - "source_branch": source_state["source_branch"], - "source_sha": source_state["source_sha"], - }, - "toolkit": { - "installed_source_sha": source_state["installed_source_sha"], - }, - "doctor_runtime": { - "installed_source_sha": source_state["installed_runtime_sha"], - }, - "decision": { - "should_act": should_act, - "act_reason": act_reason, - "managed_drift_present": scan_result["managed_drift_present"], - "runtime_drift_present": scan_result["runtime_drift_present"], - "observed_findings_present": scan_result["observed_findings_present"], - }, - "contract": contract_payload, - "checks": scan_result["checks"], - "findings": findings, - } - - return { - "fatal_error": source_state["fatal_error"], - "job_outputs": job_outputs, - "stats_payload": stats_payload, - "findings_payload": findings_payload, - } - - -def _write_json_file(path: Path, payload: dict[str, Any]) -> None: - path.write_text(f"{json.dumps(payload, indent=2)}\n", encoding="utf-8") - - -def _write_github_output(outputs: dict[str, str]) -> None: - github_output = os.getenv("GITHUB_OUTPUT") - if not github_output: - return - - with Path(github_output).open("a", encoding="utf-8") as handle: - for key, value in outputs.items(): - handle.write(f"{key}={value}\n") - - -def main() -> int: - repo_root = Path(os.getenv("DOCTOR_REPO_ROOT", ".")).resolve() - output_dir = Path(os.getenv("DOCTOR_OUTPUT_DIR", ".")).resolve() - output_dir.mkdir(parents=True, exist_ok=True) - - collected_at = os.getenv("DOCTOR_COLLECTED_AT", _rfc3339_now()) - report_date = os.getenv("DOCTOR_REPORT_DATE", collected_at[:10]) - default_window_from, default_window_to = _default_window(report_date) - - source_root = os.getenv("DOCTOR_SOURCE_ROOT") - if source_root: - expected_manifest = build_expected_manifest_from_source( - source_root=Path(source_root).resolve(), - source_sha=os.getenv("DOCTOR_SOURCE_SHA") or None, - source_branch=os.getenv("DOCTOR_SOURCE_BRANCH", SOURCE_BRANCH), - ) - else: - expected_manifest = _load_json_source( - env_var="DOCTOR_EXPECTED_MANIFEST", - path_env_var="DOCTOR_EXPECTED_MANIFEST_PATH", - default={}, - ) - - activity_payload = _load_json_source( - env_var="DOCTOR_ACTIVITY", - path_env_var="DOCTOR_ACTIVITY_PATH", - default={}, - ) - - result = assemble_collect_result( - repo_root=repo_root, - expected_manifest=expected_manifest, - issues_enabled=_parse_bool(os.getenv("DOCTOR_ISSUES_ENABLED"), default=True), - repo_full_name=os.getenv("DOCTOR_REPO_FULL_NAME", os.getenv("GITHUB_REPOSITORY", "")), - repo_default_branch=os.getenv("DOCTOR_REPO_DEFAULT_BRANCH", "main"), - workflow_name=os.getenv("GITHUB_WORKFLOW", "doctor"), - workflow_run_id=int(os.getenv("GITHUB_RUN_ID", "0")), - workflow_run_attempt=int(os.getenv("GITHUB_RUN_ATTEMPT", "0")), - workflow_event_name=os.getenv("GITHUB_EVENT_NAME", "workflow_dispatch"), - workflow_actor=os.getenv("GITHUB_ACTOR", ""), - source_repo_full_name=os.getenv("DOCTOR_SOURCE_REPO", "G-Core/agent-toolkit"), - analyze_day=os.getenv("DOCTOR_ANALYZE_DAY"), - report_tz=os.getenv("DOCTOR_REPORT_TZ"), - collected_at=collected_at, - report_date=report_date, - window_from=os.getenv("DOCTOR_WINDOW_FROM", default_window_from), - window_to=os.getenv("DOCTOR_WINDOW_TO", default_window_to), - daily_commits=activity_payload.get("commits", []), - daily_prs=activity_payload.get("prs", []), - daily_issues=activity_payload.get("issues", []), - snapshot_prs=activity_payload.get("snapshot_prs", []), - snapshot_issues=activity_payload.get("snapshot_issues", []), - ) - - findings_path = output_dir / "doctor-findings.json" - _write_json_file(findings_path, result["findings_payload"]) - - if result["stats_payload"] is not None: - _write_json_file(output_dir / "doctor-stats.json", result["stats_payload"]) - - _write_github_output(result["job_outputs"]) - return 1 if result["fatal_error"] else 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.github/workflows/doctor-analyze.lock.yml b/.github/workflows/doctor-analyze.lock.yml deleted file mode 100644 index 2ce1161..0000000 --- a/.github/workflows/doctor-analyze.lock.yml +++ /dev/null @@ -1,1807 +0,0 @@ -# -# ___ _ _ -# / _ \ | | (_) -# | |_| | __ _ ___ _ __ | |_ _ ___ -# | _ |/ _` |/ _ \ '_ \| __| |/ __| -# | | | | (_| | __/ | | | |_| | (__ -# \_| |_/\__, |\___|_| |_|\__|_|\___| -# __/ | -# _ _ |___/ -# | | | | / _| | -# | | | | ___ _ __ _ __| |_| | _____ ____ -# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| -# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ -# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ -# -# This file was automatically generated by gh-aw (v0.44.0). DO NOT EDIT. -# -# To update this file, run: -# python3 workflows/build_doctor_analyze_lock.py -# This tracked lock is generated by gh aw compile and then post-processed. -# Do not edit this file manually. -# -# For more information: https://github.github.com/gh-aw/introduction/overview/ -# -# -# frontmatter-hash: 26ed66316fc76b55ddfd8e9b55e3ebebba4ee98bbbea3e8d33c3f45a23ed4a52 - -name: "doctor-analyze" -"on": - workflow_call: - inputs: - analyze_day: - required: true - type: string - findings_artifact_name: - required: true - type: string - force_analyze: - required: false - type: boolean - installed_runtime_sha: - required: false - type: string - installed_source_sha: - required: false - type: string - issues_enabled: - required: true - type: string - observed_findings_present: - required: true - type: string - report_tz: - required: true - type: string - source_sha: - required: false - type: string - stats_artifact_name: - required: true - type: string - -permissions: {} - -concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}" - -run-name: "doctor-analyze" - -jobs: - activation: - needs: pre_activation - if: needs.pre_activation.outputs.activated == 'true' - runs-on: ubuntu-slim - permissions: - contents: read - outputs: - comment_id: "" - comment_repo: "" - steps: - - name: Setup Scripts - uses: github/gh-aw/actions/setup@cec1ecf3b97e9a1bbffaedf490a49ce03c1071ba # v0.44.0 - with: - destination: /opt/gh-aw/actions - agent: - needs: activation - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - issues: read - pull-requests: read - env: - DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - GH_AW_ASSETS_ALLOWED_EXTS: "" - GH_AW_ASSETS_BRANCH: "" - GH_AW_ASSETS_MAX_SIZE_KB: 0 - GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs - GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl - GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json - GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json - GH_AW_WORKFLOW_ID_SANITIZED: doctoranalyze - outputs: - checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} - has_patch: ${{ steps.collect_output.outputs.has_patch }} - model: ${{ steps.generate_aw_info.outputs.model }} - output: ${{ steps.collect_output.outputs.output }} - output_types: ${{ steps.collect_output.outputs.output_types }} - secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} - steps: - - name: Setup Scripts - uses: github/gh-aw/actions/setup@cec1ecf3b97e9a1bbffaedf490a49ce03c1071ba # v0.44.0 - with: - destination: /opt/gh-aw/actions - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - name: Create gh-aw temp directory - run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh - - name: Download doctor-stats artifact - continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - with: - name: ${{ inputs.stats_artifact_name }} - path: /tmp/gh-aw/collect-artifacts/stats - - name: Download doctor-findings artifact - continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - with: - name: ${{ inputs.findings_artifact_name }} - path: /tmp/gh-aw/collect-artifacts/findings - - name: Configure Git credentials - env: - REPO_NAME: ${{ github.repository }} - SERVER_URL: ${{ github.server_url }} - run: | - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git config --global user.name "github-actions[bot]" - # Re-authenticate git with GitHub token - SERVER_URL_STRIPPED="${SERVER_URL#https://}" - git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" - echo "Git configured with standard GitHub Actions identity" - - name: Checkout PR branch - id: checkout-pr - if: | - github.event.pull_request - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - with: - github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs'); - await main(); - - name: Generate agentic run info - id: generate_aw_info - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const fs = require('fs'); - - const awInfo = { - engine_id: "claude", - engine_name: "Claude Code", - model: process.env.GH_AW_MODEL_AGENT_CLAUDE || "", - version: "", - agent_version: "2.1.42", - cli_version: "v0.44.0", - workflow_name: "doctor-analyze", - experimental: false, - supports_tools_allowlist: true, - supports_http_transport: true, - run_id: context.runId, - run_number: context.runNumber, - run_attempt: process.env.GITHUB_RUN_ATTEMPT, - repository: context.repo.owner + '/' + context.repo.repo, - ref: context.ref, - sha: context.sha, - actor: context.actor, - event_name: context.eventName, - staged: false, - allowed_domains: ["defaults"], - firewall_enabled: true, - awf_version: "v0.18.0", - awmg_version: "v0.1.4", - steps: { - firewall: "squid" - }, - created_at: new Date().toISOString() - }; - - // Write to /tmp/gh-aw directory to avoid inclusion in PR - const tmpPath = '/tmp/gh-aw/aw_info.json'; - fs.writeFileSync(tmpPath, JSON.stringify(awInfo, null, 2)); - console.log('Generated aw_info.json at:', tmpPath); - console.log(JSON.stringify(awInfo, null, 2)); - - // Set model as output for reuse in other steps/jobs - core.setOutput('model', awInfo.model); - - name: Validate CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY secret - id: validate-secret - run: /opt/gh-aw/actions/validate_multi_secret.sh CLAUDE_CODE_OAUTH_TOKEN ANTHROPIC_API_KEY 'Claude Code' https://github.github.com/gh-aw/reference/engines/#anthropic-claude-code - env: - CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '24' - package-manager-cache: false - - name: Install awf binary - run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.18.0 - - name: Install Claude Code CLI - run: npm install -g --silent @anthropic-ai/claude-code@2.1.42 - - name: Determine automatic lockdown mode for GitHub MCP server - id: determine-automatic-lockdown - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} - GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - with: - script: | - const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs'); - await determineAutomaticLockdown(github, context, core); - - name: Download container images - run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.18.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.18.0 ghcr.io/github/gh-aw-firewall/squid:0.18.0 ghcr.io/github/gh-aw-mcpg:v0.1.4 ghcr.io/github/github-mcp-server:v0.30.3 node:lts-alpine - - name: Write Safe Outputs Config - run: | - mkdir -p /opt/gh-aw/safeoutputs - mkdir -p /tmp/gh-aw/safeoutputs - mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF' - {"add_comment":{"max":1},"close_issue":{"max":1},"create_issue":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1},"update_issue":{"max":1}} - GH_AW_SAFE_OUTPUTS_CONFIG_EOF - cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF' - [ - { - "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.", - "type": "string" - }, - "labels": { - "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.", - "items": { - "type": "string" - }, - "type": "array" - }, - "parent": { - "description": "Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from a previously created issue in the same workflow run.", - "type": [ - "number", - "string" - ] - }, - "temporary_id": { - "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 3 to 8 alphanumeric characters (e.g., 'aw_abc1', 'aw_Test123'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.", - "pattern": "^aw_[A-Za-z0-9]{4,8}$", - "type": "string" - }, - "title": { - "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.", - "type": "string" - } - }, - "required": [ - "title", - "body" - ], - "type": "object" - }, - "name": "create_issue" - }, - { - "description": "Close a GitHub issue with a closing comment. You can and should always add a comment when closing an issue to explain the action or provide context. This tool is ONLY for closing issues - use update_issue if you need to change the title, body, labels, or other metadata without closing. Use close_issue when work is complete, the issue is no longer relevant, or it's a duplicate. The closing comment should explain the resolution or reason for closing. If the issue is already closed, a comment will still be posted. CONSTRAINTS: Maximum 1 issue(s) can be closed.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "Closing comment explaining why the issue is being closed and summarizing any resolution, workaround, or conclusion.", - "type": "string" - }, - "issue_number": { - "description": "Issue number to close. This is the numeric ID from the GitHub URL (e.g., 901 in github.com/owner/repo/issues/901). If omitted, closes the issue that triggered this workflow (requires an issue event trigger).", - "type": [ - "number", - "string" - ] - } - }, - "required": [ - "body" - ], - "type": "object" - }, - "name": "close_issue" - }, - { - "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. CONSTRAINTS: Maximum 1 comment(s) can be added.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation.", - "type": "string" - }, - "item_number": { - "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool will attempt to resolve the target from the current workflow context (triggering issue, PR, or discussion).", - "type": "number" - } - }, - "required": [ - "body" - ], - "type": "object" - }, - "name": "add_comment" - }, - { - "description": "Update an existing GitHub issue's title, body, labels, assignees, or milestone WITHOUT closing it. This tool is primarily for editing issue metadata and content. While it supports changing status between 'open' and 'closed', use close_issue instead when you want to close an issue with a closing comment. Body updates support replacing, appending to, prepending content, or updating a per-run \"island\" section. CONSTRAINTS: Maximum 1 issue(s) can be updated.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "assignees": { - "description": "Replace the issue assignees with this list of GitHub usernames (e.g., ['octocat', 'mona']).", - "items": { - "type": "string" - }, - "type": "array" - }, - "body": { - "description": "Issue body content in Markdown. For 'replace', this becomes the entire body. For 'append'/'prepend', this content is added with a separator and an attribution footer. For 'replace-island', only the run-specific section is updated.", - "type": "string" - }, - "issue_number": { - "description": "Issue number to update. This is the numeric ID from the GitHub URL (e.g., 789 in github.com/owner/repo/issues/789). Required when the workflow target is '*' (any issue).", - "type": [ - "number", - "string" - ] - }, - "labels": { - "description": "Replace the issue labels with this list (e.g., ['bug', 'tracking:foo']). Labels must exist in the repository.", - "items": { - "type": "string" - }, - "type": "array" - }, - "milestone": { - "description": "Milestone number to assign (e.g., 1). Use null to clear.", - "type": [ - "number", - "string" - ] - }, - "operation": { - "description": "How to update the issue body: 'append' (default - add to end with separator), 'prepend' (add to start with separator), 'replace' (overwrite entire body), or 'replace-island' (update a run-specific section).", - "enum": [ - "replace", - "append", - "prepend", - "replace-island" - ], - "type": "string" - }, - "status": { - "description": "New issue status: 'open' to reopen a closed issue, 'closed' to close an open issue.", - "enum": [ - "open", - "closed" - ], - "type": "string" - }, - "title": { - "description": "New issue title to replace the existing title.", - "type": "string" - } - }, - "type": "object" - }, - "name": "update_issue" - }, - { - "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "alternatives": { - "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", - "type": "string" - }, - "reason": { - "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).", - "type": "string" - }, - "tool": { - "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.", - "type": "string" - } - }, - "required": [ - "reason" - ], - "type": "object" - }, - "name": "missing_tool" - }, - { - "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "message": { - "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').", - "type": "string" - } - }, - "required": [ - "message" - ], - "type": "object" - }, - "name": "noop" - }, - { - "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "alternatives": { - "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", - "type": "string" - }, - "context": { - "description": "Additional context about the missing data or where it should come from (max 256 characters).", - "type": "string" - }, - "data_type": { - "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.", - "type": "string" - }, - "reason": { - "description": "Explanation of why this data is needed to complete the task (max 256 characters).", - "type": "string" - } - }, - "required": [], - "type": "object" - }, - "name": "missing_data" - } - ] - GH_AW_SAFE_OUTPUTS_TOOLS_EOF - cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF' - { - "add_comment": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "item_number": { - "issueOrPRNumber": true - } - } - }, - "close_issue": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "issue_number": { - "optionalPositiveInteger": true - } - } - }, - "create_issue": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "labels": { - "type": "array", - "itemType": "string", - "itemSanitize": true, - "itemMaxLength": 128 - }, - "parent": { - "issueOrPRNumber": true - }, - "repo": { - "type": "string", - "maxLength": 256 - }, - "temporary_id": { - "type": "string" - }, - "title": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 128 - } - } - }, - "missing_tool": { - "defaultMax": 20, - "fields": { - "alternatives": { - "type": "string", - "sanitize": true, - "maxLength": 512 - }, - "reason": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 256 - }, - "tool": { - "type": "string", - "sanitize": true, - "maxLength": 128 - } - } - }, - "noop": { - "defaultMax": 1, - "fields": { - "message": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - } - } - }, - "update_issue": { - "defaultMax": 1, - "fields": { - "body": { - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "issue_number": { - "issueOrPRNumber": true - }, - "status": { - "type": "string", - "enum": [ - "open", - "closed" - ] - }, - "title": { - "type": "string", - "sanitize": true, - "maxLength": 128 - } - }, - "customValidation": "requiresOneOf:status,title,body" - } - } - GH_AW_SAFE_OUTPUTS_VALIDATION_EOF - - name: Generate Safe Outputs MCP Server Config - id: safe-outputs-config - run: | - # Generate a secure random API key (360 bits of entropy, 40+ chars) - # Mask immediately to prevent timing vulnerabilities - API_KEY=$(openssl rand -base64 45 | tr -d '/+=') - echo "::add-mask::${API_KEY}" - - PORT=3001 - - # Set outputs for next steps - { - echo "safe_outputs_api_key=${API_KEY}" - echo "safe_outputs_port=${PORT}" - } >> "$GITHUB_OUTPUT" - - echo "Safe Outputs MCP server will run on port ${PORT}" - - - name: Start Safe Outputs MCP HTTP Server - id: safe-outputs-start - env: - DEBUG: '*' - GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} - GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} - GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json - GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json - GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs - run: | - # Environment variables are set above to prevent template injection - export DEBUG - export GH_AW_SAFE_OUTPUTS_PORT - export GH_AW_SAFE_OUTPUTS_API_KEY - export GH_AW_SAFE_OUTPUTS_TOOLS_PATH - export GH_AW_SAFE_OUTPUTS_CONFIG_PATH - export GH_AW_MCP_LOG_DIR - - bash /opt/gh-aw/actions/start_safe_outputs_server.sh - - - name: Start MCP gateway - id: start-mcp-gateway - env: - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} - GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} - GITHUB_MCP_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }} - GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - run: | - set -eo pipefail - mkdir -p /tmp/gh-aw/mcp-config - - # Export gateway environment variables for MCP config and gateway script - export MCP_GATEWAY_PORT="80" - export MCP_GATEWAY_DOMAIN="host.docker.internal" - MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') - echo "::add-mask::${MCP_GATEWAY_API_KEY}" - export MCP_GATEWAY_API_KEY - export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads" - mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" - export DEBUG="*" - - export GH_AW_ENGINE="claude" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.4' - - cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh - { - "mcpServers": { - "github": { - "container": "ghcr.io/github/github-mcp-server:v0.30.3", - "env": { - "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN", - "GITHUB_PERSONAL_ACCESS_TOKEN": "$GITHUB_MCP_SERVER_TOKEN", - "GITHUB_READ_ONLY": "1", - "GITHUB_TOOLSETS": "context,repos,issues,pull_requests" - } - }, - "safeoutputs": { - "type": "http", - "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", - "headers": { - "Authorization": "$GH_AW_SAFE_OUTPUTS_API_KEY" - } - } - }, - "gateway": { - "port": $MCP_GATEWAY_PORT, - "domain": "${MCP_GATEWAY_DOMAIN}", - "apiKey": "${MCP_GATEWAY_API_KEY}", - "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" - } - } - GH_AW_MCP_CONFIG_EOF - - name: Generate workflow overview - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { generateWorkflowOverview } = require('/opt/gh-aw/actions/generate_workflow_overview.cjs'); - await generateWorkflowOverview(core); - - name: Create prompt with built-in context - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} - GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} - GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} - GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} - run: | - bash /opt/gh-aw/actions/create_prompt_first.sh - cat << 'GH_AW_PROMPT_EOF' > "$GH_AW_PROMPT" - - GH_AW_PROMPT_EOF - cat "/opt/gh-aw/prompts/xpia.md" >> "$GH_AW_PROMPT" - cat "/opt/gh-aw/prompts/temp_folder_prompt.md" >> "$GH_AW_PROMPT" - cat "/opt/gh-aw/prompts/markdown.md" >> "$GH_AW_PROMPT" - cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT" - - GitHub API Access Instructions - - The gh CLI is NOT authenticated. Do NOT use gh commands for GitHub operations. - - - To create or modify GitHub resources (issues, discussions, pull requests, etc.), you MUST call the appropriate safe output tool. Simply writing content will NOT work - the workflow requires actual tool calls. - - Temporary IDs: Some safe output tools support a temporary ID field (usually named temporary_id) so you can reference newly-created items elsewhere in the SAME agent output (for example, using #aw_abc1 in a later body). - - **IMPORTANT - temporary_id format rules:** - - If you DON'T need to reference the item later, OMIT the temporary_id field entirely (it will be auto-generated if needed) - - If you DO need cross-references/chaining, you MUST match this EXACT validation regex: /^aw_[A-Za-z0-9]{3,8}$/i - - Format: aw_ prefix followed by 3 to 8 alphanumeric characters (A-Z, a-z, 0-9, case-insensitive) - - Valid alphanumeric characters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 - - INVALID examples: aw_ab (too short), aw_123456789 (too long), aw_test-id (contains hyphen), aw_id_123 (contains underscore) - - VALID examples: aw_abc, aw_abc1, aw_Test123, aw_A1B2C3D4, aw_12345678 - - To generate valid IDs: use 3-8 random alphanumeric characters or omit the field to let the system auto-generate - - Do NOT invent other aw_* formats — downstream steps will reject them with validation errors matching against /^aw_[A-Za-z0-9]{3,8}$/i. - - Discover available tools from the safeoutputs MCP server. - - **Critical**: Tool calls write structured data that downstream jobs process. Without tool calls, follow-up actions will be skipped. - - **Note**: If you made no other safe output tool calls during this workflow execution, call the "noop" tool to provide a status message indicating completion or that no actions were needed. - - - - The following GitHub context information is available for this workflow: - {{#if __GH_AW_GITHUB_ACTOR__ }} - - **actor**: __GH_AW_GITHUB_ACTOR__ - {{/if}} - {{#if __GH_AW_GITHUB_REPOSITORY__ }} - - **repository**: __GH_AW_GITHUB_REPOSITORY__ - {{/if}} - {{#if __GH_AW_GITHUB_WORKSPACE__ }} - - **workspace**: __GH_AW_GITHUB_WORKSPACE__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} - - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} - - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} - - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} - - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ - {{/if}} - {{#if __GH_AW_GITHUB_RUN_ID__ }} - - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ - {{/if}} - - - The following workflow call inputs are available for this workflow: - - **issues_enabled**: __GH_AW_INPUTS_ISSUES_ENABLED__ - - **observed_findings_present**: __GH_AW_INPUTS_OBSERVED_FINDINGS_PRESENT__ - - **stats_artifact_name**: __GH_AW_INPUTS_STATS_ARTIFACT_NAME__ - - **findings_artifact_name**: __GH_AW_INPUTS_FINDINGS_ARTIFACT_NAME__ - - **source_sha**: __GH_AW_INPUTS_SOURCE_SHA__ - - **installed_source_sha**: __GH_AW_INPUTS_INSTALLED_SOURCE_SHA__ - - **installed_runtime_sha**: __GH_AW_INPUTS_INSTALLED_RUNTIME_SHA__ - - **analyze_day**: __GH_AW_INPUTS_ANALYZE_DAY__ - - **report_tz**: __GH_AW_INPUTS_REPORT_TZ__ - - **force_analyze**: __GH_AW_INPUTS_FORCE_ANALYZE__ - - **run_id**: __GH_AW_GITHUB_RUN_ID__ - - **actor**: __GH_AW_GITHUB_ACTOR__ - - **workflow-run-url**: __GH_AW_GITHUB_SERVER_URL__/__GH_AW_GITHUB_REPOSITORY__/actions/runs/__GH_AW_GITHUB_RUN_ID__ - - - GH_AW_PROMPT_EOF - cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT" - - GH_AW_PROMPT_EOF - cat << 'GH_AW_PROMPT_EOF' >> "$GH_AW_PROMPT" - # Doctor Analyze - - ## TL;DR - - Read-only analyze job for the `doctor` workflow. Downloads `collect` artifacts, - validates findings, and manages a deterministic GitHub issue for observed drift. - Writes `doctor-report.json` as the only persistent output. - - You are the `analyze` job for the repository described in the `` block above. - This workflow is called only from `doctor.yml` and must stay read-only for repository files. - Never create PRs. Never edit tracked repository files. The only persistent outputs you may write are: - - - `doctor-report.json` in the workspace root - - mirrored copies of the same report under `/tmp/gh-aw/agent/` so the - current compiled workflow uploads them via generic agent artifacts - - Temporary scratch files are allowed only if they are needed to build or validate the report. - - ## Runtime Context - - Treat the `` block from the system prompt as the runtime contract from `collect`. - It must provide these keys: - - - `issues_enabled` - - `observed_findings_present` - - `stats_artifact_name` - - `findings_artifact_name` - - `source_sha` - - `installed_source_sha` - - `installed_runtime_sha` - - `analyze_day` - - `report_tz` - - `force_analyze` - - `run_id` - - `actor` - - `workflow_run_url` - - Read `run_attempt` from env var `GITHUB_RUN_ATTEMPT` via Bash. - Read `event_name` from env var `GITHUB_EVENT_NAME` via Bash. - If the `` block is missing any required key, record - that in `runtime_notes[]`, write `doctor-report.json` with - `issue.reason = "model_error"`, and exit with failure. - - Use `report_tz` to derive: - - - `report_date` in `YYYY-MM-DD` - - `today_name` as a lowercase English weekday name - - `analyze_day_match = (today_name == analyze_day.lower())` - - `manual_override = (force_analyze == true)` - - ## Operating Rules - - - Use GitHub MCP tools only for read operations: artifacts, issues, labels, workflow metadata, repository contents. - - Use safe outputs only for issue mutations: `create-issue`, `update-issue`, `close-issue`, `add-comment`. - - Never perform direct write mutations through bash, git, or raw GitHub API calls. - - Prefer GitHub MCP tools for workflow runs, artifacts, issues, and labels. - - If workflow artifact MCP tools are unavailable in the exposed tool list, - you may use `Bash` with authenticated GitHub API calls for artifact lookup - and download only. - - Never use unauthenticated `gh` or unauthenticated `curl` for GitHub API access. - - For authenticated fallback in Bash, export - `GH_TOKEN="$GITHUB_TOKEN"` before `gh api`, or use `curl` with header - `Authorization: Bearer $GITHUB_TOKEN`. - - `collect` is the source of truth for findings and severities. Do not invent new finding IDs or new finding categories. - - Limit issue-generating analysis to findings where: - - `category == observed` - - `auto_action == analyze` - - `path` is one of: - - `AGENTS.md` - - `CLAUDE.md` - - `DOCS.md` - - `.specify/memory/constitution.md` - - `docs/quickstart.md` - - You may read repository files to improve recommendations and evidence, - but not to expand the scope beyond the allowed observed-only paths. - - ## Required Procedure - - 1. Start by creating a scratch work directory for downloaded artifacts and intermediate notes. - 2. Compute `report_date`, `today_name`, `analyze_day_match`, and `manual_override`. - 3. Initialize `runtime_notes[]` and a draft `doctor-report.json` object. - - ### Runtime Gate - - Apply gates in this order: - - 1. If `observed_findings_present != "true"`: - - write `doctor-report.json` - - set: - - `decision.observed_findings_present = false` - - `decision.qualifying_findings_present = false` - - `issue.action = "none"` - - `issue.reason = "no_observed_findings"` - - do not download artifacts - - do not call safe outputs - - exit successfully - 2. If `manual_override` is false and `analyze_day_match` is false: - - write `doctor-report.json` - - set: - - `decision.observed_findings_present = true` - - `decision.qualifying_findings_present = false` - - `issue.action = "skipped"` - - `issue.reason = "not_analyze_day"` - - do not call safe outputs - - exit successfully - 3. Otherwise continue to artifact download and analysis. - - ## Artifact Download And Validation - - Download artifacts from the current workflow run identified in - `` using the exact artifact names from `collect`: - - - the `stats_artifact_name` value from `` - - the `findings_artifact_name` value from `` - - the predownloaded local files, when present: - - `/tmp/gh-aw/collect-artifacts/stats/doctor-stats.json` - - `/tmp/gh-aw/collect-artifacts/findings/doctor-findings.json` - - Required procedure for artifact access: - - 1. First check the predownloaded local files under - `/tmp/gh-aw/collect-artifacts/`. If both required files are present, use - them as the primary source and do not attempt network artifact lookup. - 2. If either local file is missing, prefer GitHub MCP workflow run and artifact tools when they are available. - 3. If the matching collect artifacts are not listed yet, wait 2 seconds and retry once using the same access path. - 4. If workflow artifact MCP tools are unavailable, use authenticated Bash fallback: - - `GH_TOKEN="$GITHUB_TOKEN" gh api ...` - - or `curl -H "Authorization: Bearer $GITHUB_TOKEN" ...` - 5. Only use workspace or runner filesystem search as a secondary diagnostic - note after both the predownloaded local files and the authenticated - access paths fail. - 6. Do not use unauthenticated `gh api`, unauthenticated `curl`, or raw REST calls without `GITHUB_TOKEN`. - - Expect these files: - - - `doctor-stats.json` - - `doctor-findings.json` - - Validate both artifacts before analysis. Treat any missing file, invalid - JSON, missing required field, wrong schema version, or type mismatch as - `artifact_invalid`. - - Minimum required validation for `doctor-stats.json`: - - - `schema_version == "doctor-stats/v3"` - - `collected_at` - - `report_date` - - `window.from` - - `window.to` - - `repo.full_name` - - `repo.default_branch` - - `workflow.run_id` - - `workflow.run_attempt` - - `workflow.event_name` - - `workflow.actor` - - `source_repo.full_name` - - `source_repo.source_branch` - - `source_repo.source_sha` - - `activity.commits` - - `activity.prs` - - `activity.issues` - - `snapshot.prs` - - `snapshot.issues` - - Minimum required validation for `doctor-findings.json`: - - - `schema_version == "doctor-findings/v4"` - - `collected_at` - - `report_date` - - `repo.full_name` - - `repo.default_branch` - - `source_repo.source_branch` - - `source_repo.source_sha` - - `decision.should_act` - - `decision.act_reason` - - `decision.managed_drift_present` - - `decision.runtime_drift_present` - - `decision.observed_findings_present` - - `findings[]` - - For every analyzed finding, require: - - - `id` - - `category` - - `severity` - - `path` - - `state` - - `auto_action` - - `message` - - If artifact validation fails: - - - write `doctor-report.json` - - set: - - `issue.action = "failed"` - - `issue.reason = "artifact_invalid"` - - add a precise explanation to `runtime_notes[]` - - do not call safe outputs - - exit with failure - - ## Analysis Scope - - Analyze only findings from `doctor-findings.json` where: - - - `category == "observed"` - - `auto_action == "analyze"` - - Exclude from issue generation: - - - `managed` - - `runtime` - - `operational` - - observed checks outside the allowed path scope - - Keep `info` findings in `analysis[]`, but they do not qualify for an issue. - Qualifying findings are only severities: - - - `warning` - - `error` - - ## Analysis Rules - - For each in-scope observed finding: - - 1. Preserve the original `finding_id`, `path`, `severity`, `state`, and `message`. - 2. Read the current repository path when it exists and use that only as supporting evidence. - 3. Produce one `analysis[]` item with: - - `finding_id` - - `category = "observed"` - - `path` - - `severity` - - `state` - - `qualifies_for_issue` - - `summary` - - `recommendation` - - `evidence[]` - - Use these guidance rules: - - - `AGENTS.md` missing: - - explain that the repo is missing the agent entry point - - recommend restoring the file or a valid symlink in the root - - `CLAUDE.md` missing: - - explain that the repo is missing the Claude-facing entry point - - recommend restoring the file or a valid symlink in the root - - `DOCS.md` missing: - - explain that the repo is missing the main docs entry point in the root - - recommend restoring the file or a valid symlink in the root - - `docs/quickstart.md` missing or placeholder: - - recommend a real first-run or onboarding guide - - `.specify/memory/constitution.md` missing or placeholder: - - recommend restoring and tracking a real working agreement - - When files exist but appear placeholder-like or incomplete, use concrete evidence such as: - - - obvious placeholder markers: `TODO`, `TBD`, `placeholder`, `coming soon`, `lorem ipsum`, `template` - - extremely short content with no actionable project-specific instructions - - Do not create duplicate recommendations for the same path family. Group repeated ideas. - - ## Issue Policy - - Deterministic issue title: - - - `Toolkit doctor: observed drift` - - Preferred labels when available: - - - `toolkit` - - `doctor` - - Issue body must contain these sections: - - - `## Summary` - - `## Findings` - - `## Recommendations` - - `## Context` - - Issue body requirements: - - - concise summary of current qualifying warnings and errors - - bullet list or table of qualifying findings with: - - path - - severity - - message - - short grouped recommendations - - link to the `workflow_run_url` value from `` - - short activity context from `doctor-stats.json` only if it clearly helps prioritization - - Use read-only GitHub tools to find an existing open issue with the exact title `Toolkit doctor: observed drift`. - Do not create duplicates. - - Before issue mutation: - - 1. Check whether labels `toolkit` and `doctor` exist. - 2. If one or both labels are missing: - - continue without the missing labels - - record the problem in `runtime_notes[]` - 3. If an existing deterministic issue is locked: - - write `doctor-report.json` - - set: - - `issue.action = "failed"` - - `issue.reason = "issue_locked"` - - do not create a duplicate - - exit with failure - - ## Issue Lifecycle - - After analysis, compute: - - - `findings_analyzed` - - `qualifying_findings` - - `warning_count` - - `error_count` - - `qualifying_findings_present` - - Then apply this lifecycle: - - 1. If `qualifying_findings_present == false`: - - if an open deterministic issue exists: - - add a resolution comment that observed drift is no longer present in the latest analyze run - - close that issue - - set: - - `issue.action = "closed"` - - `issue.reason = "closed_resolved"` - - otherwise: - - set: - - `issue.action = "none"` - - `issue.reason = "no_qualifying_findings"` - 2. If `qualifying_findings_present == true` and `issues_enabled != "true"`: - - perform the full analysis - - do not create, update, close, or comment on issues - - set: - - `issue.action = "skipped"` - - `issue.reason = "issues_disabled"` - - if an existing deterministic issue exists, keep its metadata in the report but do not mutate it - 3. If `qualifying_findings_present == true` and no open deterministic issue exists: - - create one issue through `create-issue` - - set: - - `issue.action = "created"` - - `issue.reason = "created_new"` - 4. If `qualifying_findings_present == true` and an open deterministic issue exists: - - update that exact issue through `update-issue` - - set: - - `issue.action = "updated"` - - `issue.reason = "updated_existing"` - - Never use direct GitHub write APIs for issues. Safe outputs only. - - ## doctor-report.json - - Always write `doctor-report.json` before exiting, including skip and failure paths. - - Write the same final JSON payload to all of these paths: - - - `./doctor-report.json` - - `/tmp/gh-aw/agent/doctor-report.json` - - `/tmp/gh-aw/agent/doctor-report-${report_date}.json` - - This is a temporary workaround until the compiled reusable workflow gets a - dedicated `upload-artifact` step for a `doctor-report-YYYY-MM-DD` artifact. - - Required top-level schema: - - ```json - { - "schema_version": "doctor-report/v1", - "analyzed_at": "RFC3339", - "report_date": "YYYY-MM-DD", - "repo": { - "full_name": "owner/repo" - }, - "workflow": { - "run_id": 0, - "run_attempt": 0, - "event_name": "workflow_dispatch|schedule|...", - "actor": "github-user" - }, - "inputs": { - "stats_artifact_name": "doctor-stats-YYYY-MM-DD", - "findings_artifact_name": "doctor-findings-YYYY-MM-DD" - }, - "decision": { - "observed_findings_present": true, - "issues_enabled": true, - "analyze_day_match": true, - "manual_override": false, - "qualifying_findings_present": true - }, - "issue": { - "action": "created|updated|closed|skipped|none|failed", - "reason": "created_new|updated_existing|closed_resolved|issues_disabled|not_analyze_day|no_observed_findings|no_qualifying_findings|artifact_invalid|model_error|issue_locked", - "number": 0, - "url": "https://github.com/owner/repo/issues/123", - "title": "Toolkit doctor: observed drift" - }, - "summary": { - "findings_analyzed": 0, - "qualifying_findings": 0, - "warning_count": 0, - "error_count": 0 - }, - "runtime_notes": [], - "analysis": [ - { - "finding_id": "observed.docs_quickstart_md.missing", - "category": "observed", - "path": "docs/quickstart.md", - "severity": "warning", - "state": "missing", - "qualifies_for_issue": true, - "summary": "Repository is missing the onboarding quickstart.", - "recommendation": "Add a real quickstart with first-run instructions for contributors.", - "evidence": [ - "doctor-findings.json: observed.docs_quickstart_md.missing", - "docs/quickstart.md is absent in the checked out repository" - ] - } - ] - } - ``` - - Populate `issue.number`, `issue.url`, and `issue.title` with `null` when absent. - `analysis[]` must include every analyzed observed finding, including - `info`, with `qualifies_for_issue` set appropriately. - - ## Failure Handling - - If you encounter a temporary tool or execution error while downloading - artifacts, reading repository context, or building issue text: - - 1. retry once - 2. if the retry succeeds, continue - 3. if the retry fails, write `doctor-report.json` with: - - `issue.action = "failed"` - - `issue.reason = "model_error"` - 4. add a precise note to `runtime_notes[]` - 5. exit with failure - - For all failure paths: - - - prefer a valid `doctor-report.json` over incomplete changes - - do not create duplicate issues - - do not mutate repository files - - ## Final Checklist - - Before finishing, verify all of the following: - - - `doctor-report.json` exists and is valid JSON - - the mirrored report copies exist in `/tmp/gh-aw/agent/` - - `schema_version == "doctor-report/v1"` - - issue decisions use only the allowed enums - - safe outputs, if any, were used only after artifact validation and only when allowed by runtime gates - - no repository files were modified other than `doctor-report.json` and temporary scratch files - GH_AW_PROMPT_EOF - - name: Substitute placeholders - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} - GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} - GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} - GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} - GH_AW_GITHUB_SERVER_URL: ${{ github.server_url }} - GH_AW_INPUTS_ANALYZE_DAY: ${{ inputs.analyze_day }} - GH_AW_INPUTS_FINDINGS_ARTIFACT_NAME: ${{ inputs.findings_artifact_name }} - GH_AW_INPUTS_FORCE_ANALYZE: ${{ inputs.force_analyze }} - GH_AW_INPUTS_INSTALLED_RUNTIME_SHA: ${{ inputs.installed_runtime_sha }} - GH_AW_INPUTS_INSTALLED_SOURCE_SHA: ${{ inputs.installed_source_sha }} - GH_AW_INPUTS_ISSUES_ENABLED: ${{ inputs.issues_enabled }} - GH_AW_INPUTS_OBSERVED_FINDINGS_PRESENT: ${{ inputs.observed_findings_present }} - GH_AW_INPUTS_REPORT_TZ: ${{ inputs.report_tz }} - GH_AW_INPUTS_SOURCE_SHA: ${{ inputs.source_sha }} - GH_AW_INPUTS_STATS_ARTIFACT_NAME: ${{ inputs.stats_artifact_name }} - with: - script: | - const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs'); - - // Call the substitution function - return await substitutePlaceholders({ - file: process.env.GH_AW_PROMPT, - substitutions: { - GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, - GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, - GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, - GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, - GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, - GH_AW_GITHUB_SERVER_URL: process.env.GH_AW_GITHUB_SERVER_URL, - GH_AW_INPUTS_ANALYZE_DAY: process.env.GH_AW_INPUTS_ANALYZE_DAY, - GH_AW_INPUTS_FINDINGS_ARTIFACT_NAME: process.env.GH_AW_INPUTS_FINDINGS_ARTIFACT_NAME, - GH_AW_INPUTS_FORCE_ANALYZE: process.env.GH_AW_INPUTS_FORCE_ANALYZE, - GH_AW_INPUTS_INSTALLED_RUNTIME_SHA: process.env.GH_AW_INPUTS_INSTALLED_RUNTIME_SHA, - GH_AW_INPUTS_INSTALLED_SOURCE_SHA: process.env.GH_AW_INPUTS_INSTALLED_SOURCE_SHA, - GH_AW_INPUTS_ISSUES_ENABLED: process.env.GH_AW_INPUTS_ISSUES_ENABLED, - GH_AW_INPUTS_OBSERVED_FINDINGS_PRESENT: process.env.GH_AW_INPUTS_OBSERVED_FINDINGS_PRESENT, - GH_AW_INPUTS_REPORT_TZ: process.env.GH_AW_INPUTS_REPORT_TZ, - GH_AW_INPUTS_SOURCE_SHA: process.env.GH_AW_INPUTS_SOURCE_SHA, - GH_AW_INPUTS_STATS_ARTIFACT_NAME: process.env.GH_AW_INPUTS_STATS_ARTIFACT_NAME, - } - }); - - name: Interpolate variables and render templates - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/interpolate_prompt.cjs'); - await main(); - - name: Validate prompt placeholders - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh - - name: Print prompt - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - run: bash /opt/gh-aw/actions/print_prompt_summary.sh - - name: Clean git credentials - run: bash /opt/gh-aw/actions/clean_git_credentials.sh - - name: Execute Claude Code CLI - id: agentic_execution - # Allowed tools (sorted): - # - Bash - # - BashOutput - # - Edit - # - ExitPlanMode - # - Glob - # - Grep - # - KillBash - # - LS - # - MultiEdit - # - NotebookEdit - # - NotebookRead - # - Read - # - Task - # - TodoWrite - # - Write - # - mcp__github__download_workflow_run_artifact - # - mcp__github__get_code_scanning_alert - # - mcp__github__get_commit - # - mcp__github__get_dependabot_alert - # - mcp__github__get_discussion - # - mcp__github__get_discussion_comments - # - mcp__github__get_file_contents - # - mcp__github__get_job_logs - # - mcp__github__get_label - # - mcp__github__get_latest_release - # - mcp__github__get_me - # - mcp__github__get_notification_details - # - mcp__github__get_pull_request - # - mcp__github__get_pull_request_comments - # - mcp__github__get_pull_request_diff - # - mcp__github__get_pull_request_files - # - mcp__github__get_pull_request_review_comments - # - mcp__github__get_pull_request_reviews - # - mcp__github__get_pull_request_status - # - mcp__github__get_release_by_tag - # - mcp__github__get_secret_scanning_alert - # - mcp__github__get_tag - # - mcp__github__get_workflow_run - # - mcp__github__get_workflow_run_logs - # - mcp__github__get_workflow_run_usage - # - mcp__github__issue_read - # - mcp__github__list_branches - # - mcp__github__list_code_scanning_alerts - # - mcp__github__list_commits - # - mcp__github__list_dependabot_alerts - # - mcp__github__list_discussion_categories - # - mcp__github__list_discussions - # - mcp__github__list_issue_types - # - mcp__github__list_issues - # - mcp__github__list_label - # - mcp__github__list_notifications - # - mcp__github__list_pull_requests - # - mcp__github__list_releases - # - mcp__github__list_secret_scanning_alerts - # - mcp__github__list_starred_repositories - # - mcp__github__list_tags - # - mcp__github__list_workflow_jobs - # - mcp__github__list_workflow_run_artifacts - # - mcp__github__list_workflow_runs - # - mcp__github__list_workflows - # - mcp__github__pull_request_read - # - mcp__github__search_code - # - mcp__github__search_issues - # - mcp__github__search_orgs - # - mcp__github__search_pull_requests - # - mcp__github__search_repositories - # - mcp__github__search_users - timeout-minutes: 20 - run: | - set -o pipefail - sudo -E awf --tty --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.18.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && claude --print --disable-slash-commands --no-chrome --mcp-config /tmp/gh-aw/mcp-config/mcp-servers.json --allowed-tools Bash,BashOutput,Edit,ExitPlanMode,Glob,Grep,KillBash,LS,MultiEdit,NotebookEdit,NotebookRead,Read,Task,TodoWrite,Write,mcp__github__download_workflow_run_artifact,mcp__github__get_code_scanning_alert,mcp__github__get_commit,mcp__github__get_dependabot_alert,mcp__github__get_discussion,mcp__github__get_discussion_comments,mcp__github__get_file_contents,mcp__github__get_job_logs,mcp__github__get_label,mcp__github__get_latest_release,mcp__github__get_me,mcp__github__get_notification_details,mcp__github__get_pull_request,mcp__github__get_pull_request_comments,mcp__github__get_pull_request_diff,mcp__github__get_pull_request_files,mcp__github__get_pull_request_review_comments,mcp__github__get_pull_request_reviews,mcp__github__get_pull_request_status,mcp__github__get_release_by_tag,mcp__github__get_secret_scanning_alert,mcp__github__get_tag,mcp__github__get_workflow_run,mcp__github__get_workflow_run_logs,mcp__github__get_workflow_run_usage,mcp__github__issue_read,mcp__github__list_branches,mcp__github__list_code_scanning_alerts,mcp__github__list_commits,mcp__github__list_dependabot_alerts,mcp__github__list_discussion_categories,mcp__github__list_discussions,mcp__github__list_issue_types,mcp__github__list_issues,mcp__github__list_label,mcp__github__list_notifications,mcp__github__list_pull_requests,mcp__github__list_releases,mcp__github__list_secret_scanning_alerts,mcp__github__list_starred_repositories,mcp__github__list_tags,mcp__github__list_workflow_jobs,mcp__github__list_workflow_run_artifacts,mcp__github__list_workflow_runs,mcp__github__list_workflows,mcp__github__pull_request_read,mcp__github__search_code,mcp__github__search_issues,mcp__github__search_orgs,mcp__github__search_pull_requests,mcp__github__search_repositories,mcp__github__search_users --debug-file /tmp/gh-aw/agent-stdio.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_CLAUDE:+ --model "$GH_AW_MODEL_AGENT_CLAUDE"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - BASH_DEFAULT_TIMEOUT_MS: 60000 - BASH_MAX_TIMEOUT_MS: 60000 - CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - DISABLE_BUG_COMMAND: 1 - DISABLE_ERROR_REPORTING: 1 - DISABLE_TELEMETRY: 1 - GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/mcp-servers.json - GH_AW_MODEL_AGENT_CLAUDE: ${{ vars.GH_AW_MODEL_AGENT_CLAUDE || '' }} - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GITHUB_WORKSPACE: ${{ github.workspace }} - MCP_TIMEOUT: 120000 - MCP_TOOL_TIMEOUT: 60000 - - name: Configure Git credentials - env: - REPO_NAME: ${{ github.repository }} - SERVER_URL: ${{ github.server_url }} - run: | - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git config --global user.name "github-actions[bot]" - # Re-authenticate git with GitHub token - SERVER_URL_STRIPPED="${SERVER_URL#https://}" - git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" - echo "Git configured with standard GitHub Actions identity" - - name: Stop MCP gateway - if: always() - continue-on-error: true - env: - MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} - MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} - GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} - run: | - bash /opt/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID" - - name: Redact secrets in logs - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs'); - await main(); - env: - GH_AW_SECRET_NAMES: 'ANTHROPIC_API_KEY,CLAUDE_CODE_OAUTH_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' - SECRET_ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - SECRET_CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} - SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload Safe Outputs - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: safe-output - path: ${{ env.GH_AW_SAFE_OUTPUTS }} - if-no-files-found: warn - - name: Ingest agent output - id: collect_output - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,playwright.download.prss.microsoft.com,ppa.launchpad.net,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" - GITHUB_SERVER_URL: ${{ github.server_url }} - GITHUB_API_URL: ${{ github.api_url }} - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs'); - await main(); - - name: Upload sanitized agent output - if: always() && env.GH_AW_AGENT_OUTPUT - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: agent-output - path: ${{ env.GH_AW_AGENT_OUTPUT }} - if-no-files-found: warn - - name: Parse agent logs for step summary - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: /tmp/gh-aw/agent-stdio.log - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_claude_log.cjs'); - await main(); - - name: Parse MCP gateway logs for step summary - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_mcp_gateway_log.cjs'); - await main(); - - name: Print firewall logs - if: always() - continue-on-error: true - env: - AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs - run: | - # Fix permissions on firewall logs so they can be uploaded as artifacts - # AWF runs with sudo, creating files owned by root - sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true - awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" - - name: Upload agent artifacts - if: always() - continue-on-error: true - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: agent-artifacts - path: | - /tmp/gh-aw/aw-prompts/prompt.txt - /tmp/gh-aw/aw_info.json - /tmp/gh-aw/mcp-logs/ - /tmp/gh-aw/sandbox/firewall/logs/ - /tmp/gh-aw/agent-stdio.log - /tmp/gh-aw/agent/ - if-no-files-found: ignore - - conclusion: - needs: - - activation - - agent - - detection - - safe_outputs - if: (always()) && (needs.agent.result != 'skipped') - runs-on: ubuntu-slim - permissions: - contents: read - discussions: write - issues: write - pull-requests: write - outputs: - noop_message: ${{ steps.noop.outputs.noop_message }} - tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} - total_count: ${{ steps.missing_tool.outputs.total_count }} - steps: - - name: Setup Scripts - uses: github/gh-aw/actions/setup@cec1ecf3b97e9a1bbffaedf490a49ce03c1071ba # v0.44.0 - with: - destination: /opt/gh-aw/actions - - name: Download agent output artifact - continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - with: - name: agent-output - path: /tmp/gh-aw/safeoutputs/ - - name: Setup agent output environment variable - run: | - mkdir -p /tmp/gh-aw/safeoutputs/ - find "/tmp/gh-aw/safeoutputs/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" - - name: Process No-Op Messages - id: noop - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_NOOP_MAX: 1 - GH_AW_WORKFLOW_NAME: "doctor-analyze" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/noop.cjs'); - await main(); - - name: Record Missing Tool - id: missing_tool - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "doctor-analyze" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/missing_tool.cjs'); - await main(); - - name: Handle Agent Failure - id: handle_agent_failure - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "doctor-analyze" - GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_WORKFLOW_ID: "doctor-analyze" - GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.agent.outputs.secret_verification_result }} - GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/handle_agent_failure.cjs'); - await main(); - - name: Handle No-Op Message - id: handle_noop_message - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "doctor-analyze" - GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }} - GH_AW_NOOP_REPORT_AS_ISSUE: "true" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs'); - await main(); - - name: Update reaction comment with completion status - id: conclusion - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} - GH_AW_COMMENT_REPO: ${{ needs.activation.outputs.comment_repo }} - GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_AW_WORKFLOW_NAME: "doctor-analyze" - GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.result }} - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/notify_comment_error.cjs'); - await main(); - - detection: - needs: agent - if: needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true' - runs-on: ubuntu-latest - permissions: {} - timeout-minutes: 10 - outputs: - success: ${{ steps.parse_results.outputs.success }} - steps: - - name: Setup Scripts - uses: github/gh-aw/actions/setup@cec1ecf3b97e9a1bbffaedf490a49ce03c1071ba # v0.44.0 - with: - destination: /opt/gh-aw/actions - - name: Download agent artifacts - continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - with: - name: agent-artifacts - path: /tmp/gh-aw/threat-detection/ - - name: Download agent output artifact - continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - with: - name: agent-output - path: /tmp/gh-aw/threat-detection/ - - name: Echo agent output types - env: - AGENT_OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }} - run: | - echo "Agent output-types: $AGENT_OUTPUT_TYPES" - - name: Setup threat detection - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - WORKFLOW_NAME: "doctor-analyze" - WORKFLOW_DESCRIPTION: "No description provided" - HAS_PATCH: ${{ needs.agent.outputs.has_patch }} - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/setup_threat_detection.cjs'); - await main(); - - name: Ensure threat-detection directory and log - run: | - mkdir -p /tmp/gh-aw/threat-detection - touch /tmp/gh-aw/threat-detection/detection.log - - name: Validate CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY secret - id: validate-secret - run: /opt/gh-aw/actions/validate_multi_secret.sh CLAUDE_CODE_OAUTH_TOKEN ANTHROPIC_API_KEY 'Claude Code' https://github.github.com/gh-aw/reference/engines/#anthropic-claude-code - env: - CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: '24' - package-manager-cache: false - - name: Install Claude Code CLI - run: npm install -g --silent @anthropic-ai/claude-code@2.1.42 - - name: Execute Claude Code CLI - id: agentic_execution - # Allowed tools (sorted): - # - Bash(cat) - # - Bash(grep) - # - Bash(head) - # - Bash(jq) - # - Bash(ls) - # - Bash(tail) - # - Bash(wc) - # - BashOutput - # - ExitPlanMode - # - Glob - # - Grep - # - KillBash - # - LS - # - NotebookRead - # - Read - # - Task - # - TodoWrite - timeout-minutes: 20 - run: | - set -o pipefail - # Execute Claude Code CLI with prompt from file - claude --print --disable-slash-commands --no-chrome --allowed-tools 'Bash(cat),Bash(grep),Bash(head),Bash(jq),Bash(ls),Bash(tail),Bash(wc),BashOutput,ExitPlanMode,Glob,Grep,KillBash,LS,NotebookRead,Read,Task,TodoWrite' --debug-file /tmp/gh-aw/threat-detection/detection.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_CLAUDE:+ --model "$GH_AW_MODEL_DETECTION_CLAUDE"} 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - BASH_DEFAULT_TIMEOUT_MS: 60000 - BASH_MAX_TIMEOUT_MS: 60000 - CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - DISABLE_BUG_COMMAND: 1 - DISABLE_ERROR_REPORTING: 1 - DISABLE_TELEMETRY: 1 - GH_AW_MODEL_DETECTION_CLAUDE: ${{ vars.GH_AW_MODEL_DETECTION_CLAUDE || '' }} - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GITHUB_WORKSPACE: ${{ github.workspace }} - MCP_TIMEOUT: 120000 - MCP_TOOL_TIMEOUT: 60000 - - name: Parse threat detection results - id: parse_results - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs'); - await main(); - - name: Upload threat detection log - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: threat-detection.log - path: /tmp/gh-aw/threat-detection/detection.log - if-no-files-found: ignore - - pre_activation: - runs-on: ubuntu-slim - outputs: - activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} - steps: - - name: Setup Scripts - uses: github/gh-aw/actions/setup@cec1ecf3b97e9a1bbffaedf490a49ce03c1071ba # v0.44.0 - with: - destination: /opt/gh-aw/actions - - name: Check team membership for workflow - id: check_membership - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_REQUIRED_ROLES: admin,maintainer,write - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/check_membership.cjs'); - await main(); - - safe_outputs: - needs: - - agent - - detection - if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.detection.outputs.success == 'true') - runs-on: ubuntu-slim - permissions: - contents: read - discussions: write - issues: write - pull-requests: write - timeout-minutes: 15 - env: - GH_AW_ENGINE_ID: "claude" - GH_AW_WORKFLOW_ID: "doctor-analyze" - GH_AW_WORKFLOW_NAME: "doctor-analyze" - outputs: - create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} - create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} - process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} - process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} - steps: - - name: Setup Scripts - uses: github/gh-aw/actions/setup@cec1ecf3b97e9a1bbffaedf490a49ce03c1071ba # v0.44.0 - with: - destination: /opt/gh-aw/actions - - name: Download agent output artifact - continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - with: - name: agent-output - path: /tmp/gh-aw/safeoutputs/ - - name: Setup agent output environment variable - run: | - mkdir -p /tmp/gh-aw/safeoutputs/ - find "/tmp/gh-aw/safeoutputs/" -type f -print - echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" - - name: Process Safe Outputs - id: process_safe_outputs - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"close_issue\":{\"max\":1},\"create_issue\":{\"max\":1},\"missing_data\":{},\"missing_tool\":{},\"update_issue\":{\"allow_body\":true,\"max\":1}}" - with: - github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs'); - await main(); - diff --git a/.github/workflows/doctor-analyze.md b/.github/workflows/doctor-analyze.md deleted file mode 100644 index 73250d9..0000000 --- a/.github/workflows/doctor-analyze.md +++ /dev/null @@ -1,503 +0,0 @@ ---- -name: doctor-analyze -on: - workflow_call: - inputs: - force_analyze: - required: false - type: boolean - analyze_day: - required: true - type: string - report_tz: - required: true - type: string - issues_enabled: - required: true - type: string - observed_findings_present: - required: true - type: string - stats_artifact_name: - required: true - type: string - findings_artifact_name: - required: true - type: string - source_sha: - required: false - type: string - installed_source_sha: - required: false - type: string - installed_runtime_sha: - required: false - type: string -permissions: - contents: read - issues: read - pull-requests: read - actions: read -safe-outputs: - create-issue: - update-issue: - close-issue: - add-comment: -engine: claude ---- - -# Doctor Analyze - -## TL;DR - -Read-only analyze job for the `doctor` workflow. Downloads `collect` artifacts, -validates findings, and manages a deterministic GitHub issue for observed drift. -Writes `doctor-report.json` as the only persistent output. - -You are the `analyze` job for the repository described in the `` block above. -This workflow is called only from `doctor.yml` and must stay read-only for repository files. -Never create PRs. Never edit tracked repository files. The only persistent outputs you may write are: - -- `doctor-report.json` in the workspace root -- mirrored copies of the same report under `/tmp/gh-aw/agent/` so the - current compiled workflow uploads them via generic agent artifacts - -Temporary scratch files are allowed only if they are needed to build or validate the report. - -## Runtime Context - -Treat the `` block from the system prompt as the runtime contract from `collect`. -It must provide these keys: - -- `issues_enabled` -- `observed_findings_present` -- `stats_artifact_name` -- `findings_artifact_name` -- `source_sha` -- `installed_source_sha` -- `installed_runtime_sha` -- `analyze_day` -- `report_tz` -- `force_analyze` -- `run_id` -- `actor` -- `workflow_run_url` - -Read `run_attempt` from env var `GITHUB_RUN_ATTEMPT` via Bash. -Read `event_name` from env var `GITHUB_EVENT_NAME` via Bash. -If the `` block is missing any required key, record -that in `runtime_notes[]`, write `doctor-report.json` with -`issue.reason = "model_error"`, and exit with failure. - -Use `report_tz` to derive: - -- `report_date` in `YYYY-MM-DD` -- `today_name` as a lowercase English weekday name -- `analyze_day_match = (today_name == analyze_day.lower())` -- `manual_override = (force_analyze == true)` - -## Operating Rules - -- Use GitHub MCP tools only for read operations: artifacts, issues, labels, workflow metadata, repository contents. -- Use safe outputs only for issue mutations: `create-issue`, `update-issue`, `close-issue`, `add-comment`. -- Never perform direct write mutations through bash, git, or raw GitHub API calls. -- Prefer GitHub MCP tools for workflow runs, artifacts, issues, and labels. -- If workflow artifact MCP tools are unavailable in the exposed tool list, - you may use `Bash` with authenticated GitHub API calls for artifact lookup - and download only. -- Never use unauthenticated `gh` or unauthenticated `curl` for GitHub API access. -- For authenticated fallback in Bash, export - `GH_TOKEN="$GITHUB_TOKEN"` before `gh api`, or use `curl` with header - `Authorization: Bearer $GITHUB_TOKEN`. -- `collect` is the source of truth for findings and severities. Do not invent new finding IDs or new finding categories. -- Limit issue-generating analysis to findings where: - - `category == observed` - - `auto_action == analyze` - - `path` is one of: - - `AGENTS.md` - - `CLAUDE.md` - - `DOCS.md` - - `.specify/memory/constitution.md` - - `docs/quickstart.md` -- You may read repository files to improve recommendations and evidence, - but not to expand the scope beyond the allowed observed-only paths. - -## Required Procedure - -1. Start by creating a scratch work directory for downloaded artifacts and intermediate notes. -2. Compute `report_date`, `today_name`, `analyze_day_match`, and `manual_override`. -3. Initialize `runtime_notes[]` and a draft `doctor-report.json` object. - -### Runtime Gate - -Apply gates in this order: - -1. If `observed_findings_present != "true"`: - - write `doctor-report.json` - - set: - - `decision.observed_findings_present = false` - - `decision.qualifying_findings_present = false` - - `issue.action = "none"` - - `issue.reason = "no_observed_findings"` - - do not download artifacts - - do not call safe outputs - - exit successfully -2. If `manual_override` is false and `analyze_day_match` is false: - - write `doctor-report.json` - - set: - - `decision.observed_findings_present = true` - - `decision.qualifying_findings_present = false` - - `issue.action = "skipped"` - - `issue.reason = "not_analyze_day"` - - do not call safe outputs - - exit successfully -3. Otherwise continue to artifact download and analysis. - -## Artifact Download And Validation - -Download artifacts from the current workflow run identified in -`` using the exact artifact names from `collect`: - -- the `stats_artifact_name` value from `` -- the `findings_artifact_name` value from `` -- the predownloaded local files, when present: - - `/tmp/gh-aw/collect-artifacts/stats/doctor-stats.json` - - `/tmp/gh-aw/collect-artifacts/findings/doctor-findings.json` - -Required procedure for artifact access: - -1. First check the predownloaded local files under - `/tmp/gh-aw/collect-artifacts/`. If both required files are present, use - them as the primary source and do not attempt network artifact lookup. -2. If either local file is missing, prefer GitHub MCP workflow run and artifact tools when they are available. -3. If the matching collect artifacts are not listed yet, wait 2 seconds and retry once using the same access path. -4. If workflow artifact MCP tools are unavailable, use authenticated Bash fallback: - - `GH_TOKEN="$GITHUB_TOKEN" gh api ...` - - or `curl -H "Authorization: Bearer $GITHUB_TOKEN" ...` -5. Only use workspace or runner filesystem search as a secondary diagnostic - note after both the predownloaded local files and the authenticated - access paths fail. -6. Do not use unauthenticated `gh api`, unauthenticated `curl`, or raw REST calls without `GITHUB_TOKEN`. - -Expect these files: - -- `doctor-stats.json` -- `doctor-findings.json` - -Validate both artifacts before analysis. Treat any missing file, invalid -JSON, missing required field, wrong schema version, or type mismatch as -`artifact_invalid`. - -Minimum required validation for `doctor-stats.json`: - -- `schema_version == "doctor-stats/v3"` -- `collected_at` -- `report_date` -- `window.from` -- `window.to` -- `repo.full_name` -- `repo.default_branch` -- `workflow.run_id` -- `workflow.run_attempt` -- `workflow.event_name` -- `workflow.actor` -- `source_repo.full_name` -- `source_repo.source_branch` -- `source_repo.source_sha` -- `activity.commits` -- `activity.prs` -- `activity.issues` -- `snapshot.prs` -- `snapshot.issues` - -Minimum required validation for `doctor-findings.json`: - -- `schema_version == "doctor-findings/v4"` -- `collected_at` -- `report_date` -- `repo.full_name` -- `repo.default_branch` -- `source_repo.source_branch` -- `source_repo.source_sha` -- `decision.should_act` -- `decision.act_reason` -- `decision.managed_drift_present` -- `decision.runtime_drift_present` -- `decision.observed_findings_present` -- `findings[]` - -For every analyzed finding, require: - -- `id` -- `category` -- `severity` -- `path` -- `state` -- `auto_action` -- `message` - -If artifact validation fails: - -- write `doctor-report.json` -- set: - - `issue.action = "failed"` - - `issue.reason = "artifact_invalid"` -- add a precise explanation to `runtime_notes[]` -- do not call safe outputs -- exit with failure - -## Analysis Scope - -Analyze only findings from `doctor-findings.json` where: - -- `category == "observed"` -- `auto_action == "analyze"` - -Exclude from issue generation: - -- `managed` -- `runtime` -- `operational` -- observed checks outside the allowed path scope - -Keep `info` findings in `analysis[]`, but they do not qualify for an issue. -Qualifying findings are only severities: - -- `warning` -- `error` - -## Analysis Rules - -For each in-scope observed finding: - -1. Preserve the original `finding_id`, `path`, `severity`, `state`, and `message`. -2. Read the current repository path when it exists and use that only as supporting evidence. -3. Produce one `analysis[]` item with: - - `finding_id` - - `category = "observed"` - - `path` - - `severity` - - `state` - - `qualifies_for_issue` - - `summary` - - `recommendation` - - `evidence[]` - -Use these guidance rules: - -- `AGENTS.md` missing: - - explain that the repo is missing the agent entry point - - recommend restoring the file or a valid symlink in the root -- `CLAUDE.md` missing: - - explain that the repo is missing the Claude-facing entry point - - recommend restoring the file or a valid symlink in the root -- `DOCS.md` missing: - - explain that the repo is missing the main docs entry point in the root - - recommend restoring the file or a valid symlink in the root -- `docs/quickstart.md` missing or placeholder: - - recommend a real first-run or onboarding guide -- `.specify/memory/constitution.md` missing or placeholder: - - recommend restoring and tracking a real working agreement - -When files exist but appear placeholder-like or incomplete, use concrete evidence such as: - -- obvious placeholder markers: `TODO`, `TBD`, `placeholder`, `coming soon`, `lorem ipsum`, `template` -- extremely short content with no actionable project-specific instructions - -Do not create duplicate recommendations for the same path family. Group repeated ideas. - -## Issue Policy - -Deterministic issue title: - -- `Toolkit doctor: observed drift` - -Preferred labels when available: - -- `toolkit` -- `doctor` - -Issue body must contain these sections: - -- `## Summary` -- `## Findings` -- `## Recommendations` -- `## Context` - -Issue body requirements: - -- concise summary of current qualifying warnings and errors -- bullet list or table of qualifying findings with: - - path - - severity - - message -- short grouped recommendations -- link to the `workflow_run_url` value from `` -- short activity context from `doctor-stats.json` only if it clearly helps prioritization - -Use read-only GitHub tools to find an existing open issue with the exact title `Toolkit doctor: observed drift`. -Do not create duplicates. - -Before issue mutation: - -1. Check whether labels `toolkit` and `doctor` exist. -2. If one or both labels are missing: - - continue without the missing labels - - record the problem in `runtime_notes[]` -3. If an existing deterministic issue is locked: - - write `doctor-report.json` - - set: - - `issue.action = "failed"` - - `issue.reason = "issue_locked"` - - do not create a duplicate - - exit with failure - -## Issue Lifecycle - -After analysis, compute: - -- `findings_analyzed` -- `qualifying_findings` -- `warning_count` -- `error_count` -- `qualifying_findings_present` - -Then apply this lifecycle: - -1. If `qualifying_findings_present == false`: - - if an open deterministic issue exists: - - add a resolution comment that observed drift is no longer present in the latest analyze run - - close that issue - - set: - - `issue.action = "closed"` - - `issue.reason = "closed_resolved"` - - otherwise: - - set: - - `issue.action = "none"` - - `issue.reason = "no_qualifying_findings"` -2. If `qualifying_findings_present == true` and `issues_enabled != "true"`: - - perform the full analysis - - do not create, update, close, or comment on issues - - set: - - `issue.action = "skipped"` - - `issue.reason = "issues_disabled"` - - if an existing deterministic issue exists, keep its metadata in the report but do not mutate it -3. If `qualifying_findings_present == true` and no open deterministic issue exists: - - create one issue through `create-issue` - - set: - - `issue.action = "created"` - - `issue.reason = "created_new"` -4. If `qualifying_findings_present == true` and an open deterministic issue exists: - - update that exact issue through `update-issue` - - set: - - `issue.action = "updated"` - - `issue.reason = "updated_existing"` - -Never use direct GitHub write APIs for issues. Safe outputs only. - -## doctor-report.json - -Always write `doctor-report.json` before exiting, including skip and failure paths. - -Write the same final JSON payload to all of these paths: - -- `./doctor-report.json` -- `/tmp/gh-aw/agent/doctor-report.json` -- `/tmp/gh-aw/agent/doctor-report-${report_date}.json` - -This is a temporary workaround until the compiled reusable workflow gets a -dedicated `upload-artifact` step for a `doctor-report-YYYY-MM-DD` artifact. - -Required top-level schema: - -```json -{ - "schema_version": "doctor-report/v1", - "analyzed_at": "RFC3339", - "report_date": "YYYY-MM-DD", - "repo": { - "full_name": "owner/repo" - }, - "workflow": { - "run_id": 0, - "run_attempt": 0, - "event_name": "workflow_dispatch|schedule|...", - "actor": "github-user" - }, - "inputs": { - "stats_artifact_name": "doctor-stats-YYYY-MM-DD", - "findings_artifact_name": "doctor-findings-YYYY-MM-DD" - }, - "decision": { - "observed_findings_present": true, - "issues_enabled": true, - "analyze_day_match": true, - "manual_override": false, - "qualifying_findings_present": true - }, - "issue": { - "action": "created|updated|closed|skipped|none|failed", - "reason": "created_new|updated_existing|closed_resolved|issues_disabled|not_analyze_day|no_observed_findings|no_qualifying_findings|artifact_invalid|model_error|issue_locked", - "number": 0, - "url": "https://github.com/owner/repo/issues/123", - "title": "Toolkit doctor: observed drift" - }, - "summary": { - "findings_analyzed": 0, - "qualifying_findings": 0, - "warning_count": 0, - "error_count": 0 - }, - "runtime_notes": [], - "analysis": [ - { - "finding_id": "observed.docs_quickstart_md.missing", - "category": "observed", - "path": "docs/quickstart.md", - "severity": "warning", - "state": "missing", - "qualifies_for_issue": true, - "summary": "Repository is missing the onboarding quickstart.", - "recommendation": "Add a real quickstart with first-run instructions for contributors.", - "evidence": [ - "doctor-findings.json: observed.docs_quickstart_md.missing", - "docs/quickstart.md is absent in the checked out repository" - ] - } - ] -} -``` - -Populate `issue.number`, `issue.url`, and `issue.title` with `null` when absent. -`analysis[]` must include every analyzed observed finding, including -`info`, with `qualifies_for_issue` set appropriately. - -## Failure Handling - -If you encounter a temporary tool or execution error while downloading -artifacts, reading repository context, or building issue text: - -1. retry once -2. if the retry succeeds, continue -3. if the retry fails, write `doctor-report.json` with: - - `issue.action = "failed"` - - `issue.reason = "model_error"` -4. add a precise note to `runtime_notes[]` -5. exit with failure - -For all failure paths: - -- prefer a valid `doctor-report.json` over incomplete changes -- do not create duplicate issues -- do not mutate repository files - -## Final Checklist - -Before finishing, verify all of the following: - -- `doctor-report.json` exists and is valid JSON -- the mirrored report copies exist in `/tmp/gh-aw/agent/` -- `schema_version == "doctor-report/v1"` -- issue decisions use only the allowed enums -- safe outputs, if any, were used only after artifact validation and only when allowed by runtime gates -- no repository files were modified other than `doctor-report.json` and temporary scratch files diff --git a/.github/workflows/doctor-analyze.prompt.md b/.github/workflows/doctor-analyze.prompt.md deleted file mode 100644 index 0958728..0000000 --- a/.github/workflows/doctor-analyze.prompt.md +++ /dev/null @@ -1,455 +0,0 @@ -# Doctor Analyze - -## TL;DR - -Read-only analyze job for the `doctor` workflow. Downloads `collect` artifacts, -validates findings, and manages a deterministic GitHub issue for observed drift. -Writes `doctor-report.json` as the only persistent output. - -You are the `analyze` job for the repository described in the `` block above. -This workflow is called only from `doctor.yml` and must stay read-only for repository files. -Never create PRs. Never edit tracked repository files. The only persistent outputs you may write are: - -- `doctor-report.json` in the workspace root -- mirrored copies of the same report under `/tmp/gh-aw/agent/` so the - current compiled workflow uploads them via generic agent artifacts - -Temporary scratch files are allowed only if they are needed to build or validate the report. - -## Runtime Context - -Treat the `` block from the system prompt as the runtime contract from `collect`. -It must provide these keys: - -- `issues_enabled` -- `observed_findings_present` -- `stats_artifact_name` -- `findings_artifact_name` -- `source_sha` -- `installed_source_sha` -- `installed_runtime_sha` -- `analyze_day` -- `report_tz` -- `force_analyze` -- `run_id` -- `actor` -- `workflow_run_url` - -Read `run_attempt` from env var `GITHUB_RUN_ATTEMPT` via Bash. -Read `event_name` from env var `GITHUB_EVENT_NAME` via Bash. -If the `` block is missing any required key, record -that in `runtime_notes[]`, write `doctor-report.json` with -`issue.reason = "model_error"`, and exit with failure. - -Use `report_tz` to derive: - -- `report_date` in `YYYY-MM-DD` -- `today_name` as a lowercase English weekday name -- `analyze_day_match = (today_name == analyze_day.lower())` -- `manual_override = (force_analyze == true)` - -## Operating Rules - -- Use GitHub MCP tools only for read operations: artifacts, issues, labels, workflow metadata, repository contents. -- Use safe outputs only for issue mutations: `create-issue`, `update-issue`, `close-issue`, `add-comment`. -- Never perform direct write mutations through bash, git, or raw GitHub API calls. -- Prefer GitHub MCP tools for workflow runs, artifacts, issues, and labels. -- If workflow artifact MCP tools are unavailable in the exposed tool list, - you may use `Bash` with authenticated GitHub API calls for artifact lookup - and download only. -- Never use unauthenticated `gh` or unauthenticated `curl` for GitHub API access. -- For authenticated fallback in Bash, export - `GH_TOKEN="$GITHUB_TOKEN"` before `gh api`, or use `curl` with header - `Authorization: Bearer $GITHUB_TOKEN`. -- `collect` is the source of truth for findings and severities. Do not invent new finding IDs or new finding categories. -- Limit issue-generating analysis to findings where: - - `category == observed` - - `auto_action == analyze` - - `path` is one of: - - `AGENTS.md` - - `CLAUDE.md` - - `DOCS.md` - - `.specify/memory/constitution.md` - - `docs/quickstart.md` -- You may read repository files to improve recommendations and evidence, - but not to expand the scope beyond the allowed observed-only paths. - -## Required Procedure - -1. Start by creating a scratch work directory for downloaded artifacts and intermediate notes. -2. Compute `report_date`, `today_name`, `analyze_day_match`, and `manual_override`. -3. Initialize `runtime_notes[]` and a draft `doctor-report.json` object. - -### Runtime Gate - -Apply gates in this order: - -1. If `observed_findings_present != "true"`: - - write `doctor-report.json` - - set: - - `decision.observed_findings_present = false` - - `decision.qualifying_findings_present = false` - - `issue.action = "none"` - - `issue.reason = "no_observed_findings"` - - do not download artifacts - - do not call safe outputs - - exit successfully -2. If `manual_override` is false and `analyze_day_match` is false: - - write `doctor-report.json` - - set: - - `decision.observed_findings_present = true` - - `decision.qualifying_findings_present = false` - - `issue.action = "skipped"` - - `issue.reason = "not_analyze_day"` - - do not call safe outputs - - exit successfully -3. Otherwise continue to artifact download and analysis. - -## Artifact Download And Validation - -Download artifacts from the current workflow run identified in -`` using the exact artifact names from `collect`: - -- the `stats_artifact_name` value from `` -- the `findings_artifact_name` value from `` -- the predownloaded local files, when present: - - `/tmp/gh-aw/collect-artifacts/stats/doctor-stats.json` - - `/tmp/gh-aw/collect-artifacts/findings/doctor-findings.json` - -Required procedure for artifact access: - -1. First check the predownloaded local files under - `/tmp/gh-aw/collect-artifacts/`. If both required files are present, use - them as the primary source and do not attempt network artifact lookup. -2. If either local file is missing, prefer GitHub MCP workflow run and artifact tools when they are available. -3. If the matching collect artifacts are not listed yet, wait 2 seconds and retry once using the same access path. -4. If workflow artifact MCP tools are unavailable, use authenticated Bash fallback: - - `GH_TOKEN="$GITHUB_TOKEN" gh api ...` - - or `curl -H "Authorization: Bearer $GITHUB_TOKEN" ...` -5. Only use workspace or runner filesystem search as a secondary diagnostic - note after both the predownloaded local files and the authenticated - access paths fail. -6. Do not use unauthenticated `gh api`, unauthenticated `curl`, or raw REST calls without `GITHUB_TOKEN`. - -Expect these files: - -- `doctor-stats.json` -- `doctor-findings.json` - -Validate both artifacts before analysis. Treat any missing file, invalid -JSON, missing required field, wrong schema version, or type mismatch as -`artifact_invalid`. - -Minimum required validation for `doctor-stats.json`: - -- `schema_version == "doctor-stats/v3"` -- `collected_at` -- `report_date` -- `window.from` -- `window.to` -- `repo.full_name` -- `repo.default_branch` -- `workflow.run_id` -- `workflow.run_attempt` -- `workflow.event_name` -- `workflow.actor` -- `source_repo.full_name` -- `source_repo.source_branch` -- `source_repo.source_sha` -- `activity.commits` -- `activity.prs` -- `activity.issues` -- `snapshot.prs` -- `snapshot.issues` - -Minimum required validation for `doctor-findings.json`: - -- `schema_version == "doctor-findings/v4"` -- `collected_at` -- `report_date` -- `repo.full_name` -- `repo.default_branch` -- `source_repo.source_branch` -- `source_repo.source_sha` -- `decision.should_act` -- `decision.act_reason` -- `decision.managed_drift_present` -- `decision.runtime_drift_present` -- `decision.observed_findings_present` -- `findings[]` - -For every analyzed finding, require: - -- `id` -- `category` -- `severity` -- `path` -- `state` -- `auto_action` -- `message` - -If artifact validation fails: - -- write `doctor-report.json` -- set: - - `issue.action = "failed"` - - `issue.reason = "artifact_invalid"` -- add a precise explanation to `runtime_notes[]` -- do not call safe outputs -- exit with failure - -## Analysis Scope - -Analyze only findings from `doctor-findings.json` where: - -- `category == "observed"` -- `auto_action == "analyze"` - -Exclude from issue generation: - -- `managed` -- `runtime` -- `operational` -- observed checks outside the allowed path scope - -Keep `info` findings in `analysis[]`, but they do not qualify for an issue. -Qualifying findings are only severities: - -- `warning` -- `error` - -## Analysis Rules - -For each in-scope observed finding: - -1. Preserve the original `finding_id`, `path`, `severity`, `state`, and `message`. -2. Read the current repository path when it exists and use that only as supporting evidence. -3. Produce one `analysis[]` item with: - - `finding_id` - - `category = "observed"` - - `path` - - `severity` - - `state` - - `qualifies_for_issue` - - `summary` - - `recommendation` - - `evidence[]` - -Use these guidance rules: - -- `AGENTS.md` missing: - - explain that the repo is missing the agent entry point - - recommend restoring the file or a valid symlink in the root -- `CLAUDE.md` missing: - - explain that the repo is missing the Claude-facing entry point - - recommend restoring the file or a valid symlink in the root -- `DOCS.md` missing: - - explain that the repo is missing the main docs entry point in the root - - recommend restoring the file or a valid symlink in the root -- `docs/quickstart.md` missing or placeholder: - - recommend a real first-run or onboarding guide -- `.specify/memory/constitution.md` missing or placeholder: - - recommend restoring and tracking a real working agreement - -When files exist but appear placeholder-like or incomplete, use concrete evidence such as: - -- obvious placeholder markers: `TODO`, `TBD`, `placeholder`, `coming soon`, `lorem ipsum`, `template` -- extremely short content with no actionable project-specific instructions - -Do not create duplicate recommendations for the same path family. Group repeated ideas. - -## Issue Policy - -Deterministic issue title: - -- `Toolkit doctor: observed drift` - -Preferred labels when available: - -- `toolkit` -- `doctor` - -Issue body must contain these sections: - -- `## Summary` -- `## Findings` -- `## Recommendations` -- `## Context` - -Issue body requirements: - -- concise summary of current qualifying warnings and errors -- bullet list or table of qualifying findings with: - - path - - severity - - message -- short grouped recommendations -- link to the `workflow_run_url` value from `` -- short activity context from `doctor-stats.json` only if it clearly helps prioritization - -Use read-only GitHub tools to find an existing open issue with the exact title `Toolkit doctor: observed drift`. -Do not create duplicates. - -Before issue mutation: - -1. Check whether labels `toolkit` and `doctor` exist. -2. If one or both labels are missing: - - continue without the missing labels - - record the problem in `runtime_notes[]` -3. If an existing deterministic issue is locked: - - write `doctor-report.json` - - set: - - `issue.action = "failed"` - - `issue.reason = "issue_locked"` - - do not create a duplicate - - exit with failure - -## Issue Lifecycle - -After analysis, compute: - -- `findings_analyzed` -- `qualifying_findings` -- `warning_count` -- `error_count` -- `qualifying_findings_present` - -Then apply this lifecycle: - -1. If `qualifying_findings_present == false`: - - if an open deterministic issue exists: - - add a resolution comment that observed drift is no longer present in the latest analyze run - - close that issue - - set: - - `issue.action = "closed"` - - `issue.reason = "closed_resolved"` - - otherwise: - - set: - - `issue.action = "none"` - - `issue.reason = "no_qualifying_findings"` -2. If `qualifying_findings_present == true` and `issues_enabled != "true"`: - - perform the full analysis - - do not create, update, close, or comment on issues - - set: - - `issue.action = "skipped"` - - `issue.reason = "issues_disabled"` - - if an existing deterministic issue exists, keep its metadata in the report but do not mutate it -3. If `qualifying_findings_present == true` and no open deterministic issue exists: - - create one issue through `create-issue` - - set: - - `issue.action = "created"` - - `issue.reason = "created_new"` -4. If `qualifying_findings_present == true` and an open deterministic issue exists: - - update that exact issue through `update-issue` - - set: - - `issue.action = "updated"` - - `issue.reason = "updated_existing"` - -Never use direct GitHub write APIs for issues. Safe outputs only. - -## doctor-report.json - -Always write `doctor-report.json` before exiting, including skip and failure paths. - -Write the same final JSON payload to all of these paths: - -- `./doctor-report.json` -- `/tmp/gh-aw/agent/doctor-report.json` -- `/tmp/gh-aw/agent/doctor-report-${report_date}.json` - -This is a temporary workaround until the compiled reusable workflow gets a -dedicated `upload-artifact` step for a `doctor-report-YYYY-MM-DD` artifact. - -Required top-level schema: - -```json -{ - "schema_version": "doctor-report/v1", - "analyzed_at": "RFC3339", - "report_date": "YYYY-MM-DD", - "repo": { - "full_name": "owner/repo" - }, - "workflow": { - "run_id": 0, - "run_attempt": 0, - "event_name": "workflow_dispatch|schedule|...", - "actor": "github-user" - }, - "inputs": { - "stats_artifact_name": "doctor-stats-YYYY-MM-DD", - "findings_artifact_name": "doctor-findings-YYYY-MM-DD" - }, - "decision": { - "observed_findings_present": true, - "issues_enabled": true, - "analyze_day_match": true, - "manual_override": false, - "qualifying_findings_present": true - }, - "issue": { - "action": "created|updated|closed|skipped|none|failed", - "reason": "created_new|updated_existing|closed_resolved|issues_disabled|not_analyze_day|no_observed_findings|no_qualifying_findings|artifact_invalid|model_error|issue_locked", - "number": 0, - "url": "https://github.com/owner/repo/issues/123", - "title": "Toolkit doctor: observed drift" - }, - "summary": { - "findings_analyzed": 0, - "qualifying_findings": 0, - "warning_count": 0, - "error_count": 0 - }, - "runtime_notes": [], - "analysis": [ - { - "finding_id": "observed.docs_quickstart_md.missing", - "category": "observed", - "path": "docs/quickstart.md", - "severity": "warning", - "state": "missing", - "qualifies_for_issue": true, - "summary": "Repository is missing the onboarding quickstart.", - "recommendation": "Add a real quickstart with first-run instructions for contributors.", - "evidence": [ - "doctor-findings.json: observed.docs_quickstart_md.missing", - "docs/quickstart.md is absent in the checked out repository" - ] - } - ] -} -``` - -Populate `issue.number`, `issue.url`, and `issue.title` with `null` when absent. -`analysis[]` must include every analyzed observed finding, including -`info`, with `qualifies_for_issue` set appropriately. - -## Failure Handling - -If you encounter a temporary tool or execution error while downloading -artifacts, reading repository context, or building issue text: - -1. retry once -2. if the retry succeeds, continue -3. if the retry fails, write `doctor-report.json` with: - - `issue.action = "failed"` - - `issue.reason = "model_error"` -4. add a precise note to `runtime_notes[]` -5. exit with failure - -For all failure paths: - -- prefer a valid `doctor-report.json` over incomplete changes -- do not create duplicate issues -- do not mutate repository files - -## Final Checklist - -Before finishing, verify all of the following: - -- `doctor-report.json` exists and is valid JSON -- the mirrored report copies exist in `/tmp/gh-aw/agent/` -- `schema_version == "doctor-report/v1"` -- issue decisions use only the allowed enums -- safe outputs, if any, were used only after artifact validation and only when allowed by runtime gates -- no repository files were modified other than `doctor-report.json` and temporary scratch files diff --git a/.github/workflows/doctor.yml b/.github/workflows/doctor.yml deleted file mode 100644 index f5b0a69..0000000 --- a/.github/workflows/doctor.yml +++ /dev/null @@ -1,320 +0,0 @@ -name: doctor - -on: - schedule: - - cron: '0 2 * * *' - workflow_dispatch: - inputs: - force_analyze: - description: Force analyze outside configured analyze day - required: false - type: boolean - default: false - -permissions: - contents: read - issues: read - pull-requests: read - actions: read - -env: - SOURCE_REPO: G-Core/agent-toolkit - REPORT_TZ: UTC - PYTHON_VERSION: '3.12' - ANALYZE_DAY: monday - -jobs: - collect: - runs-on: ubuntu-latest - outputs: - should_act: ${{ steps.collect.outputs.should_act }} - source_sha: ${{ steps.collect.outputs.source_sha }} - installed_source_sha: ${{ steps.collect.outputs.installed_source_sha }} - installed_runtime_sha: ${{ steps.collect.outputs.installed_runtime_sha }} - act_reason: ${{ steps.collect.outputs.act_reason }} - analyze_day: ${{ steps.collect.outputs.analyze_day }} - report_tz: ${{ steps.collect.outputs.report_tz }} - issues_enabled: ${{ steps.collect.outputs.issues_enabled }} - observed_findings_present: ${{ steps.collect.outputs.observed_findings_present }} - stats_artifact_name: ${{ steps.collect.outputs.stats_artifact_name }} - findings_artifact_name: ${{ steps.collect.outputs.findings_artifact_name }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: ${{ env.PYTHON_VERSION }} - - - name: Collect runtime inputs from GitHub API - id: collect_inputs - uses: actions/github-script@v8 - env: - SOURCE_REPO: ${{ env.SOURCE_REPO }} - SOURCE_GITHUB_TOKEN: ${{ secrets.TOOLKIT_READ_TOKEN || secrets.GITHUB_TOKEN }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const fs = require("fs"); - const path = require("path"); - - const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/"); - const repoMeta = await github.rest.repos.get({ owner, repo }); - const repoDefaultBranch = repoMeta.data.default_branch; - const issuesEnabled = repoMeta.data.has_issues ? "true" : "false"; - - const now = new Date(); - const reportDate = now.toISOString().slice(0, 10); - const reportDateStart = new Date(`${reportDate}T00:00:00Z`); - const windowTo = reportDateStart.toISOString(); - const windowFrom = new Date(reportDateStart.getTime() - 24 * 60 * 60 * 1000).toISOString(); - const collectedAt = now.toISOString(); - - const commits = await github.paginate(github.rest.repos.listCommits, { - owner, - repo, - since: windowFrom, - until: windowTo, - per_page: 100, - }); - const dailyCommits = commits.map((item) => ({ - sha: item.sha, - author: item.author?.login || item.commit?.author?.name || "unknown", - authored_at: item.commit?.author?.date || null, - message: item.commit?.message || "", - })); - - const pullsAll = await github.paginate(github.rest.pulls.list, { - owner, - repo, - state: "all", - sort: "updated", - direction: "desc", - per_page: 100, - }); - const inWindow = (value) => { - if (!value) { - return false; - } - return value >= windowFrom && value < windowTo; - }; - const mapPull = (item) => ({ - number: item.number, - author: item.user?.login || "unknown", - title: item.title || "", - state: item.state || "open", - created_at: item.created_at, - merged_at: item.merged_at, - closed_at: item.closed_at, - labels: (item.labels || []).map((label) => label.name), - assignees: (item.assignees || []).map((assignee) => assignee.login), - }); - const dailyPRs = pullsAll - .filter((item) => inWindow(item.created_at) || inWindow(item.merged_at) || inWindow(item.closed_at)) - .map(mapPull); - - const issuesAll = await github.paginate(github.rest.issues.listForRepo, { - owner, - repo, - state: "all", - since: windowFrom, - per_page: 100, - }); - const isPlainIssue = (item) => !item.pull_request; - const mapIssue = (item) => ({ - number: item.number, - author: item.user?.login || "unknown", - title: item.title || "", - state: item.state || "open", - created_at: item.created_at, - closed_at: item.closed_at, - labels: (item.labels || []).map((label) => - typeof label === "string" ? label : label.name - ), - assignees: (item.assignees || []).map((assignee) => assignee.login), - }); - const dailyIssues = issuesAll - .filter((item) => isPlainIssue(item) && (inWindow(item.created_at) || inWindow(item.closed_at))) - .map(mapIssue); - - const pullsOpen = await github.paginate(github.rest.pulls.list, { - owner, - repo, - state: "open", - per_page: 100, - }); - const snapshotPRs = pullsOpen.map((item) => ({ - number: item.number, - author: item.user?.login || "unknown", - title: item.title || "", - created_at: item.created_at, - days_open: Math.floor((Date.now() - Date.parse(item.created_at)) / 86400000), - labels: (item.labels || []).map((label) => label.name), - assignees: (item.assignees || []).map((assignee) => assignee.login), - })); - - const issuesOpen = await github.paginate(github.rest.issues.listForRepo, { - owner, - repo, - state: "open", - per_page: 100, - }); - const snapshotIssues = issuesOpen - .filter(isPlainIssue) - .map((item) => ({ - number: item.number, - author: item.user?.login || "unknown", - title: item.title || "", - created_at: item.created_at, - assignees: (item.assignees || []).map((assignee) => assignee.login), - labels: (item.labels || []).map((label) => - typeof label === "string" ? label : label.name - ), - })); - - const activityPayload = { - commits: dailyCommits, - prs: dailyPRs, - issues: dailyIssues, - snapshot_prs: snapshotPRs, - snapshot_issues: snapshotIssues, - }; - - const workDir = path.join(process.env.RUNNER_TEMP, "doctor-inputs"); - fs.mkdirSync(workDir, { recursive: true }); - const activityPath = path.join(workDir, "activity.json"); - fs.writeFileSync(activityPath, JSON.stringify(activityPayload)); - - core.setOutput("activity_path", activityPath); - core.setOutput("repo_default_branch", repoDefaultBranch); - core.setOutput("issues_enabled", issuesEnabled); - core.setOutput("collected_at", collectedAt); - core.setOutput("report_date", reportDate); - core.setOutput("window_from", windowFrom); - core.setOutput("window_to", windowTo); - - - name: Checkout toolkit source - uses: actions/checkout@v4 - with: - repository: ${{ env.SOURCE_REPO }} - ref: doctor-v1 - path: .doctor-source - token: ${{ secrets.TOOLKIT_READ_TOKEN || secrets.GITHUB_TOKEN }} - - - name: Run collect - id: collect - env: - DOCTOR_REPO_ROOT: ${{ github.workspace }} - DOCTOR_OUTPUT_DIR: ${{ runner.temp }}/doctor - DOCTOR_SOURCE_ROOT: ${{ github.workspace }}/.doctor-source - DOCTOR_ACTIVITY_PATH: ${{ steps.collect_inputs.outputs.activity_path }} - DOCTOR_ISSUES_ENABLED: ${{ steps.collect_inputs.outputs.issues_enabled }} - DOCTOR_REPO_FULL_NAME: ${{ github.repository }} - DOCTOR_REPO_DEFAULT_BRANCH: ${{ steps.collect_inputs.outputs.repo_default_branch }} - DOCTOR_SOURCE_REPO: ${{ env.SOURCE_REPO }} - DOCTOR_SOURCE_BRANCH: doctor-v1 - DOCTOR_COLLECTED_AT: ${{ steps.collect_inputs.outputs.collected_at }} - DOCTOR_REPORT_DATE: ${{ steps.collect_inputs.outputs.report_date }} - DOCTOR_WINDOW_FROM: ${{ steps.collect_inputs.outputs.window_from }} - DOCTOR_WINDOW_TO: ${{ steps.collect_inputs.outputs.window_to }} - DOCTOR_ANALYZE_DAY: ${{ env.ANALYZE_DAY }} - DOCTOR_REPORT_TZ: ${{ env.REPORT_TZ }} - run: python .doctor-source/workflows/runtime/collect.py - - - name: Upload doctor-stats artifact - if: ${{ always() }} - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.collect.outputs.stats_artifact_name }} - path: ${{ runner.temp }}/doctor/doctor-stats.json - if-no-files-found: error - - - name: Upload doctor-findings artifact - if: ${{ always() }} - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.collect.outputs.findings_artifact_name }} - path: ${{ runner.temp }}/doctor/doctor-findings.json - if-no-files-found: error - - act: - needs: collect - if: ${{ needs.collect.outputs.should_act == 'true' }} - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - actions: read - steps: - - name: Checkout target repository - uses: actions/checkout@v4 - with: - ref: ${{ github.event.repository.default_branch }} - - - name: Download doctor-findings artifact - uses: actions/download-artifact@v4 - with: - name: ${{ needs.collect.outputs.findings_artifact_name }} - path: ${{ runner.temp }}/doctor-findings - - - name: Checkout toolkit source - uses: actions/checkout@v4 - with: - repository: ${{ env.SOURCE_REPO }} - ref: doctor-v1 - path: .doctor-source - token: ${{ secrets.TOOLKIT_READ_TOKEN || secrets.GITHUB_TOKEN }} - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: ${{ env.PYTHON_VERSION }} - - - name: Run act - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCTOR_REPO_ROOT: ${{ github.workspace }} - DOCTOR_SOURCE_ROOT: ${{ github.workspace }}/.doctor-source - DOCTOR_FINDINGS_PATH: ${{ runner.temp }}/doctor-findings/doctor-findings.json - DOCTOR_SOURCE_SHA: ${{ needs.collect.outputs.source_sha }} - DOCTOR_INSTALLED_SOURCE_SHA: ${{ needs.collect.outputs.installed_source_sha }} - DOCTOR_INSTALLED_RUNTIME_SHA: ${{ needs.collect.outputs.installed_runtime_sha }} - DOCTOR_ACT_REASON: ${{ needs.collect.outputs.act_reason }} - DOCTOR_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - DOCTOR_SOURCE_REPO: ${{ env.SOURCE_REPO }} - DOCTOR_WORKFLOW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - run: python .doctor-source/workflows/act.py - - analyze: - needs: - - collect - - act - if: >- - ${{ - always() && - needs.collect.result == 'success' && - (needs.act.result == 'success' || needs.act.result == 'skipped') - }} - # Required for reusable gh-aw analyze with safe outputs. GitHub validates - # the caller permission envelope before analyze starts; the current - # compiled lock also requests discussions: write. - permissions: - actions: read - contents: read - issues: write - pull-requests: write - discussions: write - uses: G-Core/agent-toolkit/.github/workflows/doctor-analyze.lock.yml@doctor-v1 - secrets: inherit - with: - force_analyze: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.force_analyze == 'true' }} - analyze_day: ${{ needs.collect.outputs.analyze_day }} - report_tz: ${{ needs.collect.outputs.report_tz }} - issues_enabled: ${{ needs.collect.outputs.issues_enabled }} - observed_findings_present: ${{ needs.collect.outputs.observed_findings_present }} - stats_artifact_name: ${{ needs.collect.outputs.stats_artifact_name }} - findings_artifact_name: ${{ needs.collect.outputs.findings_artifact_name }} - source_sha: ${{ needs.collect.outputs.source_sha }} - installed_source_sha: ${{ needs.collect.outputs.installed_source_sha }} - installed_runtime_sha: ${{ needs.collect.outputs.installed_runtime_sha }} From 5c6a11be0580a1479f812bcc3d633f8b95064a0e Mon Sep 17 00:00:00 2001 From: Gordon Farquharson Date: Wed, 8 Apr 2026 15:35:21 +0100 Subject: [PATCH 5/8] esbuild break --- package.json | 2 +- pnpm-lock.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 03101a1..4dda764 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,6 @@ "babel-jest": "^30.3.0", "babel-plugin-transform-import-meta": "^2.3.3", "conventional-changelog-eslint": "^5.0.0", - "esbuild": "^0.28.0", "esbuild-plugin-polyfill-node": "^0.3.0", "eslint": "^10.2.0", "eslint-plugin-import-x": "^4.16.2", @@ -92,6 +91,7 @@ "enquirer": "^2.4.1", "event-target-polyfill": "^0.0.4", "magic-string": "^0.30.19", + "esbuild": "^0.28.0", "npm-run-all": "^4.1.5", "prompts": "^2.4.2", "regexpu-core": "^5.3.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 49432c5..cb0616e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: enquirer: specifier: ^2.4.1 version: 2.4.1 + esbuild: + specifier: ^0.28.0 + version: 0.28.0 event-target-polyfill: specifier: ^0.0.4 version: 0.0.4 @@ -81,9 +84,6 @@ importers: conventional-changelog-eslint: specifier: ^5.0.0 version: 5.0.0 - esbuild: - specifier: ^0.28.0 - version: 0.28.0 esbuild-plugin-polyfill-node: specifier: ^0.3.0 version: 0.3.0(esbuild@0.28.0) From c08c830e73d6cdedbb55702a427dd3e4227bbd01 Mon Sep 17 00:00:00 2001 From: Gordon Farquharson Date: Wed, 8 Apr 2026 15:41:09 +0100 Subject: [PATCH 6/8] fix: :bug: esbuild installed incorrectly moved esbuild back to dependencies - required at runtime --- src/utils/syntax-checker.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utils/syntax-checker.ts b/src/utils/syntax-checker.ts index a4d25cf..3efe5ae 100644 --- a/src/utils/syntax-checker.ts +++ b/src/utils/syntax-checker.ts @@ -63,8 +63,9 @@ function containsTypeScriptSyntaxErrors(tsInput: string, tsConfigPath?: string): ? [] : ['--types', './node_modules/@gcoredev/fastedge-sdk-js']; - // moduleResolution 'node' (node10) is deprecated since TS 5.0; - // --ignoreDeprecations is only supported in TS >= 5 + // ! This needs future work - moduleResolution 'node' (node10) is deprecated since TS 5.0; + // ! --ignoreDeprecations is only supported in TS >= 5 + const ignoreDeprecationsFlags = tsMajor >= 5 ? ['--ignoreDeprecations', tsMajor >= 6 ? '6.0' : '5.0'] : []; From e883bdf70ca1185bca8529295927a95800a262db Mon Sep 17 00:00:00 2001 From: Gordon Farquharson Date: Thu, 9 Apr 2026 07:56:35 +0100 Subject: [PATCH 7/8] update manifest naming convention --- context/CONTEXT_INDEX.md | 8 ++++ context/ENHANCEMENTS.md | 53 ++++++++++++++++++++++++ context/PLUGIN_CONTRACT.md | 60 ++++++++++++++++++++++++++++ fastedge-plugin-source/manifest.json | 24 +++++------ 4 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 context/ENHANCEMENTS.md create mode 100644 context/PLUGIN_CONTRACT.md diff --git a/context/CONTEXT_INDEX.md b/context/CONTEXT_INDEX.md index eed715f..8b0cab8 100644 --- a/context/CONTEXT_INDEX.md +++ b/context/CONTEXT_INDEX.md @@ -36,6 +36,13 @@ |----------|-------|---------| | `PROJECT_OVERVIEW.md` | ~150 | Lightweight project overview — architecture, key modules, dev setup, common commands. Read when new to the codebase. | | `CHANGELOG.md` | ~25+ | Change history. Use grep, don't read linearly as this file grows. | +| `ENHANCEMENTS.md` | ~50 | Known inconsistencies and planned improvements. Read before refactoring related areas. | + +### Plugin Integration (read when modifying manifest or examples) + +| Document | Lines | Purpose | +|----------|-------|---------| +| `PLUGIN_CONTRACT.md` | ~70 | Naming conventions, manifest rules, intent file matching for the fastedge-plugin sync pipeline. Read when adding examples to `manifest.json` or changing `fastedge-plugin-source/`. | ### External (not in context/) @@ -83,6 +90,7 @@ 4. **Every example MUST have its own `README.md`** explaining what it does 5. **Every example MUST have an entry in `examples/README.md`** (the top-level index) 6. **Terminology**: In READMEs, always refer to "environment variables" — never "dictionary variables". `dictionary` is the internal package name for accessing environment variables, not a user-facing concept +7. **Plugin sync**: If this example should feed into fastedge-plugin, read `context/PLUGIN_CONTRACT.md` for manifest and naming conventions ### Changing the Build System 1. Read `development/BUILD_SYSTEM.md` diff --git a/context/ENHANCEMENTS.md b/context/ENHANCEMENTS.md new file mode 100644 index 0000000..de91a0c --- /dev/null +++ b/context/ENHANCEMENTS.md @@ -0,0 +1,53 @@ +# Enhancements & Known Issues + +Tracked improvements that don't warrant external issues. Check items off or remove them as they're resolved. + +--- + +## Config Schema: `ignoreDirs` vs `ignorePaths` inconsistency + +**Status:** Open +**Identified:** 2026-04-08 (during plugin reference doc review) +**Affects:** `fastedge-init` scaffolder, `fastedge-build` static pipeline + +### Problem + +The init wizard (`src/cli/fastedge-init/create-config.ts`) generates static build configs using `ignoreDirs`: + +```js +// What fastedge-init writes to .fastedge/build-config.js +{ + type: "static", + ignoreDirs: ["./node_modules"] +} +``` + +But the formal `AssetCacheConfig` type (`src/server/static-assets/asset-manifest/types.ts`) defines `ignorePaths` and `assetManifestPath`: + +```ts +interface AssetCacheConfig { + assetManifestPath: string; + ignorePaths: string[]; + // ... +} +``` + +The build pipeline silently accepts both — `create-manifest-file-map.ts` merges `ignoreDirs` and `ignorePaths` into one array. But this means: + +1. Configs generated by `fastedge-init` use a field name (`ignoreDirs`) not present in the formal type +2. `assetManifestPath` is required in `AssetCacheConfig` but never emitted by `fastedge-init` +3. Docs for each tool are accurate to their respective source, but contradict each other + +### Suggested Fix + +Either: +- **Option A:** Update `create-config.ts` to emit `ignorePaths` + `assetManifestPath` (align init output with the formal type) +- **Option B:** Add `ignoreDirs` as an explicit field in `AssetCacheConfig` and make `assetManifestPath` optional + +Option A is cleaner — one canonical field name, init output matches the type system. + +### Files Involved + +- `src/cli/fastedge-init/create-config.ts` — generates the config (uses `ignoreDirs`) +- `src/server/static-assets/asset-manifest/types.ts` — defines `AssetCacheConfig` (uses `ignorePaths`) +- `src/server/static-assets/asset-manifest/create-manifest-file-map.ts` — consumes both (merges them) diff --git a/context/PLUGIN_CONTRACT.md b/context/PLUGIN_CONTRACT.md new file mode 100644 index 0000000..6d76c3e --- /dev/null +++ b/context/PLUGIN_CONTRACT.md @@ -0,0 +1,60 @@ +# Plugin Source Contract — Naming Conventions + +This document describes the naming and structure conventions for `manifest.json` in this repo. These rules ensure the sync-reference-docs pipeline correctly maps source files to plugin reference docs and intent skills. + +## Reference File Structure + +Reference files in the plugin repo are organized by app_type: + +``` +plugins/gcore-fastedge/skills/ + scaffold/reference/ + http/ # HTTP app blueprints + base-ts.md # Base skeleton + kv-store-ts.md # Feature blueprint + cdn/ # CDN app blueprints (future) + build-cli.md # Cross-cutting (no subfolder) + fastedge-docs/reference/ + http/ # HTTP app example patterns + examples-kv-store-js.md + cdn/ # CDN app example patterns (future) + sdk-reference-js.md # Cross-cutting (no subfolder) +``` + +## File Naming Convention + +**`{concept}-{lang}.md`** — concept first, language last. The subfolder provides the app_type context. + +| Type | Pattern | Example | +|---|---|---| +| Base skeleton | `{appType}/base-{lang}.md` | `http/base-ts.md` | +| Feature blueprint | `{appType}/{concept}-{lang}.md` | `http/kv-store-ts.md` | +| Docs pattern | `{appType}/examples-{concept}-{lang}.md` | `http/examples-kv-store-js.md` | +| Cross-cutting SDK ref | `sdk-reference-{lang}.md` | `sdk-reference-js.md` | + +## Manifest target_mapping Rules + +1. **reference_file** paths must include the `http/` or `cdn/` subfolder for app_type-specific content +2. **section** should be `null` for all entries (each file is owned by one repo — no splicing) +3. **Dual-intent pattern**: each example gets two entries with the same `files` array: + - `{name}-blueprint` → `scaffold/reference/{appType}/{concept}-{lang}.md` + - `{name}-pattern` → `fastedge-docs/reference/{appType}/examples-{concept}-{lang}.md` + +## Intent File Matching + +The pipeline resolves intent files by extracting the path suffix after `reference/` from the `reference_file` path. It looks for that same relative path inside the plugin's intent directory for this repo. + +Example: +- `reference_file`: `plugins/.../scaffold/reference/http/kv-store-ts.md` +- Path suffix: `http/kv-store-ts.md` +- Intent lookup: `agent-intent-skills/fastedge-sdk-js/http/kv-store-ts.md` + +## When Adding New Examples + +1. Add source entries (paired `-blueprint` and `-pattern`) to `manifest.json` +2. Add target_mapping entries pointing to `{appType}/{concept}-{lang}.md` paths +3. Request intent files be created in `fastedge-plugin` repo (or create via PR): + - `agent-intent-skills/fastedge-sdk-js/{appType}/{concept}-{lang}.md` (scaffold) + - `agent-intent-skills/fastedge-sdk-js/{appType}/examples-{concept}-{lang}.md` (docs) + - Each should reference `../_scaffold-blueprint-base.md` or `../_docs-pattern-base.md` +4. Create placeholder reference files at the target paths in the plugin repo diff --git a/fastedge-plugin-source/manifest.json b/fastedge-plugin-source/manifest.json index e648495..8226c75 100644 --- a/fastedge-plugin-source/manifest.json +++ b/fastedge-plugin-source/manifest.json @@ -140,7 +140,7 @@ }, "target_mapping": { "sdk-api": { - "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/sdk-reference.md", + "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/sdk-reference-js.md", "section": null }, "build-cli": { @@ -161,52 +161,52 @@ }, "hello-world-blueprint": { - "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/base-http-ts.md", + "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/http/base-ts.md", "section": null }, "kv-store-blueprint": { - "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/http-ts-kv-store.md", + "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/http/kv-store-ts.md", "section": null }, "kv-store-pattern": { - "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/examples-kv-store.md", + "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-kv-store-js.md", "section": null }, "ab-testing-blueprint": { - "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/http-ts-ab-testing.md", + "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/http/ab-testing-ts.md", "section": null }, "ab-testing-pattern": { - "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/examples-ab-testing.md", + "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-ab-testing-js.md", "section": null }, "fetch-blueprint": { - "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/http-ts-fetch.md", + "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/http/fetch-ts.md", "section": null }, "fetch-pattern": { - "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/examples-fetch.md", + "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-fetch-js.md", "section": null }, "headers-blueprint": { - "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/http-ts-headers.md", + "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/http/headers-ts.md", "section": null }, "headers-pattern": { - "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/examples-headers.md", + "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-headers-js.md", "section": null }, "geo-redirect-blueprint": { - "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/http-ts-geo-redirect.md", + "reference_file": "plugins/gcore-fastedge/skills/scaffold/reference/http/geo-redirect-ts.md", "section": null }, "geo-redirect-pattern": { - "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/examples-geo-redirect.md", + "reference_file": "plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-geo-redirect-js.md", "section": null } }, From 8c599a450a7a34098bc7970407c1842e27312b8f Mon Sep 17 00:00:00 2001 From: Gordon Farquharson Date: Thu, 9 Apr 2026 09:34:51 +0100 Subject: [PATCH 8/8] copilot --- context/PLUGIN_CONTRACT.md | 6 ++++-- fastedge-plugin-source/manifest.json | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/context/PLUGIN_CONTRACT.md b/context/PLUGIN_CONTRACT.md index 6d76c3e..9f97825 100644 --- a/context/PLUGIN_CONTRACT.md +++ b/context/PLUGIN_CONTRACT.md @@ -36,10 +36,12 @@ plugins/gcore-fastedge/skills/ 1. **reference_file** paths must include the `http/` or `cdn/` subfolder for app_type-specific content 2. **section** should be `null` for all entries (each file is owned by one repo — no splicing) -3. **Dual-intent pattern**: each example gets two entries with the same `files` array: +3. **Dual-intent pattern**: each **feature** example gets two entries with the same `files` array: - `{name}-blueprint` → `scaffold/reference/{appType}/{concept}-{lang}.md` - `{name}-pattern` → `fastedge-docs/reference/{appType}/examples-{concept}-{lang}.md` + **Exception**: Base skeleton examples (`hello-world`) only get a `-blueprint` entry pointing to `scaffold/reference/{appType}/base-{lang}.md`. They have no `-pattern` counterpart because they don't demonstrate a reusable feature pattern. + ## Intent File Matching The pipeline resolves intent files by extracting the path suffix after `reference/` from the `reference_file` path. It looks for that same relative path inside the plugin's intent directory for this repo. @@ -51,7 +53,7 @@ Example: ## When Adding New Examples -1. Add source entries (paired `-blueprint` and `-pattern`) to `manifest.json` +1. Add source entries (paired `-blueprint` and `-pattern` for feature examples; `-blueprint` only for base skeletons) to `manifest.json` 2. Add target_mapping entries pointing to `{appType}/{concept}-{lang}.md` paths 3. Request intent files be created in `fastedge-plugin` repo (or create via PR): - `agent-intent-skills/fastedge-sdk-js/{appType}/{concept}-{lang}.md` (scaffold) diff --git a/fastedge-plugin-source/manifest.json b/fastedge-plugin-source/manifest.json index 8226c75..540ad7d 100644 --- a/fastedge-plugin-source/manifest.json +++ b/fastedge-plugin-source/manifest.json @@ -1,6 +1,6 @@ { "$schema": "https://fastedge-plugin-source/manifest/v1", - "repo_id": "FastEdge-sdk-js", + "repo_id": "fastedge-sdk-js", "version": "1.1.0", "sources": { "sdk-api": {