diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 686509c8..9bf68b61 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -26,7 +26,6 @@
"markdown.extension.list.indentationSize": "adaptive",
"markdown.extension.italic.indicator": "_",
"markdown.extension.orderedList.marker": "one",
- "remote.SSH.enableAgentForwarding": true,
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
},
@@ -52,7 +51,6 @@
"GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}"
},
"features": {
- "ghcr.io/devcontainers/features/github-cli:1": {},
- "ghcr.io/devcontainers-contrib/features/prettier:1": {}
+ "ghcr.io/devcontainers-community/npm-features/prettier": {}
}
}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 948c0003..9524be92 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -54,6 +54,8 @@ jobs:
module-change-exclude-patterns: .gitignore,*.md,*.tftest.hcl,tests/**,examples/**
module-asset-exclude-patterns: .gitignore,*.md,*.tftest.hcl,tests/**
use-ssh-source-format: true
+ tag-directory-separator: "-"
+ use-version-prefix: false
- name: Test Action Outputs
id: test-outputs
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 19e2f655..4cf426c9 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -42,7 +42,7 @@ jobs:
- name: Lint Codebase
id: super-linter
- uses: super-linter/super-linter/slim@v7
+ uses: super-linter/super-linter@12150456a73e248bdc94d0794898f94e23127c88 # v7.4.0
env:
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release-start.yml b/.github/workflows/release-start.yml
index abfb5db7..1c498dc9 100644
--- a/.github/workflows/release-start.yml
+++ b/.github/workflows/release-start.yml
@@ -149,7 +149,7 @@ jobs:
}
- name: Create Branch and Pull Request
- uses: peter-evans/create-pull-request@v7
+ uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ steps.app-token.outputs.token }}
base: main
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 7b87f0e0..82544f88 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -10,9 +10,9 @@ on:
types: [opened, synchronize, reopened]
jobs:
- tests:
+ Tests:
runs-on: ubuntu-latest
- name: Test
+ name: TypeScript Tests
permissions:
contents: read
steps:
@@ -33,9 +33,10 @@ jobs:
- name: Run Tests Typescript
run: npm run test
env:
- GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO_CI_TESTING }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # Note: SonarQube requires the results from tests to get the coverage report
- name: SonarQube Scan
- uses: SonarSource/sonarqube-scan-action@v5
+ uses: SonarSource/sonarqube-scan-action@2500896589ef8f7247069a56136f8dc177c27ccf # v5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
diff --git a/README.md b/README.md
index 16227690..44577c50 100644
--- a/README.md
+++ b/README.md
@@ -194,12 +194,14 @@ configuring the following optional input parameters as needed.
| `delete-legacy-tags` | Specifies a boolean that determines whether tags and releases from Terraform modules that have been deleted should be automatically removed | `true` |
| `disable-wiki` | Whether to disable wiki generation for Terraform modules | `false` |
| `wiki-sidebar-changelog-max` | An integer that specifies how many changelog entries are displayed in the sidebar per module | `5` |
+| `wiki-usage-template` | A raw, multi-line string to override the default 'Usage' section in the generated wiki. Allows using variables like {{module_name}}, {{latest_tag}}, {{latest_tag_version_number}} and more.
[Read more here](#configuring-the-usage-template) | [See action.yml](https://github.com/polleuretan/terraform-module-releaser/blob/main/action.yml#L108) |
| `disable-branding` | Controls whether a small branding link to the action's repository is added to PR comments. Recommended to leave enabled to support OSS. | `false` |
| `module-path-ignore` | Comma-separated list of module paths to completely ignore. Modules matching any pattern here are excluded from all versioning, releases, and documentation.
[Read more here](#understanding-the-filtering-options) | `` (empty string) |
| `module-change-exclude-patterns` | Comma-separated list of file patterns (relative to each module) to exclude from triggering version changes. Lets you release a module but control which files inside it do not force a version bump.
[Read more here](#understanding-the-filtering-options) | `.gitignore,*.md,*.tftest.hcl,tests/**` |
| `module-asset-exclude-patterns` | A comma-separated list of file patterns to exclude when bundling a Terraform module for tag/release. Patterns follow glob syntax (e.g., `tests/\*\*`) and are relative to each Terraform module directory. Files matching these patterns will be excluded from the bundled output. | `.gitignore,*.md,*.tftest.hcl,tests/**` |
| `use-ssh-source-format` | If enabled, all links to source code in generated Wiki documentation will use SSH standard format (e.g., `git::ssh://git@github.com/owner/repo.git`) instead of HTTPS format (`git::https://github.com/owner/repo.git`) | `false` |
-| `wiki-usage-template` | A raw, multi-line string to override the default 'Usage' section in the generated wiki. Allows using variables like {{module_name}}, {{latest_tag}}, {{latest_tag_version_number}} and more.
[Read more here](#configuring-the-usage-template) | [See action.yml](https://github.com/polleuretan/terraform-module-releaser/blob/main/action.yml#L108) |
+| `tag-directory-separator` | Character used to separate directory path components in Git tags. Supports `/`, `-`, `_`, or `.` | `/` |
+| `use-version-prefix` | Whether to include the 'v' prefix on version tags (e.g., v1.2.3 vs 1.2.3) | `true` |
### Understanding the filtering options
diff --git a/__mocks__/@actions/core.ts b/__mocks__/@actions/core.ts
index e47f4769..9bb718e2 100644
--- a/__mocks__/@actions/core.ts
+++ b/__mocks__/@actions/core.ts
@@ -14,13 +14,13 @@ type MockedFunction = TFunc extends (...args: infer TArgs) => infer TRetu
* Writes a debug message to the user log.
* @param message - The debug message to log.
*/
-export const debug: MockedFunction<(message: string) => void> = vi.fn((message: string): void => {});
+export const debug: MockedFunction<(message: string) => void> = vi.fn((_message: string): void => {});
/**
* Writes an informational message to the log.
* @param message - The info message to log.
*/
-export const info: MockedFunction<(message: string) => void> = vi.fn((message: string): void => {});
+export const info: MockedFunction<(message: string) => void> = vi.fn((_message: string): void => {});
/**
* Adds a warning issue with optional annotation properties.
@@ -28,7 +28,7 @@ export const info: MockedFunction<(message: string) => void> = vi.fn((message: s
* @param properties - Optional properties to add to the annotation.
*/
export const warning: MockedFunction<(message: string | Error, properties?: AnnotationProperties) => void> = vi.fn(
- (message: string | Error, properties?: AnnotationProperties): void => {},
+ (_message: string | Error, _properties?: AnnotationProperties): void => {},
);
/**
@@ -37,7 +37,7 @@ export const warning: MockedFunction<(message: string | Error, properties?: Anno
* @param properties - Optional properties to add to the annotation.
*/
export const notice: MockedFunction<(message: string | Error, properties?: AnnotationProperties) => void> = vi.fn(
- (message: string | Error, properties?: AnnotationProperties): void => {},
+ (_message: string | Error, _properties?: AnnotationProperties): void => {},
);
/**
@@ -46,7 +46,7 @@ export const notice: MockedFunction<(message: string | Error, properties?: Annot
* @param properties - Optional properties to add to the annotation.
*/
export const error: MockedFunction<(message: string | Error, properties?: AnnotationProperties) => void> = vi.fn(
- (message: string | Error, properties?: AnnotationProperties): void => {},
+ (_message: string | Error, _properties?: AnnotationProperties): void => {},
);
/**
@@ -55,13 +55,13 @@ export const error: MockedFunction<(message: string | Error, properties?: Annota
* @param message - The error message or object.
* @throws An error with the specified message.
*/
-export const setFailed: MockedFunction<(message: string | Error) => void> = vi.fn((message: string | Error) => {});
+export const setFailed: MockedFunction<(message: string | Error) => void> = vi.fn((_message: string | Error) => {});
/**
* Begins a new output group. Output until the next `endGroup` will be foldable in this group.
* @param name - The name of the output group.
*/
-export const startGroup: MockedFunction<(name: string) => void> = vi.fn((name: string): void => {});
+export const startGroup: MockedFunction<(name: string) => void> = vi.fn((_name: string): void => {});
/**
* Ends the current output group.
@@ -109,13 +109,13 @@ export const getMultilineInput: MockedFunction<(name: string, options?: InputOpt
* Masks a value in the log. When the masked value appears in the log, it is replaced with asterisks.
* @param secret - Value to mask
*/
-export const setSecret: MockedFunction<(secret: string) => void> = vi.fn((secret: string): void => {});
+export const setSecret: MockedFunction<(secret: string) => void> = vi.fn((_secret: string): void => {});
/**
* Prepends the given path to the PATH environment variable.
* @param inputPath - Path to prepend
*/
-export const addPath: MockedFunction<(inputPath: string) => void> = vi.fn((inputPath: string): void => {});
+export const addPath: MockedFunction<(inputPath: string) => void> = vi.fn((_inputPath: string): void => {});
/**
* Sets env variable for this action and future actions in the job.
@@ -123,14 +123,14 @@ export const addPath: MockedFunction<(inputPath: string) => void> = vi.fn((input
* @param val - Value of the variable
*/
export const exportVariable: MockedFunction<(name: string, val: string) => void> = vi.fn(
- (name: string, val: string): void => {},
+ (_name: string, _val: string): void => {},
);
/**
* Enables or disables the echoing of commands into stdout for the rest of the step.
* @param enabled - True to enable echoing, false to disable
*/
-export const setCommandEcho: MockedFunction<(enabled: boolean) => void> = vi.fn((enabled: boolean): void => {});
+export const setCommandEcho: MockedFunction<(enabled: boolean) => void> = vi.fn((_enabled: boolean): void => {});
/**
* Begin an output group.
@@ -138,7 +138,7 @@ export const setCommandEcho: MockedFunction<(enabled: boolean) => void> = vi.fn(
* @param fn - Function to execute within the output group
*/
export const group: MockedFunction<(name: string, fn: () => Promise) => Promise> = vi.fn(
- async (name: string, fn: () => Promise): Promise => {
+ async (_name: string, fn: () => Promise): Promise => {
await fn();
},
);
@@ -150,7 +150,7 @@ export const group: MockedFunction<(name: string, fn: () => Promise) => Pr
* @param value - Value to store. Non-string values will be converted to a string via JSON.stringify
*/
export const saveState: MockedFunction<(name: string, value: string) => void> = vi.fn(
- (name: string, value: string): void => {},
+ (_name: string, _value: string): void => {},
);
/**
@@ -158,7 +158,7 @@ export const saveState: MockedFunction<(name: string, value: string) => void> =
* @param name - Name of the state to get
* @returns string
*/
-export const getState: MockedFunction<(name: string) => string> = vi.fn((name: string): string => '');
+export const getState: MockedFunction<(name: string) => string> = vi.fn((_name: string): string => '');
/**
* Gets whether Actions Step Debug is on or not
@@ -172,7 +172,7 @@ export const isDebug: MockedFunction<() => boolean> = vi.fn((): boolean => false
* @returns string
*/
export const getIDToken: MockedFunction<(audience?: string) => Promise> = vi.fn(
- async (audience?: string): Promise => '',
+ async (_audience?: string): Promise => '',
);
/**
@@ -181,7 +181,7 @@ export const getIDToken: MockedFunction<(audience?: string) => Promise>
* @param value - Value to store. Non-string values will be converted to a string via JSON.stringify
*/
export const setOutput: MockedFunction<(name: string, value: string) => void> = vi.fn(
- (name: string, value: string): void => {},
+ (_name: string, _value: string): void => {},
);
// Re-export types
diff --git a/__mocks__/config.ts b/__mocks__/config.ts
index 5c43f6b4..bd10312b 100644
--- a/__mocks__/config.ts
+++ b/__mocks__/config.ts
@@ -1,4 +1,7 @@
+import { setupTestInputs } from '@/tests/helpers/inputs';
import type { Config } from '@/types';
+import type { ActionInputMetadata } from '@/types';
+import { ACTION_INPUTS, createConfigFromInputs } from '@/utils/metadata';
/**
* Configuration interface with added utility methods
@@ -9,55 +12,24 @@ interface ConfigWithMethods extends Config {
}
/**
- * Default configuration object.
+ * Load default configuration from action.yml.
*/
-const defaultConfig: Config = {
- majorKeywords: ['BREAKING CHANGE', '!', 'MAJOR CHANGE'],
- minorKeywords: ['feat', 'feature'],
- patchKeywords: ['fix', 'chore'],
- defaultFirstTag: 'v1.0.0',
- terraformDocsVersion: 'v0.20.0',
- deleteLegacyTags: false,
- disableWiki: false,
- wikiSidebarChangelogMax: 10,
- disableBranding: false,
- modulePathIgnore: ['tf-modules/kms/examples/complete'],
- moduleChangeExcludePatterns: ['.gitignore', '*.md'],
- moduleAssetExcludePatterns: ['tests/**', 'examples/**'],
- githubToken: 'ghp_test_token_2c6912E7710c838347Ae178B4',
- useSSHSourceFormat: false,
- wikiUsageTemplate: `
- To use this module in your Terraform, refer to the below module example:
-
- \`\`\`hcl
- module "{{module_name_terraform}}" {
- source = "git::{{module_source}}?ref={{latest_tag}}"
-
- # See inputs below for additional required parameters
- }
- \`\`\`
-`
+const createDefaultConfig = (): Config => {
+ setupTestInputs();
+ return createConfigFromInputs();
};
/**
- * Valid configuration keys.
+ * Default configuration object loaded from action.yml.
+ */
+const defaultConfig: Config = createDefaultConfig();
+
+/**
+ * Valid configuration keys derived from ACTION_INPUTS.
*/
-const validConfigKeys = [
- 'majorKeywords',
- 'minorKeywords',
- 'patchKeywords',
- 'defaultFirstTag',
- 'terraformDocsVersion',
- 'deleteLegacyTags',
- 'disableWiki',
- 'wikiSidebarChangelogMax',
- 'disableBranding',
- 'modulePathIgnore',
- 'moduleChangeExcludePatterns',
- 'moduleAssetExcludePatterns',
- 'githubToken',
- 'useSSHSourceFormat',
-] as const;
+const validConfigKeys = (Object.values(ACTION_INPUTS) as ActionInputMetadata[]).map(
+ (metadata) => metadata.configKey,
+) as Array;
type ValidConfigKey = (typeof validConfigKeys)[number];
@@ -68,7 +40,7 @@ let currentConfig: Config = { ...defaultConfig };
* Config proxy handler.
*/
const configProxyHandler: ProxyHandler = {
- set(target: ConfigWithMethods, key: string, value: unknown): boolean {
+ set(_target: ConfigWithMethods, key: string, value: unknown): boolean {
if (!validConfigKeys.includes(key as ValidConfigKey)) {
throw new Error(`Invalid config key: ${key}`);
}
@@ -77,7 +49,7 @@ const configProxyHandler: ProxyHandler = {
const expectedValue = defaultConfig[typedKey];
if ((Array.isArray(expectedValue) && Array.isArray(value)) || typeof expectedValue === typeof value) {
- // @ts-ignore - we know that the key is valid and that the value is correct
+ // @ts-expect-error - we know that the key is valid and that the value is correct
currentConfig[typedKey] = value as typeof expectedValue;
return true;
}
@@ -85,7 +57,7 @@ const configProxyHandler: ProxyHandler = {
throw new TypeError(`Invalid value type for config key: ${key}`);
},
- get(target: ConfigWithMethods, prop: string | symbol): unknown {
+ get(_target: ConfigWithMethods, prop: string | symbol): unknown {
if (typeof prop === 'string') {
if (prop === 'set') {
return (overrides: Partial = {}) => {
diff --git a/__mocks__/context.ts b/__mocks__/context.ts
index 11ad91d0..5c0a9595 100644
--- a/__mocks__/context.ts
+++ b/__mocks__/context.ts
@@ -59,7 +59,7 @@ let currentContext: Context = { ...defaultContext };
* Context proxy handler
*/
const contextProxyHandler: ProxyHandler = {
- set(target: ContextWithMethods, key: string, value: unknown): boolean {
+ set(_target: ContextWithMethods, key: string, value: unknown): boolean {
if (!validContextKeys.includes(key as ValidContextKey)) {
throw new Error(`Invalid context key: ${key}`);
}
@@ -68,7 +68,7 @@ const contextProxyHandler: ProxyHandler = {
const expectedValue = defaultContext[typedKey];
if (typeof expectedValue === typeof value || (typedKey === 'octokit' && typeof value === 'object')) {
- // @ts-ignore - we know the key is valid and value type is correct
+ // @ts-expect-error - we know the key is valid and value type is correct
currentContext[typedKey] = value;
return true;
}
@@ -76,7 +76,7 @@ const contextProxyHandler: ProxyHandler = {
throw new TypeError(`Invalid value type for context key: ${key}`);
},
- get(target: ContextWithMethods, prop: string | symbol): unknown {
+ get(_target: ContextWithMethods, prop: string | symbol): unknown {
if (typeof prop === 'string') {
if (prop === 'set') {
return (overrides: Partial = {}) => {
diff --git a/__tests__/_setup.ts b/__tests__/_setup.ts
index 7a9ac6ff..da84e9c1 100644
--- a/__tests__/_setup.ts
+++ b/__tests__/_setup.ts
@@ -1,3 +1,4 @@
+import { setupTestInputs } from '@/tests/helpers/inputs';
import { afterEach, beforeEach, vi } from 'vitest';
// Mocked node modules (./__mocks__/*)
@@ -20,11 +21,14 @@ const defaultEnvironmentVariables = {
};
beforeEach(() => {
- // Initialize environment
+ // Initialize GitHub mock pull request environment
for (const [key, value] of Object.entries(defaultEnvironmentVariables)) {
vi.stubEnv(key, value);
}
+ // Set up action input defaults for testing
+ setupTestInputs();
+
// Clear all mocked functions usage data and state
vi.clearAllMocks();
});
diff --git a/__tests__/config.test.ts b/__tests__/config.test.ts
index be14bc22..1cc95cf7 100644
--- a/__tests__/config.test.ts
+++ b/__tests__/config.test.ts
@@ -2,14 +2,14 @@ import { clearConfigForTesting, config, getConfig } from '@/config';
import {
arrayInputs,
booleanInputs,
- inputToConfigKey,
- inputToConfigKeyMap,
+ clearEnvironmentInput,
+ getConfigKey,
optionalInputs,
requiredInputs,
+ setupTestInputs,
stringInputs,
- stubInputEnv,
} from '@/tests/helpers/inputs';
-import type { Config } from '@/types';
+import { VALID_TAG_DIRECTORY_SEPARATORS } from '@/utils/constants';
import { endGroup, getBooleanInput, getInput, info, startGroup } from '@actions/core';
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
@@ -22,38 +22,40 @@ describe('config', () => {
});
beforeEach(() => {
+ // The config is cached. To ensure each test starts with a clean slate, we implicity clear it.
+ // We don't do this globally in setup as it's not necessary for all tests.
clearConfigForTesting();
- // Note: We don't stubInputEnv here as there are cases where we want to test default inputs and
- // in this case we would have to do a full reset of the config.
});
describe('input validation', () => {
for (const input of requiredInputs) {
it(`should throw error when required input "${input}" is missing`, () => {
- stubInputEnv({ [input]: null });
- expect(() => getConfig()).toThrow(new Error(`Input required and not supplied: ${input}`));
+ clearEnvironmentInput(input);
+ expect(() => getConfig()).toThrow(
+ new Error(`Failed to process input '${input}': Input required and not supplied: ${input}`),
+ );
expect(getInput).toHaveBeenCalled();
});
}
for (const input of optionalInputs) {
it(`should handle optional input "${input}" when not present`, () => {
- stubInputEnv({ [input]: null });
+ clearEnvironmentInput(input);
// Simply verify it doesn't throw without the specific error object
expect(() => getConfig()).not.toThrow();
// Get the config and check the actual value
const config = getConfig();
- // Get the config key using the mapping directly if possible
- const configKey = inputToConfigKeyMap[input] || inputToConfigKey(input);
+ // Get the config key using the new getConfigKey function
+ const configKey = getConfigKey(input);
// Type-safe access using the mapping
if (arrayInputs.includes(input)) {
- // Cast configKey to keyof Config to ensure type safety
- expect(config[configKey as keyof Config]).toEqual([]);
+ // Now configKey is properly typed as keyof Config
+ expect(config[configKey]).toEqual([]);
}
if (stringInputs.includes(input)) {
- expect(config[configKey as keyof Config]).toEqual('');
+ expect(config[configKey]).toEqual('');
}
expect(getInput).toHaveBeenCalled();
@@ -62,10 +64,10 @@ describe('config', () => {
for (const input of booleanInputs) {
it(`should throw error when input "${input}" has an invalid boolean value`, () => {
- stubInputEnv({ [input]: 'invalid-boolean' });
+ setupTestInputs({ [input]: 'invalid-boolean' });
expect(() => getConfig()).toThrow(
- new TypeError(
- `Input does not meet YAML 1.2 "Core Schema" specification: ${input}\nSupport boolean input list: \`true | True | TRUE | false | False | FALSE\``,
+ new Error(
+ `Failed to process input '${input}': Input does not meet YAML 1.2 "Core Schema" specification: ${input}\nSupport boolean input list: \`true | True | TRUE | false | False | FALSE\``,
),
);
expect(getBooleanInput).toHaveBeenCalled();
@@ -73,20 +75,20 @@ describe('config', () => {
}
it('should throw error when moduleChangeExcludePatterns includes *.tf', () => {
- stubInputEnv({ 'module-change-exclude-patterns': '*.tf,tests/**' });
+ setupTestInputs({ 'module-change-exclude-patterns': '*.tf,tests/**' });
expect(() => getConfig()).toThrow(
new TypeError('Exclude patterns cannot contain "*.tf" as it is required for module detection'),
);
});
it('should throw error when moduleAssetExcludePatterns includes *.tf', () => {
- stubInputEnv({ 'module-asset-exclude-patterns': '*.tf,tests/**' });
+ setupTestInputs({ 'module-asset-exclude-patterns': '*.tf,tests/**' });
expect(() => getConfig()).toThrow(
new TypeError('Asset exclude patterns cannot contain "*.tf" as these files are required'),
);
});
- it('should handle boolean conversions for various formats', async () => {
+ it('should handle boolean conversions for various formats', () => {
const booleanCases = ['true', 'True', 'TRUE', 'false', 'False', 'FALSE'];
for (const booleanValue of booleanCases) {
@@ -100,36 +102,134 @@ describe('config', () => {
return acc;
}, {});
- stubInputEnv(booleanInputValuesTest);
+ setupTestInputs(booleanInputValuesTest);
// Check the boolean conversion for each key in booleanInputs
const config = getConfig();
for (const booleanInput of booleanInputs) {
// Get config key from the mapping, which is already typed as keyof Config
- const configKey = inputToConfigKeyMap[booleanInput];
+ const configKey = getConfigKey(booleanInput);
expect(config[configKey]).toBe(booleanValue.toLowerCase() === 'true');
}
}
});
+ it('should handle array input parsing and deduplication', () => {
+ const arrayTestCases = [
+ { input: 'item1,item2,item3', expected: ['item1', 'item2', 'item3'] },
+ { input: ' item4 , item5 , item6 ', expected: ['item4', 'item5', 'item6'] },
+ { input: 'item7,item7,item8', expected: ['item7', 'item8'] },
+ { input: 'item10,,item11,,,item12', expected: ['item10', 'item11', 'item12'] },
+ ];
+
+ for (const testCase of arrayTestCases) {
+ // Ensure we reset the configuration since this is looping inside the test
+ clearConfigForTesting();
+ vi.unstubAllEnvs();
+
+ // Create test inputs for all array inputs
+ const arrayInputValuesTest = arrayInputs.reduce((acc: Record, key) => {
+ acc[key] = testCase.input;
+ return acc;
+ }, {});
+
+ setupTestInputs(arrayInputValuesTest);
+
+ // Check array parsing for each array input
+ const config = getConfig();
+ for (const arrayInput of arrayInputs) {
+ const configKey = getConfigKey(arrayInput);
+ expect(config[configKey]).toEqual(testCase.expected);
+ }
+ }
+ });
+
+ it('should throw error for required array inputs when empty string is provided', () => {
+ const requiredArrayInputs = arrayInputs.filter((input) => requiredInputs.includes(input));
+
+ for (const input of requiredArrayInputs) {
+ clearConfigForTesting();
+ vi.unstubAllEnvs();
+
+ // Set the required array input to empty string
+ setupTestInputs({ [input]: '' });
+
+ expect(() => getConfig()).toThrow(
+ new Error(`Failed to process input '${input}': Input required and not supplied: ${input}`),
+ );
+ }
+ });
+
+ it('should return empty array for optional array inputs when empty string is provided', () => {
+ const optionalArrayInputs = arrayInputs.filter((input) => optionalInputs.includes(input));
+
+ for (const input of optionalArrayInputs) {
+ clearConfigForTesting();
+ vi.unstubAllEnvs();
+
+ // Set the optional array input to empty string
+ setupTestInputs({ [input]: '' });
+
+ const config = getConfig();
+ const configKey = getConfigKey(input);
+ expect(config[configKey]).toEqual([]);
+ }
+ });
+
it('should throw error for non-numeric wiki-sidebar-changelog-max', () => {
- stubInputEnv({ 'wiki-sidebar-changelog-max': 'invalid' });
+ setupTestInputs({ 'wiki-sidebar-changelog-max': 'invalid' });
expect(() => getConfig()).toThrow(
new TypeError('Wiki Sidebar Change Log Max must be an integer greater than or equal to one'),
);
});
it('should throw error for 0 wiki-sidebar-changelog-max', () => {
- stubInputEnv({ 'wiki-sidebar-changelog-max': '0' });
+ setupTestInputs({ 'wiki-sidebar-changelog-max': '0' });
expect(() => getConfig()).toThrow(
new TypeError('Wiki Sidebar Change Log Max must be an integer greater than or equal to one'),
);
});
+
+ it('should throw error for invalid tag directory separator length', () => {
+ setupTestInputs({ 'tag-directory-separator': 'ab' });
+ expect(() => getConfig()).toThrow(new TypeError('Tag directory separator must be exactly one character'));
+ });
+
+ it('should throw error for invalid tag directory separator character', () => {
+ setupTestInputs({ 'tag-directory-separator': '@' });
+ expect(() => getConfig()).toThrow(
+ new TypeError(`Tag directory separator must be one of: ${VALID_TAG_DIRECTORY_SEPARATORS.join(', ')}. Got: '@'`),
+ );
+ });
+
+ it('should allow valid tag directory separators', () => {
+ for (const separator of VALID_TAG_DIRECTORY_SEPARATORS) {
+ clearConfigForTesting();
+ vi.unstubAllEnvs();
+ setupTestInputs({ 'tag-directory-separator': separator });
+ const config = getConfig();
+ expect(config.tagDirectorySeparator).toBe(separator);
+ }
+ });
+
+ it('should throw error for invalid default first tag format', () => {
+ setupTestInputs({ 'default-first-tag': 'invalid-tag' });
+ expect(() => getConfig()).toThrow(
+ new TypeError(
+ "Default first tag must be in format v#.#.# or #.#.# (e.g., v1.0.0 or 1.0.0). Got: 'invalid-tag'",
+ ),
+ );
+
+ clearConfigForTesting();
+ setupTestInputs({ 'default-first-tag': 'v1.0' });
+ expect(() => getConfig()).toThrow(
+ new TypeError("Default first tag must be in format v#.#.# or #.#.# (e.g., v1.0.0 or 1.0.0). Got: 'v1.0'"),
+ );
+ });
});
describe('initialization', () => {
it('should maintain singleton instance across multiple imports', () => {
- stubInputEnv();
const firstInstance = getConfig();
const secondInstance = getConfig();
expect(firstInstance).toBe(secondInstance);
@@ -137,47 +237,50 @@ describe('config', () => {
expect(endGroup).toHaveBeenCalledTimes(1);
});
- it('should initialize with valid inputs and log configuration', () => {
- stubInputEnv();
+ it('should initialize with valid default inputs', () => {
const config = getConfig();
- expect(config.majorKeywords).toEqual(['MAJOR CHANGE', 'BREAKING CHANGE', '!']);
+ expect(config.majorKeywords).toEqual(['major change', 'breaking change']);
expect(config.minorKeywords).toEqual(['feat', 'feature']);
- expect(config.patchKeywords).toEqual(['fix', 'chore']);
- expect(config.defaultFirstTag).toBe('v0.1.0');
- expect(config.terraformDocsVersion).toBe('v0.19.0');
- expect(config.deleteLegacyTags).toBe(false);
+ expect(config.patchKeywords).toEqual(['fix', 'chore', 'docs']);
+ expect(config.defaultFirstTag).toBe('v1.0.0');
+ expect(config.terraformDocsVersion).toBe('v0.20.0');
+ expect(config.deleteLegacyTags).toBe(true);
expect(config.disableWiki).toBe(false);
- expect(config.wikiSidebarChangelogMax).toBe(10);
+ expect(config.wikiSidebarChangelogMax).toBe(5);
expect(config.disableBranding).toBe(false);
expect(config.githubToken).toBe('ghp_test_token_2c6912E7710c838347Ae178B4');
- expect(config.moduleChangeExcludePatterns).toEqual(['.gitignore', '*.md']);
- expect(config.moduleAssetExcludePatterns).toEqual(['tests/**', 'examples/**']);
- expect(config.modulePathIgnore).toEqual(['tf-modules/kms/examples/complete']);
+ expect(config.modulePathIgnore).toEqual([]);
+ expect(config.moduleChangeExcludePatterns).toEqual(['.gitignore', '*.md', '*.tftest.hcl', 'tests/**']);
+ expect(config.moduleAssetExcludePatterns).toEqual(['.gitignore', '*.md', '*.tftest.hcl', 'tests/**']);
expect(config.useSSHSourceFormat).toBe(false);
+ expect(config.tagDirectorySeparator).toBe('/');
+ expect(config.useVersionPrefix).toBe(true);
+
expect(startGroup).toHaveBeenCalledWith('Initializing Config');
expect(startGroup).toHaveBeenCalledTimes(1);
expect(endGroup).toHaveBeenCalledTimes(1);
expect(vi.mocked(info).mock.calls).toEqual([
- ['Major Keywords: MAJOR CHANGE, BREAKING CHANGE, !'],
+ ['Major Keywords: major change, breaking change'],
['Minor Keywords: feat, feature'],
- ['Patch Keywords: fix, chore'],
- ['Default First Tag: v0.1.0'],
- ['Terraform Docs Version: v0.19.0'],
- ['Delete Legacy Tags: false'],
+ ['Patch Keywords: fix, chore, docs'],
+ ['Default First Tag: v1.0.0'],
+ ['Terraform Docs Version: v0.20.0'],
+ ['Delete Legacy Tags: true'],
['Disable Wiki: false'],
- ['Wiki Sidebar Changelog Max: 10'],
- ['Module Paths to Ignore: tf-modules/kms/examples/complete'],
- ['Module Change Exclude Patterns: .gitignore, *.md'],
- ['Module Asset Exclude Patterns: tests/**, examples/**'],
+ ['Wiki Sidebar Changelog Max: 5'],
+ ['Module Paths to Ignore: '],
+ ['Module Change Exclude Patterns: .gitignore, *.md, *.tftest.hcl, tests/**'],
+ ['Module Asset Exclude Patterns: .gitignore, *.md, *.tftest.hcl, tests/**'],
['Use SSH Source Format: false'],
+ ['Tag Directory Separator: /'],
+ ['Use Version Prefix: true'],
]);
});
});
describe('config proxy', () => {
it('should proxy config properties', () => {
- stubInputEnv();
const proxyMajorKeywords = config.majorKeywords;
const getterMajorKeywords = getConfig().majorKeywords;
expect(proxyMajorKeywords).toEqual(getterMajorKeywords);
@@ -196,32 +299,4 @@ describe('config', () => {
expect(info).not.toHaveBeenCalled();
});
});
-
- describe('input formatting', () => {
- it('should handle various whitespace and duplicates in comma-separated inputs', () => {
- stubInputEnv({
- 'major-keywords': ' BREAKING CHANGE , ! ',
- 'minor-keywords': '\tfeat,\nfeature\r,feat',
- });
- const config = getConfig();
- expect(config.majorKeywords).toEqual(['BREAKING CHANGE', '!']);
- expect(config.minorKeywords).toEqual(['feat', 'feature']);
- });
-
- it('should filter out empty items in arrays', async () => {
- stubInputEnv({
- 'major-keywords': 'BREAKING CHANGE,,!,,,',
- 'module-change-exclude-patterns': ',.gitignore,,*.md,,',
- });
- const config = getConfig();
- expect(config.majorKeywords).toEqual(['BREAKING CHANGE', '!']);
- expect(config.moduleChangeExcludePatterns).toEqual(['.gitignore', '*.md']);
- });
-
- it('should handle empty modulePathIgnore', () => {
- stubInputEnv({ 'module-path-ignore': '' });
- const config = getConfig();
- expect(config.modulePathIgnore).toEqual([]);
- });
- });
});
diff --git a/__tests__/context.test.ts b/__tests__/context.test.ts
index f837d46f..923a4830 100644
--- a/__tests__/context.test.ts
+++ b/__tests__/context.test.ts
@@ -4,7 +4,7 @@ import { createPullRequestMock } from '@/mocks/context';
import { info, startGroup } from '@actions/core';
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
-// Mock node:fs. (Note: Appears we can't spy on functions via node:fs)
+// Mock node:fs required for reading pull-request file information (Note: Appears we can't spy on functions via node:fs)
vi.mock('node:fs', async () => {
const original = await vi.importActual('node:fs');
return {
@@ -46,7 +46,9 @@ describe('context', () => {
describe('environment variable validation', () => {
for (const envVar of requiredEnvVars) {
it(`should throw an error if ${envVar} is not set`, () => {
+ // Set the specific environment variable to undefined, but keep others set
vi.stubEnv(envVar, undefined);
+
expect(() => getContext()).toThrow(
new Error(
`The ${envVar} environment variable is missing or invalid. This variable should be automatically set by GitHub for each workflow run. If this variable is missing or not correctly set, it indicates a serious issue with the GitHub Actions environment, potentially affecting the execution of subsequent steps in the workflow. Please review the workflow setup or consult the documentation for proper configuration.`,
@@ -182,9 +184,6 @@ describe('context', () => {
const customApiUrl = 'https://github.example.com/api/v3';
vi.stubEnv('GITHUB_API_URL', customApiUrl);
- // Clear context to force reinitialization
- clearContextForTesting();
-
const context = getContext();
// Check that the context was created (which means the custom API URL was used)
@@ -196,9 +195,6 @@ describe('context', () => {
// Ensure GITHUB_API_URL is not set to test the default fallback
vi.stubEnv('GITHUB_API_URL', undefined);
- // Clear context to force reinitialization
- clearContextForTesting();
-
const context = getContext();
// Check that the context was created with default API URL
@@ -220,7 +216,7 @@ describe('context', () => {
vi.mocked(startGroup).mockClear();
// Second access should not trigger initialization
- const prNumber = context.prNumber; // Intentionally access a property with no usage
+ const _prNumber = context.prNumber; // Intentionally access a property with no usage
expect(startGroup).not.toHaveBeenCalled();
expect(info).not.toHaveBeenCalled();
});
diff --git a/__tests__/helpers/action-defaults.ts b/__tests__/helpers/action-defaults.ts
new file mode 100644
index 00000000..ff549e93
--- /dev/null
+++ b/__tests__/helpers/action-defaults.ts
@@ -0,0 +1,48 @@
+import * as fs from 'node:fs';
+import * as path from 'node:path';
+import { ACTION_INPUTS } from '@/utils/metadata';
+import * as yaml from 'js-yaml';
+
+/**
+ * Interface for action.yml structure
+ */
+interface ActionYml {
+ inputs: Record<
+ string,
+ {
+ description: string;
+ required: boolean;
+ default?: string;
+ }
+ >;
+}
+
+/**
+ * Gets action defaults from action.yml file.
+ * Returns a record of all input names to their default values (or undefined if no default).
+ */
+/**
+ * Extracts default values for GitHub Action inputs from action.yml file.
+ *
+ * This function reads the action.yml file from the current working directory,
+ * parses its content, and retrieves the default values for all inputs defined
+ * in ACTION_INPUTS.
+ *
+ * @returns A record mapping each input name to its default value from the action.yml file.
+ * If an input has no default value, its entry will contain undefined.
+ */
+export function getActionDefaults(): Record {
+ const actionYmlPath = path.join(process.cwd(), 'action.yml');
+ const actionYmlContent = fs.readFileSync(actionYmlPath, 'utf8');
+ const actionYml = yaml.load(actionYmlContent) as ActionYml;
+
+ const defaults: Record = {};
+
+ // Process all inputs from ACTION_INPUTS to ensure we have entries for all inputs
+ for (const [inputName] of Object.entries(ACTION_INPUTS)) {
+ const actionInput = actionYml.inputs[inputName];
+ defaults[inputName] = actionInput?.default;
+ }
+
+ return defaults;
+}
diff --git a/__tests__/helpers/inputs.ts b/__tests__/helpers/inputs.ts
index 5fa41ad0..0801dbdd 100644
--- a/__tests__/helpers/inputs.ts
+++ b/__tests__/helpers/inputs.ts
@@ -1,121 +1,89 @@
+import { getActionDefaults } from '@/tests/helpers/action-defaults';
import type { Config } from '@/types';
+import { ACTION_INPUTS } from '@/utils/metadata';
import { vi } from 'vitest';
-const INPUT_KEY = 'INPUT_';
+// Load action defaults once globally
+const ACTION_DEFAULTS = getActionDefaults();
+
+// Generate input type arrays from centralized metadata
+export const requiredInputs = Object.entries(ACTION_INPUTS)
+ .filter(([, metadata]) => metadata.required)
+ .map(([inputName]) => inputName);
+
+export const optionalInputs = Object.entries(ACTION_INPUTS)
+ .filter(([, metadata]) => !metadata.required)
+ .map(([inputName]) => inputName);
+
+export const booleanInputs = Object.entries(ACTION_INPUTS)
+ .filter(([, metadata]) => metadata.type === 'boolean')
+ .map(([inputName]) => inputName);
+
+export const arrayInputs = Object.entries(ACTION_INPUTS)
+ .filter(([, metadata]) => metadata.type === 'array')
+ .map(([inputName]) => inputName);
+
+export const stringInputs = Object.entries(ACTION_INPUTS)
+ .filter(([, metadata]) => metadata.type === 'string')
+ .map(([inputName]) => inputName);
+
+export const numberInputs = Object.entries(ACTION_INPUTS)
+ .filter(([, metadata]) => metadata.type === 'number')
+ .map(([inputName]) => inputName);
/**
- * Type-safe mapping from input names to config keys.
- * This ensures that each value is a valid key in the Config type.
+ * Converts an input name to its corresponding config key.
+ * @param inputName The input name (e.g., 'github_token', 'module-path-ignore')
+ * @returns The corresponding config key as a keyof Config
*/
-export const inputToConfigKeyMap: Record = {
- 'major-keywords': 'majorKeywords',
- 'minor-keywords': 'minorKeywords',
- 'patch-keywords': 'patchKeywords',
- 'default-first-tag': 'defaultFirstTag',
- 'terraform-docs-version': 'terraformDocsVersion',
- 'delete-legacy-tags': 'deleteLegacyTags',
- 'disable-wiki': 'disableWiki',
- 'wiki-sidebar-changelog-max': 'wikiSidebarChangelogMax',
- 'disable-branding': 'disableBranding',
- github_token: 'githubToken',
- 'module-path-ignore': 'modulePathIgnore',
- 'module-change-exclude-patterns': 'moduleChangeExcludePatterns',
- 'module-asset-exclude-patterns': 'moduleAssetExcludePatterns',
- 'use-ssh-source-format': 'useSSHSourceFormat',
-};
+export function getConfigKey(inputName: string): keyof Config {
+ const metadata = ACTION_INPUTS[inputName];
+ if (!metadata) {
+ throw new Error(`Unknown input: ${inputName}`);
+ }
-// Create reverse mapping from config keys to input names
-export const configKeyToInputMap = Object.entries(inputToConfigKeyMap).reduce(
- (acc, [inputName, configKey]) => {
- acc[configKey] = inputName;
- return acc;
- },
- {} as Record,
-);
+ return metadata.configKey;
+}
-// Default inputs used for testing @actions/core behavior
-export const defaultInputs = {
- 'major-keywords': 'MAJOR CHANGE,BREAKING CHANGE,!',
- 'minor-keywords': 'feat,feature',
- 'patch-keywords': 'fix,chore',
- 'default-first-tag': 'v0.1.0',
- 'terraform-docs-version': 'v0.19.0',
- 'delete-legacy-tags': 'false',
- 'disable-wiki': 'false',
- 'wiki-sidebar-changelog-max': '10',
- 'disable-branding': 'false',
- 'module-path-ignore': 'tf-modules/kms/examples/complete',
- 'module-change-exclude-patterns': '.gitignore,*.md',
- 'module-asset-exclude-patterns': 'tests/**,examples/**',
- github_token: 'ghp_test_token_2c6912E7710c838347Ae178B4',
- 'use-ssh-source-format': 'false',
-};
-export const requiredInputs = [
- 'major-keywords',
- 'minor-keywords',
- 'patch-keywords',
- 'default-first-tag',
- 'terraform-docs-version',
- 'delete-legacy-tags',
- 'disable-wiki',
- 'wiki-sidebar-changelog-max',
- 'disable-branding',
- 'github_token',
- 'use-ssh-source-format',
-];
-export const optionalInputs = Object.keys(defaultInputs).filter((key) => !requiredInputs.includes(key));
-export const booleanInputs = ['delete-legacy-tags', 'disable-wiki', 'disable-branding', 'use-ssh-source-format'];
-export const arrayInputs = [
- 'major-keywords',
- 'minor-keywords',
- 'patch-keywords',
- 'module-path-ignore',
- 'module-change-exclude-patterns',
- 'module-asset-exclude-patterns',
-];
-export const stringInputs = ['default-first-tag', 'terraform-docs-version', 'github_token'];
-export const numberInputs = ['wiki-sidebar-changelog-max'];
+/**
+ * Converts an input name to its corresponding environment variable name.
+ * This is the exact inverse of what @actions/core getInput() does.
+ * @param inputName The input name (e.g., 'github_token', 'module-path-ignore')
+ * @returns The environment variable name (e.g., 'INPUT_GITHUB_TOKEN', 'INPUT_MODULE_PATH_IGNORE')
+ */
+function inputToEnvVar(inputName: string): string {
+ return `INPUT_${inputName.replace(/ /g, '_').toUpperCase()}`;
+}
/**
- * Converts a dash-case input name to its corresponding camelCase config key
- * Prefer using the inputToConfigKeyMap directly for known input keys
+ * Sets up test environment with action defaults and optional overrides.
+ * This replaces the previous stubInputEnv function with a cleaner approach
+ * that loads defaults from action.yml and applies test-specific overrides.
*
- * @param inputName The input name to convert
- * @returns The corresponding config key as a string
+ * @param overrides - Test-specific overrides for input values.
*/
-export function inputToConfigKey(inputName: string): string {
- // Check if the input name is in our mapping first
- if (inputName in inputToConfigKeyMap) {
- return inputToConfigKeyMap[inputName];
- }
+export function setupTestInputs(overrides: Record = {}) {
+ // Start with action.yml defaults and apply test-specific defaults
+ const allInputs = {
+ ...ACTION_DEFAULTS,
+ github_token: 'ghp_test_token_2c6912E7710c838347Ae178B4',
+ ...overrides,
+ };
- // Fallback to the conversion logic
- return inputName.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
+ // Set environment variables for all values (undefined is valid for vi.stubEnv)
+ for (const [inputName, value] of Object.entries(allInputs)) {
+ vi.stubEnv(inputToEnvVar(inputName), value);
+ }
}
/**
- * Stubs environment variables with an `INPUT_` prefix using a set of default values,
- * while allowing specific overrides. By default, this function sets a baseline of
- * sane default environment values that would typically be used in tests.
+ * Clears a specific action input environment variable.
*
- * Overrides can be provided as key-value pairs, where:
- * - A `string` value sets or replaces the environment variable.
- * - A `null` value skips the setting, allowing for flexibility in customizing the stubbed environment.
+ * Useful for testing scenarios where you need to remove a specific input. Wrapper around
+ * vi.stubEnv which has an unsual syntax for clearing environment variables/
*
- * @param {Record} overrides - An object specifying environment variable overrides.
- * Keys in this object correspond to the environment variable names (without the `INPUT_` prefix),
- * and values specify the desired values or `null` to skip setting.
+ * @param inputName The input name to clear (e.g., 'github_token', 'module-path-ignore')
*/
-export function stubInputEnv(inputs: Record = {}) {
- // Merge default inputs with overrides, giving precedence to overrides
- const mergedInputs = { ...defaultInputs, ...inputs };
-
- for (const [key, value] of Object.entries(mergedInputs)) {
- if (value === null) {
- continue;
- }
-
- const prefixedKey = `${INPUT_KEY}${key.replace(/ /g, '_').toUpperCase()}`;
- vi.stubEnv(prefixedKey, value);
- }
+export function clearEnvironmentInput(inputName: string): void {
+ vi.stubEnv(inputToEnvVar(inputName), undefined);
}
diff --git a/__tests__/helpers/octokit.ts b/__tests__/helpers/octokit.ts
index 4438055f..e5cb69aa 100644
--- a/__tests__/helpers/octokit.ts
+++ b/__tests__/helpers/octokit.ts
@@ -1,5 +1,5 @@
import type { OctokitRestApi } from '@/types';
-import { trimSlashes } from '@/utils/string';
+import { removeTrailingCharacters } from '@/utils/string';
import { paginateRest } from '@octokit/plugin-paginate-rest';
import { restEndpointMethods } from '@octokit/plugin-rest-endpoint-methods';
import type { RestEndpointMethodTypes } from '@octokit/plugin-rest-endpoint-methods';
@@ -384,5 +384,6 @@ function getLinkHeader(slug: string, page: number, perPage: number, totalCount:
const nextPage = page + 1;
const lastPage = totalPages;
- return `; rel="next", ; rel="last"`;
+ const slugTrimmed = removeTrailingCharacters(slug, ['/']);
+ return `; rel="next", ; rel="last"`;
}
diff --git a/__tests__/tags.test.ts b/__tests__/tags.test.ts
index 44a05ae2..51836ddf 100644
--- a/__tests__/tags.test.ts
+++ b/__tests__/tags.test.ts
@@ -53,7 +53,7 @@ describe('tags', () => {
expect(debugCall).toBeDefined(); // Ensure there is a debug call
const debugMessage = debugCall[0];
expect(/^Total page requests: \d+$/.test(debugMessage)).toBe(true); // Check if it matches the format
- expect(Number.parseInt(debugMessage.split(': ')[1])).toBeGreaterThan(1); // Check if number > 1
+ expect(Number.parseInt(debugMessage.split(': ')[1], 10)).toBeGreaterThan(1); // Check if number > 1
// Check the first info call for "Found X tags"
const infoCall = vi.mocked(info).mock.calls[0]; // Get the first call
@@ -270,7 +270,7 @@ describe('tags', () => {
await expect(deleteTags(tagsToDelete)).rejects.toThrow(
`Failed to delete repository tag: v1.0.0 Resource not accessible by integration.
-Ensure that the GitHub Actions workflow has the correct permissions to delete tags by ensuring that your workflow YAML file has the following block under \"permissions\":
+Ensure that the GitHub Actions workflow has the correct permissions to delete tags by ensuring that your workflow YAML file has the following block under "permissions":
permissions:
contents: write`,
diff --git a/__tests__/templating.test.ts b/__tests__/templating.test.ts
deleted file mode 100644
index 82c62d4e..00000000
--- a/__tests__/templating.test.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { describe, it, expect } from 'vitest';
-import { render } from '../src/templating';
-
-describe('templating', () => {
- it('should replace a single placeholder', () => {
- const template = 'Hello, {{name}}!';
- const variables = { name: 'World' };
- const result = render(template, variables);
- expect(result).toBe('Hello, World!');
- });
-
- it('should replace multiple placeholders', () => {
- const template = '{{greeting}}, {{name}}!';
- const variables = { greeting: 'Hi', name: 'There' };
- const result = render(template, variables);
- expect(result).toBe('Hi, There!');
- });
-
- it('should handle templates with no placeholders', () => {
- const template = 'Just a plain string.';
- const variables = { name: 'World' };
- const result = render(template, variables);
- expect(result).toBe('Just a plain string.');
- });
-
- it('should handle empty string values', () => {
- const template = 'A{{key}}B';
- const variables = { key: '' };
- const result = render(template, variables);
- expect(result).toBe('AB');
- });
-
- it('should leave unmapped placeholders untouched', () => {
- const template = 'Hello, {{name}} and {{unmapped}}!';
- const variables = { name: 'World' };
- const result = render(template, variables);
- expect(result).toBe('Hello, World and {{unmapped}}!');
- });
-});
diff --git a/__tests__/terraform-docs.test.ts b/__tests__/terraform-docs.test.ts
index df851ef4..214114d6 100644
--- a/__tests__/terraform-docs.test.ts
+++ b/__tests__/terraform-docs.test.ts
@@ -251,7 +251,7 @@ describe('terraform-docs', async () => {
for (const file of cleanupFiles) {
try {
unlinkSync(file);
- } catch (err) {
+ } catch (_err) {
// Ignore cleanup errors
}
}
diff --git a/__tests__/terraform-module.test.ts b/__tests__/terraform-module.test.ts
index 13818d25..7be18aaa 100644
--- a/__tests__/terraform-module.test.ts
+++ b/__tests__/terraform-module.test.ts
@@ -33,6 +33,7 @@ describe('TerraformModule', () => {
defaultFirstTag: 'v0.1.0',
moduleChangeExcludePatterns: [],
modulePathIgnore: [],
+ useVersionPrefix: true,
});
});
@@ -57,7 +58,7 @@ describe('TerraformModule', () => {
mkdirSync(specialDir, { recursive: true });
const module = new TerraformModule(specialDir);
- expect(module.name).toBe('complex_module-name-with/chars');
+ expect(module.name).toBe('complex_module-name.with/chars');
});
it('should handle nested directory paths', () => {
@@ -245,6 +246,38 @@ describe('TerraformModule', () => {
expect(module.getLatestTagVersion()).toBeNull();
});
+ it('should handle tags with different separators in getLatestTagVersion', () => {
+ // Test with different separators to ensure regex works correctly
+ module.setTags(['tf-modules/test-module/v1.0.0']);
+ expect(module.getLatestTagVersion()).toBe('v1.0.0');
+
+ // Test with hyphen separator
+ module.setTags(['tf-modules-test-module-v2.0.0']);
+ expect(module.getLatestTagVersion()).toBe('v2.0.0');
+
+ // Test with underscore separator
+ module.setTags(['tf-modules_test_module_v3.0.0']);
+ expect(module.getLatestTagVersion()).toBe('v3.0.0');
+
+ // Test with dot separator
+ module.setTags(['tf-modules.test.module.v4.0.0']);
+ expect(module.getLatestTagVersion()).toBe('v4.0.0');
+
+ // Test without v prefix
+ module.setTags(['tf-modules/test-module/5.0.0']);
+ expect(module.getLatestTagVersion()).toBe('5.0.0');
+ });
+
+ it('should return null when latest tag does not match MODULE_TAG_REGEX', () => {
+ // Mock getLatestTag to return an invalid format that won't match the regex
+ vi.spyOn(module, 'getLatestTag').mockReturnValue('invalid-tag-format');
+
+ expect(module.getLatestTagVersion()).toBeNull();
+
+ // Restore the original method
+ vi.restoreAllMocks();
+ });
+
it('should handle complex version sorting', () => {
const tags = [
'tf-modules/test-module/v1.2.10',
@@ -275,14 +308,14 @@ describe('TerraformModule', () => {
it('should throw error for tag with no slash (invalid format)', () => {
const tags = ['v1.2.3'];
expect(() => module.setTags(tags)).toThrow(
- "Invalid tag format: 'v1.2.3'. Expected format: 'tf-modules/test-module/v#.#.#' or 'tf-modules/test-module/#.#.#' for module.",
+ "Invalid tag format: 'v1.2.3'. Expected format: 'tf-modules/test-module[separator]v#.#.#' or 'tf-modules/test-module[separator]#.#.#'.",
);
});
it('should throw error for tag with incorrect module name', () => {
const tags = ['foo/bar/v9.8.7'];
expect(() => module.setTags(tags)).toThrow(
- "Invalid tag format: 'foo/bar/v9.8.7'. Expected format: 'tf-modules/test-module/v#.#.#' or 'tf-modules/test-module/#.#.#' for module.",
+ "Invalid tag format: 'foo/bar/v9.8.7'. Expected format: 'tf-modules/test-module[separator]v#.#.#' or 'tf-modules/test-module[separator]#.#.#'.",
);
});
@@ -304,7 +337,6 @@ describe('TerraformModule', () => {
expect(module.tags[1]).toBe('tf-modules/test-module/1.2.3');
});
- // Add tests for extractVersionFromTag
describe('extractVersionFromTag()', () => {
let module: TerraformModule;
@@ -473,7 +505,7 @@ describe('TerraformModule', () => {
];
expect(() => module.setReleases(releases)).toThrow(
- "Invalid tag format: 'tf-modules/test-module/v1.0'. Expected format: 'tf-modules/test-module/v#.#.#' or 'tf-modules/test-module/#.#.#' for module.",
+ "Invalid tag format: 'tf-modules/test-module/v1.0'. Expected format: 'tf-modules/test-module[separator]v#.#.#' or 'tf-modules/test-module[separator]#.#.#'.",
);
});
@@ -494,7 +526,7 @@ describe('TerraformModule', () => {
];
expect(() => module.setReleases(releases)).toThrow(
- "Invalid tag format: 'tf-modules/test-module/vbeta.1.0'. Expected format: 'tf-modules/test-module/v#.#.#' or 'tf-modules/test-module/#.#.#' for module.",
+ "Invalid tag format: 'tf-modules/test-module/vbeta.1.0'. Expected format: 'tf-modules/test-module[separator]v#.#.#' or 'tf-modules/test-module[separator]#.#.#'.",
);
});
@@ -788,6 +820,38 @@ describe('TerraformModule', () => {
"Invalid version format: 'invalid-format'. Expected v#.#.# or #.#.# format.",
);
});
+
+ it('should respect useVersionPrefix setting when true (with v prefix)', () => {
+ // Set useVersionPrefix to true
+ config.set({
+ useVersionPrefix: true,
+ });
+
+ module.setTags(['tf-modules/test-module/v1.2.3']);
+ module.addCommit({
+ sha: 'abc123',
+ message: 'fix: bug fix',
+ files: ['main.tf'],
+ });
+
+ expect(module.getReleaseTagVersion()).toBe('v1.2.4');
+ });
+
+ it('should respect useVersionPrefix setting when false (without v prefix)', () => {
+ // Set useVersionPrefix to false
+ config.set({
+ useVersionPrefix: false,
+ });
+
+ module.setTags(['tf-modules/test-module/v1.2.3']);
+ module.addCommit({
+ sha: 'abc123',
+ message: 'fix: bug fix',
+ files: ['main.tf'],
+ });
+
+ expect(module.getReleaseTagVersion()).toBe('1.2.4'); // No 'v' prefix
+ });
});
describe('getReleaseTag()', () => {
@@ -885,44 +949,222 @@ describe('TerraformModule', () => {
describe('static utilities', () => {
describe('getTerraformModuleNameFromRelativePath()', () => {
- it('should generate valid module names from paths', () => {
- expect(TerraformModule.getTerraformModuleNameFromRelativePath('tf-modules/simple-module')).toBe(
- 'tf-modules/simple-module',
- );
+ beforeEach(() => {
+ // Reset to default config for each test
+ config.set({
+ tagDirectorySeparator: '/',
+ majorKeywords: ['BREAKING CHANGE', 'major change'],
+ minorKeywords: ['feat:', 'feature:'],
+ defaultFirstTag: 'v0.1.0',
+ moduleChangeExcludePatterns: [],
+ modulePathIgnore: [],
+ useVersionPrefix: true,
+ });
+ });
- expect(TerraformModule.getTerraformModuleNameFromRelativePath('complex_module-name.with/chars')).toBe(
- 'complex_module-name-with/chars',
- );
+ describe('with different tag directory separators', () => {
+ it('should use forward slash separator by default', () => {
+ config.set({ tagDirectorySeparator: '/' });
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('tf-modules/simple-module')).toBe(
+ 'tf-modules/simple-module',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('complex\\module\\windows\\path')).toBe(
+ 'complex/module/windows/path',
+ );
+ });
- expect(TerraformModule.getTerraformModuleNameFromRelativePath('/leading/slash/')).toBe('leading/slash');
+ it('should use hyphen separator when configured', () => {
+ config.set({ tagDirectorySeparator: '-' });
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('tf-modules/simple-module')).toBe(
+ 'tf-modules-simple-module',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('complex\\module\\windows\\path')).toBe(
+ 'complex-module-windows-path',
+ );
+ });
- expect(TerraformModule.getTerraformModuleNameFromRelativePath('module...with...dots')).toBe('module-with-dots');
- });
+ it('should use underscore separator when configured', () => {
+ config.set({ tagDirectorySeparator: '_' });
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('tf-modules/simple-module')).toBe(
+ 'tf-modules_simple-module',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('complex\\module\\windows\\path')).toBe(
+ 'complex_module_windows_path',
+ );
+ });
- it('should handle leading and trailing slashes', () => {
- expect(TerraformModule.getTerraformModuleNameFromRelativePath('/test-module/')).toBe('test-module');
+ it('should use dot separator when configured', () => {
+ config.set({ tagDirectorySeparator: '.' });
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('tf-modules/simple-module')).toBe(
+ 'tf-modules.simple-module',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('complex\\module\\windows\\path')).toBe(
+ 'complex.module.windows.path',
+ );
+ });
});
- it('should handle multiple consecutive slashes', () => {
- expect(TerraformModule.getTerraformModuleNameFromRelativePath('tf-modules//vpc//endpoint')).toBe(
- 'tf-modules/vpc/endpoint',
- );
- });
+ describe('character normalization and cleanup', () => {
+ beforeEach(() => {
+ config.set({ tagDirectorySeparator: '/' });
+ });
- it('should handle whitespace', () => {
- expect(TerraformModule.getTerraformModuleNameFromRelativePath(' test module ')).toBe('test-module');
- });
+ it('should normalize Windows backslashes to configured separator', () => {
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('windows\\path\\module')).toBe(
+ 'windows/path/module',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('mixed\\and/path\\separators')).toBe(
+ 'mixed/and/path/separators',
+ );
+ });
- it('should convert to lowercase', () => {
- expect(TerraformModule.getTerraformModuleNameFromRelativePath('Test-Module')).toBe('test-module');
- });
+ it('should convert to lowercase', () => {
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('Test-Module')).toBe('test-module');
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('UPPERCASE/MODULE')).toBe('uppercase/module');
+ });
+
+ it('should replace invalid characters with hyphens', () => {
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('test@module!#$')).toBe('test-module');
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('module%with&special*chars')).toBe(
+ 'module-with-special-chars',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('test module with spaces')).toBe(
+ 'test-module-with-spaces',
+ );
+ });
+
+ it('should normalize consecutive special characters', () => {
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('module...with...dots')).toBe(
+ 'module.with.dots',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('tf-modules//vpc//endpoint')).toBe(
+ 'tf-modules/vpc/endpoint',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('module---with---hyphens')).toBe(
+ 'module-with-hyphens',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('module___with___underscores')).toBe(
+ 'module_with_underscores',
+ );
+ });
- it('should clean up invalid characters', () => {
- expect(TerraformModule.getTerraformModuleNameFromRelativePath('test@module!#$')).toBe('test-module');
+ it('should remove leading and trailing special characters', () => {
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('/leading/slash/')).toBe('leading/slash');
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('...leading.dots')).toBe('leading.dots');
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('trailing.dots...')).toBe('trailing.dots');
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('---leading-hyphens')).toBe('leading-hyphens');
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('trailing-hyphens---')).toBe(
+ 'trailing-hyphens',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('___leading_underscores')).toBe(
+ 'leading_underscores',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('trailing_underscores___')).toBe(
+ 'trailing_underscores',
+ );
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('/.-_mixed_leading')).toBe('mixed_leading');
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('mixed_trailing_.-/')).toBe('mixed_trailing');
+ });
+
+ it('should handle edge cases', () => {
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath(' whitespace ')).toBe('whitespace');
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('/test-module/')).toBe('test-module');
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('single')).toBe('single');
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath('a')).toBe('a');
+ });
});
- it('should remove trailing special characters', () => {
- expect(TerraformModule.getTerraformModuleNameFromRelativePath('test-module-.')).toBe('test-module');
+ describe('comprehensive scenarios with different separators', () => {
+ const testScenarios = [
+ {
+ separator: '/',
+ input: 'tf-modules/aws/vpc-endpoint',
+ expected: 'tf-modules/aws/vpc-endpoint',
+ },
+ {
+ separator: '-',
+ input: 'tf-modules/aws/vpc-endpoint',
+ expected: 'tf-modules-aws-vpc-endpoint',
+ },
+ {
+ separator: '_',
+ input: 'tf-modules/aws/vpc-endpoint',
+ expected: 'tf-modules_aws_vpc-endpoint',
+ },
+ {
+ separator: '.',
+ input: 'tf-modules/aws/vpc-endpoint',
+ expected: 'tf-modules.aws.vpc-endpoint',
+ },
+ ];
+
+ for (const { separator, input, expected } of testScenarios) {
+ it(`should handle complex paths with ${separator} separator`, () => {
+ config.set({ tagDirectorySeparator: separator });
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath(input)).toBe(expected);
+ });
+ }
+
+ const complexTestScenarios = [
+ {
+ separator: '/',
+ input: '//tf-modules//aws..vpc--endpoint__',
+ expected: 'tf-modules/aws.vpc-endpoint',
+ },
+ {
+ separator: '-',
+ input: '//tf-modules//aws..vpc--endpoint__',
+ expected: 'tf-modules-aws.vpc-endpoint',
+ },
+ {
+ separator: '_',
+ input: '//tf-modules//aws..vpc--endpoint__',
+ expected: 'tf-modules_aws.vpc-endpoint',
+ },
+ {
+ separator: '.',
+ input: '//tf-modules//aws..vpc--endpoint__',
+ expected: 'tf-modules.aws.vpc-endpoint',
+ },
+ ];
+
+ for (const { separator, input, expected } of complexTestScenarios) {
+ it(`should handle complex normalization with ${separator} separator`, () => {
+ config.set({ tagDirectorySeparator: separator });
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath(input)).toBe(expected);
+ });
+ }
+ });
+
+ describe('real-world terraform module scenarios', () => {
+ it('should handle typical terraform module paths', () => {
+ config.set({ tagDirectorySeparator: '/' });
+
+ const testCases = [
+ { input: 'modules/networking/vpc', expected: 'modules/networking/vpc' },
+ { input: 'modules/compute/ec2-instance', expected: 'modules/compute/ec2-instance' },
+ { input: 'modules/storage/s3-bucket', expected: 'modules/storage/s3-bucket' },
+ { input: 'terraform/aws/rds_cluster', expected: 'terraform/aws/rds_cluster' },
+ { input: 'tf-modules/azure/storage.account', expected: 'tf-modules/azure/storage.account' },
+ ];
+
+ for (const { input, expected } of testCases) {
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath(input)).toBe(expected);
+ }
+ });
+
+ it('should handle module paths with various separators configured', () => {
+ const separatorTests = [
+ { separator: '-', input: 'modules/aws/vpc', expected: 'modules-aws-vpc' },
+ { separator: '_', input: 'modules/aws/vpc', expected: 'modules_aws_vpc' },
+ { separator: '.', input: 'modules/aws/vpc', expected: 'modules.aws.vpc' },
+ ];
+
+ for (const { separator, input, expected } of separatorTests) {
+ config.set({ tagDirectorySeparator: separator });
+ expect(TerraformModule.getTerraformModuleNameFromRelativePath(input)).toBe(expected);
+ }
+ });
});
});
@@ -954,17 +1196,48 @@ describe('TerraformModule', () => {
TerraformModule.isModuleAssociatedWithTag('tf-modules/vpc-endpoint', 'tf-modules/vpc-endpoint/v1.0.0'),
).toBe(true);
expect(
- TerraformModule.isModuleAssociatedWithTag('tf-modules/vpc-endpoint', 'tf-modules/vpc-endpoint/1.0.0'),
+ TerraformModule.isModuleAssociatedWithTag('tf-modules/vpc-endpoint', 'tf-modules-vpc-endpoint-v1.0.0'),
+ ).toBe(true);
+ expect(
+ TerraformModule.isModuleAssociatedWithTag('tf-modules/vpc-endpoint', 'tf-modules_vpc_endpoint_v1.0.0'),
+ ).toBe(true);
+ expect(
+ TerraformModule.isModuleAssociatedWithTag('tf-modules/vpc-endpoint', 'tf-modules.vpc.endpoint.v1.0.0'),
).toBe(true);
- expect(TerraformModule.isModuleAssociatedWithTag('tf-modules/vpc-endpoint', 'tf-modules/vpc/v1.0.0')).toBe(
- false,
- );
});
it('should be case sensitive', () => {
expect(TerraformModule.isModuleAssociatedWithTag('my-module', 'My-Module/v1.0.0')).toBe(false);
expect(TerraformModule.isModuleAssociatedWithTag('my-module', 'my-module/V1.0.0')).toBe(false);
});
+
+ it('should handle tags with different directory separators', () => {
+ // Test that tags with different separators are properly associated after normalization
+ expect(TerraformModule.isModuleAssociatedWithTag('my-module', 'my-module/v1.0.0')).toBe(true);
+ expect(TerraformModule.isModuleAssociatedWithTag('my-module', 'my-module-v1.0.0')).toBe(true);
+ expect(TerraformModule.isModuleAssociatedWithTag('my-module', 'my-module_v1.0.0')).toBe(true);
+ expect(TerraformModule.isModuleAssociatedWithTag('my-module', 'my-module.v1.0.0')).toBe(true);
+
+ // Test complex module names with separators
+ expect(
+ TerraformModule.isModuleAssociatedWithTag('tf-modules/vpc-endpoint', 'tf-modules/vpc-endpoint/v1.0.0'),
+ ).toBe(true);
+ expect(
+ TerraformModule.isModuleAssociatedWithTag('tf-modules/vpc-endpoint', 'tf-modules-vpc-endpoint-v1.0.0'),
+ ).toBe(true);
+ expect(
+ TerraformModule.isModuleAssociatedWithTag('tf-modules/vpc-endpoint', 'tf-modules_vpc_endpoint_v1.0.0'),
+ ).toBe(true);
+ expect(
+ TerraformModule.isModuleAssociatedWithTag('tf-modules/vpc-endpoint', 'tf-modules.vpc.endpoint.v1.0.0'),
+ ).toBe(true);
+
+ // Test that wrong associations still return false
+ expect(TerraformModule.isModuleAssociatedWithTag('my-module', 'other-module/v1.0.0')).toBe(false);
+ expect(TerraformModule.isModuleAssociatedWithTag('my-module', 'other-module-v1.0.0')).toBe(false);
+ expect(TerraformModule.isModuleAssociatedWithTag('my-module', 'other-module_v1.0.0')).toBe(false);
+ expect(TerraformModule.isModuleAssociatedWithTag('my-module', 'other-module.v1.0.0')).toBe(false);
+ });
});
describe('getTagsForModule()', () => {
@@ -1147,6 +1420,45 @@ describe('TerraformModule', () => {
expect(tagsToDelete).toEqual(['apple-module/v1.0.0', 'banana-module/v1.0.0', 'zebra-module/v1.0.0']);
});
+
+ it('should handle tags with different directory separators for same module', () => {
+ // Scenario: Module was originally using / separator, but tags exist with various separators
+ const allTags = [
+ 'test-module/v1.0.0', // Forward slash (current format)
+ 'test-module-v1.1.0', // Hyphen (old format)
+ 'test-module_v1.2.0', // Underscore (old format)
+ 'test-module.v1.3.0', // Dot (old format)
+ 'other-module/v1.0.0', // Different module that no longer exists
+ ];
+ const existingModules = [createMockTerraformModule({ directory: join(tmpDir, 'test-module') })];
+
+ const tagsToDelete = TerraformModule.getTagsToDelete(allTags, existingModules);
+
+ // Only tags for non-existent modules should be deleted
+ // All test-module tags should be kept regardless of separator
+ expect(tagsToDelete).toEqual(['other-module/v1.0.0']);
+ });
+
+ it('should handle complex module names with various separators', () => {
+ const allTags = [
+ 'tf-modules/vpc-endpoint/v1.0.0', // Current format
+ 'tf-modules-vpc-endpoint-v1.1.0', // All hyphens
+ 'tf-modules_vpc_endpoint_v1.2.0', // All underscores
+ 'tf-modules.vpc.endpoint.v1.3.0', // All dots
+ 'tf-modules/vpc-endpoint-v1.4.0', // Mixed separators
+ 'removed-module/v1.0.0', // Module that no longer exists
+ ];
+ const existingModules = [
+ createMockTerraformModule({
+ directory: join(tmpDir, 'tf-modules', 'vpc-endpoint'),
+ }),
+ ];
+
+ const tagsToDelete = TerraformModule.getTagsToDelete(allTags, existingModules);
+
+ // Only tags for non-existent modules should be deleted
+ expect(tagsToDelete).toEqual(['removed-module/v1.0.0']);
+ });
});
describe('getReleasesToDelete()', () => {
@@ -1536,6 +1848,102 @@ describe('TerraformModule', () => {
expect(releasesToDelete).toHaveLength(2);
expect(releasesToDelete.map((r) => r.tagName)).toEqual(['legacy-module/v1.0.0', 'legacy-module/v1.2.0']);
});
+
+ it('should handle releases with different directory separators for same module', () => {
+ // Scenario: Module was originally using / separator, but releases exist with various separators
+ const allReleases: GitHubRelease[] = [
+ {
+ id: 1,
+ title: 'test-module/v1.0.0',
+ tagName: 'test-module/v1.0.0',
+ body: 'Forward slash format',
+ },
+ {
+ id: 2,
+ title: 'test-module-v1.1.0',
+ tagName: 'test-module-v1.1.0',
+ body: 'Hyphen format',
+ },
+ {
+ id: 3,
+ title: 'test-module_v1.2.0',
+ tagName: 'test-module_v1.2.0',
+ body: 'Underscore format',
+ },
+ {
+ id: 4,
+ title: 'test-module.v1.3.0',
+ tagName: 'test-module.v1.3.0',
+ body: 'Dot format',
+ },
+ {
+ id: 5,
+ title: 'other-module/v1.0.0',
+ tagName: 'other-module/v1.0.0',
+ body: 'Different module that no longer exists',
+ },
+ ];
+ const existingModules = [createMockTerraformModule({ directory: join(tmpDir, 'test-module') })];
+
+ const releasesToDelete = TerraformModule.getReleasesToDelete(allReleases, existingModules);
+
+ // Only releases for non-existent modules should be deleted
+ // All test-module releases should be kept regardless of separator
+ expect(releasesToDelete).toHaveLength(1);
+ expect(releasesToDelete[0].tagName).toBe('other-module/v1.0.0');
+ });
+
+ it('should handle complex module names with various separators in releases', () => {
+ const allReleases: GitHubRelease[] = [
+ {
+ id: 1,
+ title: 'tf-modules/vpc-endpoint/v1.0.0',
+ tagName: 'tf-modules/vpc-endpoint/v1.0.0',
+ body: 'Current format',
+ },
+ {
+ id: 2,
+ title: 'tf-modules-vpc-endpoint-v1.1.0',
+ tagName: 'tf-modules-vpc-endpoint-v1.1.0',
+ body: 'All hyphens',
+ },
+ {
+ id: 3,
+ title: 'tf-modules_vpc_endpoint_v1.2.0',
+ tagName: 'tf-modules_vpc_endpoint_v1.2.0',
+ body: 'All underscores',
+ },
+ {
+ id: 4,
+ title: 'tf-modules.vpc.endpoint.v1.3.0',
+ tagName: 'tf-modules.vpc.endpoint.v1.3.0',
+ body: 'All dots',
+ },
+ {
+ id: 5,
+ title: 'tf-modules/vpc-endpoint-v1.4.0',
+ tagName: 'tf-modules/vpc-endpoint-v1.4.0',
+ body: 'Mixed separators',
+ },
+ {
+ id: 6,
+ title: 'removed-module/v1.0.0',
+ tagName: 'removed-module/v1.0.0',
+ body: 'Module that no longer exists',
+ },
+ ];
+ const existingModules = [
+ createMockTerraformModule({
+ directory: join(tmpDir, 'tf-modules', 'vpc-endpoint'),
+ }),
+ ];
+
+ const releasesToDelete = TerraformModule.getReleasesToDelete(allReleases, existingModules);
+
+ // Only releases for non-existent modules should be deleted
+ expect(releasesToDelete).toHaveLength(1);
+ expect(releasesToDelete[0].tagName).toBe('removed-module/v1.0.0');
+ });
});
// Test private helper methods via the public interface
diff --git a/__tests__/utils/constants.test.ts b/__tests__/utils/constants.test.ts
index af782714..abbde3bd 100644
--- a/__tests__/utils/constants.test.ts
+++ b/__tests__/utils/constants.test.ts
@@ -1,4 +1,7 @@
import {
+ VALID_TAG_DIRECTORY_SEPARATORS,
+ VERSION_TAG_REGEX,
+ MODULE_TAG_REGEX,
BRANDING_COMMENT,
BRANDING_WIKI,
GITHUB_ACTIONS_BOT_NAME,
@@ -11,6 +14,18 @@ import {
import { describe, expect, it } from 'vitest';
describe('utils/constants', () => {
+ it('should have the correct default separators', () => {
+ expect(VALID_TAG_DIRECTORY_SEPARATORS).toStrictEqual(['-', '_', '/', '.']);
+ });
+
+ it('should have the correct version tag regex', () => {
+ expect(VERSION_TAG_REGEX).toStrictEqual(/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/);
+ });
+
+ it('should have the correct module tag regex', () => {
+ expect(MODULE_TAG_REGEX).toStrictEqual(/^(.+)([-_/.])(v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*))$/);
+ });
+
it('should have the correct GitHub Actions bot name', () => {
expect(GITHUB_ACTIONS_BOT_NAME).toBe('GitHub Actions');
});
diff --git a/__tests__/utils/file.test.ts b/__tests__/utils/file.test.ts
index 558f46ff..989a42a2 100644
--- a/__tests__/utils/file.test.ts
+++ b/__tests__/utils/file.test.ts
@@ -619,7 +619,7 @@ describe('utils/file', () => {
// Create terraform file above workspace (if possible)
try {
writeFileSync(terraformFileAbove, 'resource "test" "example" {}');
- } catch (error) {
+ } catch (_error) {
// Skip this test if we can't write above tmpDir
return;
}
@@ -635,7 +635,7 @@ describe('utils/file', () => {
// Cleanup
try {
rmSync(terraformFileAbove);
- } catch (error) {
+ } catch (_error) {
// Ignore cleanup errors
}
});
diff --git a/__tests__/utils/metadata.test.ts b/__tests__/utils/metadata.test.ts
new file mode 100644
index 00000000..e4847a99
--- /dev/null
+++ b/__tests__/utils/metadata.test.ts
@@ -0,0 +1,172 @@
+import { ACTION_INPUTS, createConfigFromInputs } from '@/utils/metadata';
+import type { ActionInputMetadata } from '@/types';
+import { getInput } from '@actions/core';
+import { describe, expect, it, vi } from 'vitest';
+
+describe('utils/metadata', () => {
+ describe('ACTION_INPUTS', () => {
+ it('should contain all expected input configurations', () => {
+ const expectedInputs = [
+ 'major-keywords',
+ 'minor-keywords',
+ 'patch-keywords',
+ 'default-first-tag',
+ 'terraform-docs-version',
+ 'delete-legacy-tags',
+ 'disable-wiki',
+ 'wiki-sidebar-changelog-max',
+ 'wiki-usage-template',
+ 'disable-branding',
+ 'module-path-ignore',
+ 'module-change-exclude-patterns',
+ 'module-asset-exclude-patterns',
+ 'use-ssh-source-format',
+ 'github_token',
+ 'tag-directory-separator',
+ 'use-version-prefix',
+ ];
+
+ expect(Object.keys(ACTION_INPUTS)).toEqual(expect.arrayContaining(expectedInputs));
+ expect(Object.keys(ACTION_INPUTS)).toHaveLength(expectedInputs.length);
+ });
+
+ it('should have correct metadata structure for required string inputs', () => {
+ const stringInputs = ['default-first-tag', 'terraform-docs-version', 'github_token', 'tag-directory-separator'];
+
+ for (const inputName of stringInputs) {
+ const metadata = ACTION_INPUTS[inputName];
+ expect(metadata).toEqual({
+ configKey: expect.any(String),
+ required: true,
+ type: 'string',
+ });
+ }
+ });
+
+ it('should have correct metadata structure for required boolean inputs', () => {
+ const booleanInputs = [
+ 'delete-legacy-tags',
+ 'disable-wiki',
+ 'disable-branding',
+ 'use-ssh-source-format',
+ 'use-version-prefix',
+ ];
+
+ for (const inputName of booleanInputs) {
+ const metadata = ACTION_INPUTS[inputName];
+ expect(metadata).toEqual({
+ configKey: expect.any(String),
+ required: true,
+ type: 'boolean',
+ });
+ }
+ });
+
+ it('should have correct metadata structure for required array inputs', () => {
+ const arrayInputs = ['major-keywords', 'minor-keywords', 'patch-keywords'];
+
+ for (const inputName of arrayInputs) {
+ const metadata = ACTION_INPUTS[inputName];
+ expect(metadata).toEqual({
+ configKey: expect.any(String),
+ required: true,
+ type: 'array',
+ });
+ }
+ });
+
+ it('should have correct metadata structure for required number inputs', () => {
+ const numberInputs = ['wiki-sidebar-changelog-max'];
+
+ for (const inputName of numberInputs) {
+ const metadata = ACTION_INPUTS[inputName];
+ expect(metadata).toEqual({
+ configKey: expect.any(String),
+ required: true,
+ type: 'number',
+ });
+ }
+ });
+
+ it('should have correct metadata structure for optional array inputs', () => {
+ const optionalArrayInputs = [
+ 'module-path-ignore',
+ 'module-change-exclude-patterns',
+ 'module-asset-exclude-patterns',
+ ];
+
+ for (const inputName of optionalArrayInputs) {
+ const metadata = ACTION_INPUTS[inputName];
+ expect(metadata).toEqual({
+ configKey: expect.any(String),
+ required: false,
+ type: 'array',
+ });
+ }
+ });
+
+ it('should have proper configKey mappings', () => {
+ const expectedMappings: Record = {
+ 'major-keywords': 'majorKeywords',
+ 'minor-keywords': 'minorKeywords',
+ 'patch-keywords': 'patchKeywords',
+ 'default-first-tag': 'defaultFirstTag',
+ 'terraform-docs-version': 'terraformDocsVersion',
+ 'delete-legacy-tags': 'deleteLegacyTags',
+ 'disable-wiki': 'disableWiki',
+ 'wiki-sidebar-changelog-max': 'wikiSidebarChangelogMax',
+ 'disable-branding': 'disableBranding',
+ 'module-path-ignore': 'modulePathIgnore',
+ 'module-change-exclude-patterns': 'moduleChangeExcludePatterns',
+ 'module-asset-exclude-patterns': 'moduleAssetExcludePatterns',
+ 'use-ssh-source-format': 'useSSHSourceFormat',
+ github_token: 'githubToken',
+ 'tag-directory-separator': 'tagDirectorySeparator',
+ 'use-version-prefix': 'useVersionPrefix',
+ };
+
+ for (const [inputName, expectedConfigKey] of Object.entries(expectedMappings)) {
+ expect(ACTION_INPUTS[inputName].configKey).toBe(expectedConfigKey);
+ }
+ });
+
+ it('should maintain type safety with ActionInputMetadata interface', () => {
+ // This test ensures the factory functions create valid ActionInputMetadata objects
+ for (const metadata of Object.values(ACTION_INPUTS)) {
+ expect(metadata).toEqual(
+ expect.objectContaining({
+ configKey: expect.any(String),
+ required: expect.any(Boolean),
+ type: expect.stringMatching(/^(string|boolean|array|number)$/),
+ }),
+ );
+
+ // Ensure type is properly typed
+ const validTypes: ActionInputMetadata['type'][] = ['string', 'boolean', 'array', 'number'];
+ expect(validTypes).toContain(metadata.type);
+ }
+ });
+ });
+
+ describe('createConfigFromInputs', () => {
+ it('should throw a custom error if getInput fails', () => {
+ const errorMessage = 'Input retrieval failed';
+ vi.mocked(getInput).mockImplementation(() => {
+ throw new Error(errorMessage);
+ });
+
+ expect(() => createConfigFromInputs()).toThrow(`Failed to process input 'major-keywords': ${errorMessage}`);
+ });
+
+ it('should handle non-Error objects thrown during input processing', () => {
+ const errorObject = 'A plain string error';
+ vi.mocked(getInput).mockImplementation(() => {
+ throw errorObject;
+ });
+
+ expect(() => createConfigFromInputs()).toThrow(
+ `Failed to process input 'major-keywords': ${String(errorObject)}`,
+ );
+ });
+ });
+});
diff --git a/__tests__/utils/string.test.ts b/__tests__/utils/string.test.ts
index b2ce45d7..6d95e89a 100644
--- a/__tests__/utils/string.test.ts
+++ b/__tests__/utils/string.test.ts
@@ -1,36 +1,49 @@
-import { removeTrailingCharacters, trimSlashes } from '@/utils/string';
+import { removeLeadingCharacters, removeTrailingCharacters, renderTemplate } from '@/utils/string';
import { describe, expect, it } from 'vitest';
describe('utils/string', () => {
- describe('trimSlashes', () => {
- it('should remove leading and trailing slashes while preserving internal ones', () => {
- const testCases = [
- { input: '/example/path/', expected: 'example/path' },
- { input: '///another/example///', expected: 'another/example' },
- { input: 'no/slashes', expected: 'no/slashes' },
- { input: '/', expected: '' },
- { input: '//', expected: '' },
- { input: '', expected: '' },
- { input: '/single/', expected: 'single' },
- { input: 'leading/', expected: 'leading' },
- { input: '/trailing', expected: 'trailing' },
- { input: '////multiple////slashes////', expected: 'multiple////slashes' },
- ];
- for (const { input, expected } of testCases) {
- expect(trimSlashes(input)).toBe(expected);
- }
+ describe('removeLeadingCharacters', () => {
+ it('should remove leading dots', () => {
+ expect(removeLeadingCharacters('...hello', ['.'])).toBe('hello');
+ expect(removeLeadingCharacters('..module-name', ['.'])).toBe('module-name');
+ expect(removeLeadingCharacters('.....test', ['.'])).toBe('test');
});
- it('should handle strings without any slashes', () => {
- expect(trimSlashes('hello')).toBe('hello');
+ it('should remove leading hyphens and underscores', () => {
+ expect(removeLeadingCharacters('--module-name', ['-'])).toBe('module-name');
+ expect(removeLeadingCharacters('__module_name', ['_'])).toBe('module_name');
+ expect(removeLeadingCharacters('-_module-name', ['-', '_'])).toBe('module-name');
});
- it('should return empty string when given only slashes', () => {
- expect(trimSlashes('//////')).toBe('');
+ it('should remove multiple leading character types', () => {
+ expect(removeLeadingCharacters('._-module-name', ['.', '-', '_'])).toBe('module-name');
+ expect(removeLeadingCharacters('.--__test', ['.', '-', '_'])).toBe('test');
+ expect(removeLeadingCharacters('___...---example', ['.', '-', '_'])).toBe('example');
});
- it('should preserve internal multiple slashes', () => {
- expect(trimSlashes('/path//with///internal////slashes/')).toBe('path//with///internal////slashes');
+ it('should preserve internal characters', () => {
+ expect(removeLeadingCharacters('.hello.world', ['.'])).toBe('hello.world');
+ expect(removeLeadingCharacters('.-module-name.test', ['.', '-'])).toBe('module-name.test');
+ expect(removeLeadingCharacters('_test_module_name', ['_'])).toBe('test_module_name');
+ });
+
+ it('should handle edge cases', () => {
+ expect(removeLeadingCharacters('', ['.'])).toBe('');
+ expect(removeLeadingCharacters('...', ['.'])).toBe('');
+ expect(removeLeadingCharacters('---', ['-'])).toBe('');
+ expect(removeLeadingCharacters('hello', ['.', '-', '_'])).toBe('hello');
+ expect(removeLeadingCharacters('module', [])).toBe('module');
+ });
+
+ it('should handle complex terraform module names', () => {
+ expect(removeLeadingCharacters('._-aws-vpc-module', ['.', '-', '_'])).toBe('aws-vpc-module');
+ expect(removeLeadingCharacters('--tf-modules/vpc-endpoint', ['-', '_'])).toBe('tf-modules/vpc-endpoint');
+ expect(removeLeadingCharacters('__modules/networking/vpc', ['_'])).toBe('modules/networking/vpc');
+ });
+
+ it('should handle forward slashes in leading characters', () => {
+ expect(removeLeadingCharacters('/./module-name', ['/', '.'])).toBe('module-name');
+ expect(removeLeadingCharacters('/./_-example', ['/', '.', '_', '-'])).toBe('example');
});
});
@@ -72,5 +85,96 @@ describe('utils/string', () => {
expect(removeTrailingCharacters('tf-modules/vpc-endpoint--', ['-', '_'])).toBe('tf-modules/vpc-endpoint');
expect(removeTrailingCharacters('modules/networking/vpc__', ['_'])).toBe('modules/networking/vpc');
});
+
+ it('should handle forward slashes in trailing characters', () => {
+ expect(removeTrailingCharacters('module-name/.', ['/', '.'])).toBe('module-name');
+ expect(removeTrailingCharacters('example-_./', ['/', '.', '_', '-'])).toBe('example');
+ });
+ });
+
+ describe('renderTemplate', () => {
+ it('should replace a single placeholder', () => {
+ const template = 'Hello, {{name}}!';
+ const variables = { name: 'World' };
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('Hello, World!');
+ });
+
+ it('should replace multiple placeholders', () => {
+ const template = '{{greeting}}, {{name}}!';
+ const variables = { greeting: 'Hi', name: 'There' };
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('Hi, There!');
+ });
+
+ it('should handle templates with no placeholders', () => {
+ const template = 'Just a plain string.';
+ const variables = { name: 'World' };
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('Just a plain string.');
+ });
+
+ it('should handle empty string values', () => {
+ const template = 'A{{key}}B';
+ const variables = { key: '' };
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('AB');
+ });
+
+ it('should leave unmapped placeholders untouched', () => {
+ const template = 'Hello, {{name}} and {{unmapped}}!';
+ const variables = { name: 'World' };
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('Hello, World and {{unmapped}}!');
+ });
+
+ it('should handle complex templates with multiple variables', () => {
+ const template = 'Module: {{module}}, Version: {{version}}, Author: {{author}}';
+ const variables = { module: 'vpc-endpoint', version: '1.0.0', author: 'TechPivot' };
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('Module: vpc-endpoint, Version: 1.0.0, Author: TechPivot');
+ });
+
+ it('should handle numeric values as strings', () => {
+ const template = 'Port: {{port}}, Count: {{count}}';
+ const variables = { port: '8080', count: '3' };
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('Port: 8080, Count: 3');
+ });
+
+ it('should handle special characters in values', () => {
+ const template = 'Path: {{path}}, Command: {{cmd}}';
+ const variables = { path: '/opt/bin/terraform', cmd: 'terraform init -backend=false' };
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('Path: /opt/bin/terraform, Command: terraform init -backend=false');
+ });
+
+ it('should handle empty template', () => {
+ const template = '';
+ const variables = { name: 'World' };
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('');
+ });
+
+ it('should handle empty variables object', () => {
+ const template = 'Hello, {{name}}!';
+ const variables = {};
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('Hello, {{name}}!');
+ });
+
+ it('should handle placeholders with different casing', () => {
+ const template = 'Hello, {{Name}} and {{NAME}}!';
+ const variables = { Name: 'World', NAME: 'UNIVERSE' };
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('Hello, World and UNIVERSE!');
+ });
+
+ it('should handle placeholders with numbers', () => {
+ const template = 'Item {{item1}} and {{item2}}';
+ const variables = { item1: 'first', item2: 'second' };
+ const result = renderTemplate(template, variables);
+ expect(result).toBe('Item first and second');
+ });
});
});
diff --git a/__tests__/wiki.test.ts b/__tests__/wiki.test.ts
index 2b003ba4..be0fdc0e 100644
--- a/__tests__/wiki.test.ts
+++ b/__tests__/wiki.test.ts
@@ -103,7 +103,7 @@ describe('wiki', async () => {
it('should handle unsetting config extraheader and throwing error accordingly', () => {
const mockExecFileSync = vi.fn(
- (command: string, args?: readonly string[] | undefined, options?: ExecFileSyncOptions) => {
+ (_command: string, args?: readonly string[] | undefined, _options?: ExecFileSyncOptions) => {
if (args?.includes('--unset-all') && args.includes('http.https://github.com/.extraheader')) {
const error = new Error('git config error') as ExecSyncError;
error.status = 10;
@@ -131,7 +131,7 @@ describe('wiki', async () => {
it('should handle unsetting config extraheader gracefully', () => {
const mockExecFileSync = vi.fn(
- (command: string, args?: readonly string[] | undefined, options?: ExecFileSyncOptions) => {
+ (_command: string, args?: readonly string[] | undefined, _options?: ExecFileSyncOptions) => {
if (args?.includes('--unset-all') && args.includes('http.https://github.com/.extraheader')) {
const error = new Error('git config error') as ExecSyncError;
error.status = 5;
@@ -168,7 +168,7 @@ describe('wiki', async () => {
// Reset mocks and configure remote command to return "origin"
vi.clearAllMocks();
- vi.mocked(execFileSync).mockImplementation((cmd, args = []) => {
+ vi.mocked(execFileSync).mockImplementation((_cmd, args = []) => {
if (args[0] === 'remote') {
return Buffer.from('origin');
}
@@ -305,7 +305,7 @@ describe('wiki', async () => {
basename(file) !== '_Footer.md'
) {
const content = readFileSync(file, 'utf8');
- const moduleName = basename(file, '.md');
+ const _moduleName = basename(file, '.md');
expect(content).toContain(`# Usage\n\nModule: ${terraformModule.name}, Missing: {{missing_variable}}`);
}
}
diff --git a/action.yml b/action.yml
index 958186ba..c51c135b 100644
--- a/action.yml
+++ b/action.yml
@@ -51,6 +51,19 @@ inputs:
Adjust this value to control the visibility of changelog entries in the module sidebar.
required: true
default: "5"
+ wiki-usage-template:
+ description: A raw, multi-line string to override the default 'Usage' section in the generated wiki. If not provided, a default usage block will be generated.
+ required: false
+ default: |
+ To use this module in your Terraform, refer to the below module example:
+
+ ```hcl
+ module "{{module_name_terraform}}" {
+ source = "git::{{module_source}}?ref={{latest_tag}}"
+
+ # See inputs below for additional required parameters
+ }
+ ```
disable-branding:
description: >
Flag to control whether the small branding link should be disabled or not in the
@@ -102,19 +115,6 @@ inputs:
If enabled, all links to source code in generated Wiki documentation will use SSH format instead of HTTPS format.
required: true
default: "false"
- wiki-usage-template:
- description: A raw, multi-line string to override the default 'Usage' section in the generated wiki. If not provided, a default usage block will be generated.
- required: false
- default: |
- To use this module in your Terraform, refer to the below module example:
-
- ```hcl
- module "{{module_name_terraform}}" {
- source = "git::{{module_source}}?ref={{latest_tag}}"
-
- # See inputs below for additional required parameters
- }
- ```
github_token:
description: >
Required for retrieving pull request metadata, tags, releases, updating PR comments, wiki, and creating
@@ -122,6 +122,27 @@ inputs:
specific requirements.
required: true
default: ${{ github.token }}
+ tag-directory-separator:
+ description: >
+ Character used to separate directory path components in Git tags. This separator is used to convert
+ module directory paths into tag names (e.g., 'modules/aws/s3-bucket' becomes 'modules-aws-s3-bucket-v1.0.0'
+ when using '-'). Must be a single character from: /, -, _, or .
+
+ Examples with different separators:
+ - "/" (default): modules/aws/s3-bucket/v1.0.0
+ - "-": modules-aws-s3-bucket-v1.0.0
+ - "_": modules_aws_s3_bucket_v1.0.0
+ - ".": modules.aws.s3.bucket.v1.0.0
+ required: true
+ default: /
+ use-version-prefix:
+ description: >
+ Whether to include the 'v' prefix on version tags (e.g., v1.2.3 vs 1.2.3). When enabled, all new version
+ tags will include the 'v' prefix. For initial releases, this setting takes precedence over any 'v' prefix
+ specified in the default-first-tag - if use-version-prefix is false and default-first-tag contains 'v',
+ the 'v' will be automatically removed to ensure consistency.
+ required: true
+ default: "true"
outputs:
changed-module-names:
diff --git a/biome.json b/biome.json
index 3d7ea7c8..7ed801a8 100644
--- a/biome.json
+++ b/biome.json
@@ -1,12 +1,15 @@
{
- "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
+ "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
+ "assist": {
+ "enabled": false
+ },
"files": {
- "ignore": ["dist", "node_modules"]
+ "includes": ["*.md", "*.ts", "__mocks__/**/*.ts", "__tests__/**/*.ts", "src/**/*.ts", "scripts/**/*.ts"]
},
"formatter": {
"enabled": true,
@@ -24,9 +27,6 @@
}
}
},
- "organizeImports": {
- "enabled": true
- },
"javascript": {
"formatter": {
"enabled": true,
diff --git a/package-lock.json b/package-lock.json
index 290b2ee1..e146f53d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,20 +15,22 @@
"@octokit/plugin-rest-endpoint-methods": "^16.0.0",
"@octokit/request-error": "^7.0.0",
"minimatch": "^10.0.1",
- "p-limit": "^6.2.0",
+ "p-limit": "^7.0.0",
"which": "^5.0.0"
},
"devDependencies": {
- "@biomejs/biome": "^1.9.4",
+ "@biomejs/biome": "^2.2.0",
"@octokit/types": "^14.0.0",
"@octokit/webhooks-types": "^7.6.1",
- "@types/node": "^22.15.29",
+ "@types/js-yaml": "^4.0.9",
+ "@types/node": "^22.17.2",
"@types/which": "^3.0.4",
"@vercel/ncc": "^0.38.3",
"@vitest/coverage-v8": "^3.1.3",
+ "js-yaml": "^4.1.0",
"make-coverage-badge": "^1.2.0",
- "openai": "*",
- "textlint": "^14.8.0",
+ "openai": "latest",
+ "textlint": "^15.2.1",
"textlint-filter-rule-comments": "^1.2.2",
"textlint-rule-terminology": "^5.2.12",
"ts-deepmerge": "^7.0.2",
@@ -106,6 +108,28 @@
"@azu/format-text": "^1.0.1"
}
},
+ "node_modules/@babel/code-frame": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+ "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
@@ -127,13 +151,13 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.27.5",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz",
- "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==",
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz",
+ "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.27.3"
+ "@babel/types": "^7.28.2"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -143,9 +167,9 @@
}
},
"node_modules/@babel/types": {
- "version": "7.27.6",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz",
- "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==",
+ "version": "7.28.2",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz",
+ "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -167,11 +191,10 @@
}
},
"node_modules/@biomejs/biome": {
- "version": "1.9.4",
- "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.4.tgz",
- "integrity": "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.0.tgz",
+ "integrity": "sha512-3On3RSYLsX+n9KnoSgfoYlckYBoU6VRM22cw1gB4Y0OuUVSYd/O/2saOJMrA4HFfA1Ff0eacOvMN1yAAvHtzIw==",
"dev": true,
- "hasInstallScript": true,
"license": "MIT OR Apache-2.0",
"bin": {
"biome": "bin/biome"
@@ -184,20 +207,20 @@
"url": "https://opencollective.com/biome"
},
"optionalDependencies": {
- "@biomejs/cli-darwin-arm64": "1.9.4",
- "@biomejs/cli-darwin-x64": "1.9.4",
- "@biomejs/cli-linux-arm64": "1.9.4",
- "@biomejs/cli-linux-arm64-musl": "1.9.4",
- "@biomejs/cli-linux-x64": "1.9.4",
- "@biomejs/cli-linux-x64-musl": "1.9.4",
- "@biomejs/cli-win32-arm64": "1.9.4",
- "@biomejs/cli-win32-x64": "1.9.4"
+ "@biomejs/cli-darwin-arm64": "2.2.0",
+ "@biomejs/cli-darwin-x64": "2.2.0",
+ "@biomejs/cli-linux-arm64": "2.2.0",
+ "@biomejs/cli-linux-arm64-musl": "2.2.0",
+ "@biomejs/cli-linux-x64": "2.2.0",
+ "@biomejs/cli-linux-x64-musl": "2.2.0",
+ "@biomejs/cli-win32-arm64": "2.2.0",
+ "@biomejs/cli-win32-x64": "2.2.0"
}
},
"node_modules/@biomejs/cli-darwin-arm64": {
- "version": "1.9.4",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz",
- "integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.0.tgz",
+ "integrity": "sha512-zKbwUUh+9uFmWfS8IFxmVD6XwqFcENjZvEyfOxHs1epjdH3wyyMQG80FGDsmauPwS2r5kXdEM0v/+dTIA9FXAg==",
"cpu": [
"arm64"
],
@@ -212,9 +235,9 @@
}
},
"node_modules/@biomejs/cli-darwin-x64": {
- "version": "1.9.4",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz",
- "integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.0.tgz",
+ "integrity": "sha512-+OmT4dsX2eTfhD5crUOPw3RPhaR+SKVspvGVmSdZ9y9O/AgL8pla6T4hOn1q+VAFBHuHhsdxDRJgFCSC7RaMOw==",
"cpu": [
"x64"
],
@@ -229,9 +252,9 @@
}
},
"node_modules/@biomejs/cli-linux-arm64": {
- "version": "1.9.4",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz",
- "integrity": "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.0.tgz",
+ "integrity": "sha512-6eoRdF2yW5FnW9Lpeivh7Mayhq0KDdaDMYOJnH9aT02KuSIX5V1HmWJCQQPwIQbhDh68Zrcpl8inRlTEan0SXw==",
"cpu": [
"arm64"
],
@@ -246,9 +269,9 @@
}
},
"node_modules/@biomejs/cli-linux-arm64-musl": {
- "version": "1.9.4",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz",
- "integrity": "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.0.tgz",
+ "integrity": "sha512-egKpOa+4FL9YO+SMUMLUvf543cprjevNc3CAgDNFLcjknuNMcZ0GLJYa3EGTCR2xIkIUJDVneBV3O9OcIlCEZQ==",
"cpu": [
"arm64"
],
@@ -263,9 +286,9 @@
}
},
"node_modules/@biomejs/cli-linux-x64": {
- "version": "1.9.4",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz",
- "integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.0.tgz",
+ "integrity": "sha512-5UmQx/OZAfJfi25zAnAGHUMuOd+LOsliIt119x2soA2gLggQYrVPA+2kMUxR6Mw5M1deUF/AWWP2qpxgH7Nyfw==",
"cpu": [
"x64"
],
@@ -280,9 +303,9 @@
}
},
"node_modules/@biomejs/cli-linux-x64-musl": {
- "version": "1.9.4",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz",
- "integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.0.tgz",
+ "integrity": "sha512-I5J85yWwUWpgJyC1CcytNSGusu2p9HjDnOPAFG4Y515hwRD0jpR9sT9/T1cKHtuCvEQ/sBvx+6zhz9l9wEJGAg==",
"cpu": [
"x64"
],
@@ -297,9 +320,9 @@
}
},
"node_modules/@biomejs/cli-win32-arm64": {
- "version": "1.9.4",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz",
- "integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.0.tgz",
+ "integrity": "sha512-n9a1/f2CwIDmNMNkFs+JI0ZjFnMO0jdOyGNtihgUNFnlmd84yIYY2KMTBmMV58ZlVHjgmY5Y6E1hVTnSRieggA==",
"cpu": [
"arm64"
],
@@ -314,9 +337,9 @@
}
},
"node_modules/@biomejs/cli-win32-x64": {
- "version": "1.9.4",
- "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz",
- "integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.0.tgz",
+ "integrity": "sha512-Nawu5nHjP/zPKTIryh2AavzTc/KEg4um/MxWdXW0A6P/RZOyIpa7+QSjeXwAwX/utJGaCoXRPWtF3m5U/bB3Ww==",
"cpu": [
"x64"
],
@@ -331,9 +354,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
- "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
+ "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==",
"cpu": [
"ppc64"
],
@@ -348,9 +371,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
- "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz",
+ "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==",
"cpu": [
"arm"
],
@@ -365,9 +388,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
- "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz",
+ "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==",
"cpu": [
"arm64"
],
@@ -382,9 +405,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
- "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz",
+ "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==",
"cpu": [
"x64"
],
@@ -399,9 +422,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
- "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz",
+ "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==",
"cpu": [
"arm64"
],
@@ -416,9 +439,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
- "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz",
+ "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==",
"cpu": [
"x64"
],
@@ -433,9 +456,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
- "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz",
+ "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==",
"cpu": [
"arm64"
],
@@ -450,9 +473,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
- "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz",
+ "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==",
"cpu": [
"x64"
],
@@ -467,9 +490,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
- "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz",
+ "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==",
"cpu": [
"arm"
],
@@ -484,9 +507,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
- "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz",
+ "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==",
"cpu": [
"arm64"
],
@@ -501,9 +524,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
- "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz",
+ "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==",
"cpu": [
"ia32"
],
@@ -518,9 +541,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
- "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz",
+ "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==",
"cpu": [
"loong64"
],
@@ -535,9 +558,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
- "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz",
+ "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==",
"cpu": [
"mips64el"
],
@@ -552,9 +575,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
- "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz",
+ "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==",
"cpu": [
"ppc64"
],
@@ -569,9 +592,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
- "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz",
+ "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==",
"cpu": [
"riscv64"
],
@@ -586,9 +609,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
- "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz",
+ "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==",
"cpu": [
"s390x"
],
@@ -603,9 +626,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
- "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz",
+ "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==",
"cpu": [
"x64"
],
@@ -620,9 +643,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
- "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz",
+ "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==",
"cpu": [
"arm64"
],
@@ -637,9 +660,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
- "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz",
+ "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==",
"cpu": [
"x64"
],
@@ -654,9 +677,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
- "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz",
+ "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==",
"cpu": [
"arm64"
],
@@ -671,9 +694,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
- "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz",
+ "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==",
"cpu": [
"x64"
],
@@ -687,10 +710,27 @@
"node": ">=18"
}
},
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz",
+ "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@esbuild/sunos-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
- "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz",
+ "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==",
"cpu": [
"x64"
],
@@ -705,9 +745,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
- "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz",
+ "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==",
"cpu": [
"arm64"
],
@@ -722,9 +762,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
- "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz",
+ "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==",
"cpu": [
"ia32"
],
@@ -739,9 +779,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
- "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz",
+ "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==",
"cpu": [
"x64"
],
@@ -764,6 +804,27 @@
"node": ">=14"
}
},
+ "node_modules/@isaacs/balanced-match": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
+ "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/@isaacs/brace-expansion": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
+ "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
+ "license": "MIT",
+ "dependencies": {
+ "@isaacs/balanced-match": "^4.0.1"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -793,18 +854,14 @@
}
},
"node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.8",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
- "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jridgewell/set-array": "^1.2.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
- },
- "engines": {
- "node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
@@ -817,27 +874,17 @@
"node": ">=6.0.0"
}
},
- "node_modules/@jridgewell/set-array": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
- "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6.0.0"
- }
- },
"node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
- "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.25",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
- "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+ "version": "0.3.30",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz",
+ "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -846,19 +893,16 @@
}
},
"node_modules/@keyv/serialize": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.0.3.tgz",
- "integrity": "sha512-qnEovoOp5Np2JDGonIDL6Ayihw0RhnRh6vxPuHo4RDn1UOzwEo4AeIfpL6UGIrsceWrCMiVPgwRjbHu4vYFc3g==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.0.tgz",
+ "integrity": "sha512-RlDgexML7Z63Q8BSaqhXdCYNBy/JQnqYIwxofUrNLGCblOMHp+xux2Q8nLMLlPpgHQPoU0Do8Z6btCpRBEqZ8g==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "buffer": "^6.0.3"
- }
+ "license": "MIT"
},
"node_modules/@modelcontextprotocol/sdk": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.12.1.tgz",
- "integrity": "sha512-KG1CZhZfWg+u8pxeM/mByJDScJSrjjxLc8fwQqbsS8xCjBmQfMNEBTotYdNanKekepnfRI85GtgQlctLFpcYPw==",
+ "version": "1.17.3",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.3.tgz",
+ "integrity": "sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -867,6 +911,7 @@
"cors": "^2.8.5",
"cross-spawn": "^7.0.5",
"eventsource": "^3.0.2",
+ "eventsource-parser": "^3.0.0",
"express": "^5.0.1",
"express-rate-limit": "^7.5.0",
"pkce-challenge": "^5.0.0",
@@ -888,9 +933,9 @@
}
},
"node_modules/@octokit/core": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.2.tgz",
- "integrity": "sha512-ODsoD39Lq6vR6aBgvjTnA3nZGliknKboc9Gtxr7E4WDNqY24MxANKcuDQSF0jzapvGb3KWOEDrKfve4HoWGK+g==",
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.3.tgz",
+ "integrity": "sha512-oNXsh2ywth5aowwIa7RKtawnkdH6LgU1ztfP9AIUCQCvzysB+WeU8o2kyyosDPwBZutPpjZDKPQGIzzrfTWweQ==",
"license": "MIT",
"dependencies": {
"@octokit/auth-token": "^6.0.0",
@@ -939,9 +984,9 @@
"license": "MIT"
},
"node_modules/@octokit/plugin-paginate-rest": {
- "version": "13.0.1",
- "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.0.1.tgz",
- "integrity": "sha512-m1KvHlueScy4mQJWvFDCxFBTIdXS0K1SgFGLmqHyX90mZdCIv6gWBbKRhatxRjhGlONuTK/hztYdaqrTXcFZdQ==",
+ "version": "13.1.1",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.1.1.tgz",
+ "integrity": "sha512-q9iQGlZlxAVNRN2jDNskJW/Cafy7/XE52wjZ5TTvyhyOD904Cvx//DNyoO3J/MXJ0ve3rPoNWKEg5iZrisQSuw==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^14.1.0"
@@ -969,9 +1014,9 @@
}
},
"node_modules/@octokit/request": {
- "version": "10.0.2",
- "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.2.tgz",
- "integrity": "sha512-iYj4SJG/2bbhh+iIpFmG5u49DtJ4lipQ+aPakjL9OKpsGY93wM8w06gvFbEQxcMsZcCvk5th5KkIm2m8o14aWA==",
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.3.tgz",
+ "integrity": "sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA==",
"license": "MIT",
"dependencies": {
"@octokit/endpoint": "^11.0.0",
@@ -1024,9 +1069,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.42.0.tgz",
- "integrity": "sha512-gldmAyS9hpj+H6LpRNlcjQWbuKUtb94lodB9uCz71Jm+7BxK1VIOo7y62tZZwxhA7j1ylv/yQz080L5WkS+LoQ==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.3.tgz",
+ "integrity": "sha512-UmTdvXnLlqQNOCJnyksjPs1G4GqXNGW1LrzCe8+8QoaLhhDeTXYBgJ3k6x61WIhlHX2U+VzEJ55TtIjR/HTySA==",
"cpu": [
"arm"
],
@@ -1038,9 +1083,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.42.0.tgz",
- "integrity": "sha512-bpRipfTgmGFdCZDFLRvIkSNO1/3RGS74aWkJJTFJBH7h3MRV4UijkaEUeOMbi9wxtxYmtAbVcnMtHTPBhLEkaw==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.3.tgz",
+ "integrity": "sha512-8NoxqLpXm7VyeI0ocidh335D6OKT0UJ6fHdnIxf3+6oOerZZc+O7r+UhvROji6OspyPm+rrIdb1gTXtVIqn+Sg==",
"cpu": [
"arm64"
],
@@ -1052,9 +1097,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.42.0.tgz",
- "integrity": "sha512-JxHtA081izPBVCHLKnl6GEA0w3920mlJPLh89NojpU2GsBSB6ypu4erFg/Wx1qbpUbepn0jY4dVWMGZM8gplgA==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.3.tgz",
+ "integrity": "sha512-csnNavqZVs1+7/hUKtgjMECsNG2cdB8F7XBHP6FfQjqhjF8rzMzb3SLyy/1BG7YSfQ+bG75Ph7DyedbUqwq1rA==",
"cpu": [
"arm64"
],
@@ -1066,9 +1111,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.42.0.tgz",
- "integrity": "sha512-rv5UZaWVIJTDMyQ3dCEK+m0SAn6G7H3PRc2AZmExvbDvtaDc+qXkei0knQWcI3+c9tEs7iL/4I4pTQoPbNL2SA==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.3.tgz",
+ "integrity": "sha512-r2MXNjbuYabSIX5yQqnT8SGSQ26XQc8fmp6UhlYJd95PZJkQD1u82fWP7HqvGUf33IsOC6qsiV+vcuD4SDP6iw==",
"cpu": [
"x64"
],
@@ -1080,9 +1125,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.42.0.tgz",
- "integrity": "sha512-fJcN4uSGPWdpVmvLuMtALUFwCHgb2XiQjuECkHT3lWLZhSQ3MBQ9pq+WoWeJq2PrNxr9rPM1Qx+IjyGj8/c6zQ==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.3.tgz",
+ "integrity": "sha512-uluObTmgPJDuJh9xqxyr7MV61Imq+0IvVsAlWyvxAaBSNzCcmZlhfYcRhCdMaCsy46ccZa7vtDDripgs9Jkqsw==",
"cpu": [
"arm64"
],
@@ -1094,9 +1139,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.42.0.tgz",
- "integrity": "sha512-CziHfyzpp8hJpCVE/ZdTizw58gr+m7Y2Xq5VOuCSrZR++th2xWAz4Nqk52MoIIrV3JHtVBhbBsJcAxs6NammOQ==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.3.tgz",
+ "integrity": "sha512-AVJXEq9RVHQnejdbFvh1eWEoobohUYN3nqJIPI4mNTMpsyYN01VvcAClxflyk2HIxvLpRcRggpX1m9hkXkpC/A==",
"cpu": [
"x64"
],
@@ -1108,9 +1153,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.42.0.tgz",
- "integrity": "sha512-UsQD5fyLWm2Fe5CDM7VPYAo+UC7+2Px4Y+N3AcPh/LdZu23YcuGPegQly++XEVaC8XUTFVPscl5y5Cl1twEI4A==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.3.tgz",
+ "integrity": "sha512-byyflM+huiwHlKi7VHLAYTKr67X199+V+mt1iRgJenAI594vcmGGddWlu6eHujmcdl6TqSNnvqaXJqZdnEWRGA==",
"cpu": [
"arm"
],
@@ -1122,9 +1167,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.42.0.tgz",
- "integrity": "sha512-/i8NIrlgc/+4n1lnoWl1zgH7Uo0XK5xK3EDqVTf38KvyYgCU/Rm04+o1VvvzJZnVS5/cWSd07owkzcVasgfIkQ==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.3.tgz",
+ "integrity": "sha512-aLm3NMIjr4Y9LklrH5cu7yybBqoVCdr4Nvnm8WB7PKCn34fMCGypVNpGK0JQWdPAzR/FnoEoFtlRqZbBBLhVoQ==",
"cpu": [
"arm"
],
@@ -1136,9 +1181,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.42.0.tgz",
- "integrity": "sha512-eoujJFOvoIBjZEi9hJnXAbWg+Vo1Ov8n/0IKZZcPZ7JhBzxh2A+2NFyeMZIRkY9iwBvSjloKgcvnjTbGKHE44Q==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.3.tgz",
+ "integrity": "sha512-VtilE6eznJRDIoFOzaagQodUksTEfLIsvXymS+UdJiSXrPW7Ai+WG4uapAc3F7Hgs791TwdGh4xyOzbuzIZrnw==",
"cpu": [
"arm64"
],
@@ -1150,9 +1195,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.42.0.tgz",
- "integrity": "sha512-/3NrcOWFSR7RQUQIuZQChLND36aTU9IYE4j+TB40VU78S+RA0IiqHR30oSh6P1S9f9/wVOenHQnacs/Byb824g==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.3.tgz",
+ "integrity": "sha512-dG3JuS6+cRAL0GQ925Vppafi0qwZnkHdPeuZIxIPXqkCLP02l7ka+OCyBoDEv8S+nKHxfjvjW4OZ7hTdHkx8/w==",
"cpu": [
"arm64"
],
@@ -1164,9 +1209,9 @@
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.42.0.tgz",
- "integrity": "sha512-O8AplvIeavK5ABmZlKBq9/STdZlnQo7Sle0LLhVA7QT+CiGpNVe197/t8Aph9bhJqbDVGCHpY2i7QyfEDDStDg==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.3.tgz",
+ "integrity": "sha512-iU8DxnxEKJptf8Vcx4XvAUdpkZfaz0KWfRrnIRrOndL0SvzEte+MTM7nDH4A2Now4FvTZ01yFAgj6TX/mZl8hQ==",
"cpu": [
"loong64"
],
@@ -1177,10 +1222,10 @@
"linux"
]
},
- "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.42.0.tgz",
- "integrity": "sha512-6Qb66tbKVN7VyQrekhEzbHRxXXFFD8QKiFAwX5v9Xt6FiJ3BnCVBuyBxa2fkFGqxOCSGGYNejxd8ht+q5SnmtA==",
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.3.tgz",
+ "integrity": "sha512-VrQZp9tkk0yozJoQvQcqlWiqaPnLM6uY1qPYXvukKePb0fqaiQtOdMJSxNFUZFsGw5oA5vvVokjHrx8a9Qsz2A==",
"cpu": [
"ppc64"
],
@@ -1192,9 +1237,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.42.0.tgz",
- "integrity": "sha512-KQETDSEBamQFvg/d8jajtRwLNBlGc3aKpaGiP/LvEbnmVUKlFta1vqJqTrvPtsYsfbE/DLg5CC9zyXRX3fnBiA==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.3.tgz",
+ "integrity": "sha512-uf2eucWSUb+M7b0poZ/08LsbcRgaDYL8NCGjUeFMwCWFwOuFcZ8D9ayPl25P3pl+D2FH45EbHdfyUesQ2Lt9wA==",
"cpu": [
"riscv64"
],
@@ -1206,9 +1251,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.42.0.tgz",
- "integrity": "sha512-qMvnyjcU37sCo/tuC+JqeDKSuukGAd+pVlRl/oyDbkvPJ3awk6G6ua7tyum02O3lI+fio+eM5wsVd66X0jQtxw==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.3.tgz",
+ "integrity": "sha512-7tnUcDvN8DHm/9ra+/nF7lLzYHDeODKKKrh6JmZejbh1FnCNZS8zMkZY5J4sEipy2OW1d1Ncc4gNHUd0DLqkSg==",
"cpu": [
"riscv64"
],
@@ -1220,9 +1265,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.42.0.tgz",
- "integrity": "sha512-I2Y1ZUgTgU2RLddUHXTIgyrdOwljjkmcZ/VilvaEumtS3Fkuhbw4p4hgHc39Ypwvo2o7sBFNl2MquNvGCa55Iw==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.3.tgz",
+ "integrity": "sha512-MUpAOallJim8CsJK+4Lc9tQzlfPbHxWDrGXZm2z6biaadNpvh3a5ewcdat478W+tXDoUiHwErX/dOql7ETcLqg==",
"cpu": [
"s390x"
],
@@ -1234,9 +1279,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.42.0.tgz",
- "integrity": "sha512-Gfm6cV6mj3hCUY8TqWa63DB8Mx3NADoFwiJrMpoZ1uESbK8FQV3LXkhfry+8bOniq9pqY1OdsjFWNsSbfjPugw==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.3.tgz",
+ "integrity": "sha512-F42IgZI4JicE2vM2PWCe0N5mR5vR0gIdORPqhGQ32/u1S1v3kLtbZ0C/mi9FFk7C5T0PgdeyWEPajPjaUpyoKg==",
"cpu": [
"x64"
],
@@ -1248,9 +1293,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.42.0.tgz",
- "integrity": "sha512-g86PF8YZ9GRqkdi0VoGlcDUb4rYtQKyTD1IVtxxN4Hpe7YqLBShA7oHMKU6oKTCi3uxwW4VkIGnOaH/El8de3w==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.3.tgz",
+ "integrity": "sha512-oLc+JrwwvbimJUInzx56Q3ujL3Kkhxehg7O1gWAYzm8hImCd5ld1F2Gry5YDjR21MNb5WCKhC9hXgU7rRlyegQ==",
"cpu": [
"x64"
],
@@ -1262,9 +1307,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.42.0.tgz",
- "integrity": "sha512-+axkdyDGSp6hjyzQ5m1pgcvQScfHnMCcsXkx8pTgy/6qBmWVhtRVlgxjWwDp67wEXXUr0x+vD6tp5W4x6V7u1A==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.3.tgz",
+ "integrity": "sha512-lOrQ+BVRstruD1fkWg9yjmumhowR0oLAAzavB7yFSaGltY8klttmZtCLvOXCmGE9mLIn8IBV/IFrQOWz5xbFPg==",
"cpu": [
"arm64"
],
@@ -1276,9 +1321,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.42.0.tgz",
- "integrity": "sha512-F+5J9pelstXKwRSDq92J0TEBXn2nfUrQGg+HK1+Tk7VOL09e0gBqUHugZv7SW4MGrYj41oNCUe3IKCDGVlis2g==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.3.tgz",
+ "integrity": "sha512-vvrVKPRS4GduGR7VMH8EylCBqsDcw6U+/0nPDuIjXQRbHJc6xOBj+frx8ksfZAh6+Fptw5wHrN7etlMmQnPQVg==",
"cpu": [
"ia32"
],
@@ -1290,9 +1335,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.42.0.tgz",
- "integrity": "sha512-LpHiJRwkaVz/LqjHjK8LCi8osq7elmpwujwbXKNW88bM8eeGxavJIKKjkjpMHAh/2xfnrt1ZSnhTv41WYUHYmA==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.3.tgz",
+ "integrity": "sha512-fi3cPxCnu3ZeM3EwKZPgXbWoGzm2XHgB/WShKI81uj8wG0+laobmqy5wbgEwzstlbLu4MyO8C19FyhhWseYKNQ==",
"cpu": [
"x64"
],
@@ -1304,66 +1349,66 @@
]
},
"node_modules/@textlint/ast-node-types": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-14.8.0.tgz",
- "integrity": "sha512-CARGqRSX+DhHdSYssa6+Yb0KAk5cGPDOgKbJo/H8djJAmw7qNzo/oYbuYZlO/fqmUbZjZcvI/6QgCxa/78Nxew==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.2.1.tgz",
+ "integrity": "sha512-20fEcLPsXg81yWpApv4FQxrZmlFF/Ta7/kz1HGIL+pJo5cSTmkc+eCki3GpOPZIoZk0tbJU8hrlwUb91F+3SNQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@textlint/ast-tester": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/ast-tester/-/ast-tester-14.8.0.tgz",
- "integrity": "sha512-nRsgHmY+O7OhCYwGyWze+8mhnTYfCPFYTvuF3mCE5nQrfO9y2anvdjj2Yf6FU7OZI7qxp/R7MWYkiIQb/WEfHQ==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/ast-tester/-/ast-tester-15.2.1.tgz",
+ "integrity": "sha512-B3BNE52w+6eCsybpKhxIm/bMY1i3oF8AC5amYeaPaTaluz+rPDR4S5S6QAMaMM8XJlD0osYBdKd9LDwQPJFsIQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/ast-node-types": "^14.8.0",
+ "@textlint/ast-node-types": "15.2.1",
"debug": "^4.4.1"
}
},
"node_modules/@textlint/ast-traverse": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/ast-traverse/-/ast-traverse-14.8.0.tgz",
- "integrity": "sha512-/u1SiIVnRFm1D/pglLtaP0QJND7UAo8axrUfaikFJZ67ciiguu17/yB0VBMbx9iZn5bmeUHH1NicgCnuirvvJg==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/ast-traverse/-/ast-traverse-15.2.1.tgz",
+ "integrity": "sha512-6i+kqjREEJ1HH3v0tltQ1ZTgptd4ViyJiZe+5J62Bn1Ml7CyV/zIJ4+3pJ4x26Ts+1sqpUD/lDDNOeZz5DKsmg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/ast-node-types": "^14.8.0"
+ "@textlint/ast-node-types": "15.2.1"
}
},
"node_modules/@textlint/config-loader": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/config-loader/-/config-loader-14.8.0.tgz",
- "integrity": "sha512-WYg2WhyFCcCmEN1HOOpe420CMg9o7HzbELVGWvNrgNqqmQDxusUX88z1IG2xJ1bIGpgZTbm9SneUBnoRTzPCJg==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/config-loader/-/config-loader-15.2.1.tgz",
+ "integrity": "sha512-Rxp9YUAyYDmy6VIFJ0aNE/18O920wGCJpAVok+TnW8VM/CJXTp6/UibgSkqjWM5W2K301AFhZgPENAWJQLP7yw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/kernel": "^14.8.0",
- "@textlint/module-interop": "^14.8.0",
- "@textlint/resolver": "^14.8.0",
- "@textlint/types": "^14.8.0",
- "@textlint/utils": "^14.8.0",
+ "@textlint/kernel": "15.2.1",
+ "@textlint/module-interop": "15.2.1",
+ "@textlint/resolver": "15.2.1",
+ "@textlint/types": "15.2.1",
+ "@textlint/utils": "15.2.1",
"debug": "^4.4.1",
"rc-config-loader": "^4.1.3"
}
},
"node_modules/@textlint/feature-flag": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/feature-flag/-/feature-flag-14.8.0.tgz",
- "integrity": "sha512-cmqPYs1EUYC/5YE8pd70ODrtHCeumR5kamK+CuNj2tS2lDPJ55XJt2I+UnX0SqyRATdl7Yp7OizLfZ5xrtAlUQ==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/feature-flag/-/feature-flag-15.2.1.tgz",
+ "integrity": "sha512-88H5WGxTperDNHA6LXT6AcTJ9MFs9l1OR7fjq+0AbXjq8Fg5RFYgx0SCxr4Fcmx0nr8JOFhexXp8qz6MMUz+bg==",
"dev": true,
"license": "MIT"
},
"node_modules/@textlint/fixer-formatter": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/fixer-formatter/-/fixer-formatter-14.8.0.tgz",
- "integrity": "sha512-eDpH/GQrod3Jg4HNkXw4SclSWLX85snUhzhMo1wmYgI8inRaIzfd1sURRy6edEabd6y1kLImyFmYOx9U96ILQA==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/fixer-formatter/-/fixer-formatter-15.2.1.tgz",
+ "integrity": "sha512-8TFs76YGJ+1rkIjQ5YXV4xhomYrkaMoqqST9d7UfGE1anj9koXNhSV4V8IHlK68dAQ91Qcc6Cdz/ohZ6Mv1t9Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/module-interop": "^14.8.0",
- "@textlint/resolver": "^14.8.0",
- "@textlint/types": "^14.8.0",
+ "@textlint/module-interop": "15.2.1",
+ "@textlint/resolver": "15.2.1",
+ "@textlint/types": "15.2.1",
"chalk": "^4.1.2",
"debug": "^4.4.1",
"diff": "^5.2.0",
@@ -1418,36 +1463,36 @@
}
},
"node_modules/@textlint/kernel": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/kernel/-/kernel-14.8.0.tgz",
- "integrity": "sha512-AUy2qK7Z1pWBwtHjb3kdCwKjPo6M5SuS+e/Homvn77oUKXJVtJi4+HpDvVxTRZjW37LtYxIr/CyNhhNN8HAu4Q==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/kernel/-/kernel-15.2.1.tgz",
+ "integrity": "sha512-Xen6wfOlZZtGPsXqk9enXlXxsDy3uXBQo+fENXohT0e6xnx500r4N6IrYOr/VANMoAS2DrIrqpN6Q1W1VpBZlg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/ast-node-types": "^14.8.0",
- "@textlint/ast-tester": "^14.8.0",
- "@textlint/ast-traverse": "^14.8.0",
- "@textlint/feature-flag": "^14.8.0",
- "@textlint/source-code-fixer": "^14.8.0",
- "@textlint/types": "^14.8.0",
- "@textlint/utils": "^14.8.0",
+ "@textlint/ast-node-types": "15.2.1",
+ "@textlint/ast-tester": "15.2.1",
+ "@textlint/ast-traverse": "15.2.1",
+ "@textlint/feature-flag": "15.2.1",
+ "@textlint/source-code-fixer": "15.2.1",
+ "@textlint/types": "15.2.1",
+ "@textlint/utils": "15.2.1",
"debug": "^4.4.1",
"fast-equals": "^4.0.3",
"structured-source": "^4.0.0"
}
},
"node_modules/@textlint/linter-formatter": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-14.8.0.tgz",
- "integrity": "sha512-xedTBR/rlVNS9Np5moxhWGwVWEY8Eg+MxkasZblEZgiGbuMhCiVNrSuvx8T6E/UFvFunQYc9oNIMylzAXtnx7A==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.2.1.tgz",
+ "integrity": "sha512-oollG/BHa07+mMt372amxHohteASC+Zxgollc1sZgiyxo4S6EuureV3a4QIQB0NecA+Ak3d0cl0WI/8nou38jw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@azu/format-text": "^1.0.2",
"@azu/style-format": "^1.0.1",
- "@textlint/module-interop": "^14.8.0",
- "@textlint/resolver": "^14.8.0",
- "@textlint/types": "^14.8.0",
+ "@textlint/module-interop": "15.2.1",
+ "@textlint/resolver": "15.2.1",
+ "@textlint/types": "15.2.1",
"chalk": "^4.1.2",
"debug": "^4.4.1",
"js-yaml": "^3.14.1",
@@ -1469,6 +1514,16 @@
"node": ">=8"
}
},
+ "node_modules/@textlint/linter-formatter/node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
"node_modules/@textlint/linter-formatter/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -1476,6 +1531,20 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@textlint/linter-formatter/node_modules/js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
"node_modules/@textlint/linter-formatter/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -1505,92 +1574,95 @@
}
},
"node_modules/@textlint/markdown-to-ast": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/markdown-to-ast/-/markdown-to-ast-14.8.0.tgz",
- "integrity": "sha512-KxvogGH8BPfR4eP5TNlRiR7KcPWzFjk1k8TX0WBnqWTzQeYbDYulYslVyiq06qc1NkTHvpK34zbS8UWZyzIQKA==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/markdown-to-ast/-/markdown-to-ast-15.2.1.tgz",
+ "integrity": "sha512-JU3AxIAuom/ZdKok6tkNVy8PsqjxKnSlBfld1dzyRV7/VFWbBuFdlaV6M8aJHa0HKy0Y9QHTXxiOJQkUPA5kWA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/ast-node-types": "^14.8.0",
+ "@textlint/ast-node-types": "15.2.1",
"debug": "^4.4.1",
"mdast-util-gfm-autolink-literal": "^0.1.3",
- "neotraverse": "^0.6.15",
+ "neotraverse": "^0.6.18",
"remark-footnotes": "^3.0.0",
"remark-frontmatter": "^3.0.0",
"remark-gfm": "^1.0.0",
"remark-parse": "^9.0.0",
+ "structured-source": "^4.0.0",
"unified": "^9.2.2"
}
},
"node_modules/@textlint/module-interop": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-14.8.0.tgz",
- "integrity": "sha512-SGeojZIpjP58RrnUAIjKO5xokloHfXJWcc3dh/QP9pDHRCI97yPJhyEXzOD3FiY9zFG2KNIYwUTyrIGnnBm9xQ==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.2.1.tgz",
+ "integrity": "sha512-b/C/ZNrm05n1ypymDknIcpkBle30V2ZgE3JVqQlA9PnQV46Ky510qrZk6s9yfKgA3m1YRnAw04m8xdVtqjq1qg==",
"dev": true,
"license": "MIT"
},
"node_modules/@textlint/resolver": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-14.8.0.tgz",
- "integrity": "sha512-FUrXlwbfLxSUvgjOG/OgDV56m0IBBswcOEoex8cXAE1677ejAAWrI9WqzuBItX5g+srh5is3Vth4D6H8iuyLAg==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.2.1.tgz",
+ "integrity": "sha512-FY3aK4tElEcOJVUsaMj4Zro4jCtKEEwUMIkDL0tcn6ljNcgOF7Em+KskRRk/xowFWayqDtdz5T3u7w/6fjjuJQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@textlint/source-code-fixer": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/source-code-fixer/-/source-code-fixer-14.8.0.tgz",
- "integrity": "sha512-/BtG3IRpmUG3A0Pr2wra2uY0d4sjmESeJlYn++ZlP8eYNYM9jotWsdb9K+fa1jMX4OzozKv1nOewhSfo/AD6Cw==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/source-code-fixer/-/source-code-fixer-15.2.1.tgz",
+ "integrity": "sha512-wMjEcH2jWfCazj2paNo5S+mnpf/ephOWceNQ5Aq1jfWCcqyJEvF8xykiCW7iFiW/KVkVIUdTdcrb+ZgY1n5bzw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/types": "^14.8.0",
+ "@textlint/types": "15.2.1",
"debug": "^4.4.1"
}
},
"node_modules/@textlint/text-to-ast": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/text-to-ast/-/text-to-ast-14.8.0.tgz",
- "integrity": "sha512-/U8k2Y6azqeKJnEJej2b8dylqKZw4tSqsOlfeI82qslDEjjdtseuzbLz7Z0X/VgWmbnqxrt1y/ZsLaThhOntuQ==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/text-to-ast/-/text-to-ast-15.2.1.tgz",
+ "integrity": "sha512-m6j+35PfBB1pWRQ7oddKhZWMPIqeEdGvQDyFvr50piyjiJ4ME7ASVhfvA3yoLQ+92jW/DWRQ+gpj0tQPdlmq8Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/ast-node-types": "^14.8.0"
+ "@textlint/ast-node-types": "15.2.1"
}
},
"node_modules/@textlint/textlint-plugin-markdown": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/textlint-plugin-markdown/-/textlint-plugin-markdown-14.8.0.tgz",
- "integrity": "sha512-BDjcoBfv+Vxg83/GrTg9XK4wKIuZb7x85gLmRqlsy48Lj5l++AIk5qe/iL1hI38PDr8IfY8JRYvfMpyn+KGuNA==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/textlint-plugin-markdown/-/textlint-plugin-markdown-15.2.1.tgz",
+ "integrity": "sha512-mHWjpGsVeIgVkWeW+H9sMhxKN/FNVofbqwwERg0vxme37vEVKrAXAq9t25ZL5erco5qkvuWT55LmgKOQG48oXw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/markdown-to-ast": "^14.8.0"
+ "@textlint/markdown-to-ast": "15.2.1",
+ "@textlint/types": "15.2.1"
}
},
"node_modules/@textlint/textlint-plugin-text": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/textlint-plugin-text/-/textlint-plugin-text-14.8.0.tgz",
- "integrity": "sha512-fg2382TsRL7FiWxatvr3VNyjIQqMTRIqFkuPjBSb8HjC5xabi5s2ZU8Z0O58SBN9YWpihcTP+N84W5l5iU784g==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/textlint-plugin-text/-/textlint-plugin-text-15.2.1.tgz",
+ "integrity": "sha512-KI5vEEQXZJmEOrVuCeYVYHZLA6tWehwrvAYNjZLnlBICD8CTPLaFm3kqlDdGosbYnsk525BhEjW6sxAeA25a6g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/text-to-ast": "^14.8.0"
+ "@textlint/text-to-ast": "15.2.1",
+ "@textlint/types": "15.2.1"
}
},
"node_modules/@textlint/types": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/types/-/types-14.8.0.tgz",
- "integrity": "sha512-Lsq2gxh2pmCKV6KN4fL70DMNNGuZlPuDQ0RHLU59/wgUs5krzrpHWCRYHK4M4J45U1PfZzQnWvLIfFETlR9GPA==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.2.1.tgz",
+ "integrity": "sha512-zyqNhSatK1cwxDUgosEEN43hFh3WCty9Zm2Vm3ogU566IYegifwqN54ey/CiRy/DiO4vMcFHykuQnh2Zwp6LLw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/ast-node-types": "^14.8.0"
+ "@textlint/ast-node-types": "15.2.1"
}
},
"node_modules/@textlint/utils": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/@textlint/utils/-/utils-14.8.0.tgz",
- "integrity": "sha512-ZYZuyPl7EW1Tio/jfjf92MFgPwrQ6nklir5uCJAwrdl9Me/9rL7l3n8HlFHc8Z7dPNeqUbDuOLgoS+74coZplA==",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/@textlint/utils/-/utils-15.2.1.tgz",
+ "integrity": "sha512-osXG48HjqaOk21mX3upTmAMhEEIULjzZgH17S4pQzrU/16N0VsuiqYOZL14uN0gyWR8YY8lec+cszDN/eCwULg==",
"dev": true,
"license": "MIT"
},
@@ -1618,6 +1690,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/js-yaml": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
+ "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/mdast": {
"version": "3.0.15",
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz",
@@ -1629,15 +1708,22 @@
}
},
"node_modules/@types/node": {
- "version": "22.15.30",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.30.tgz",
- "integrity": "sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA==",
+ "version": "22.17.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.2.tgz",
+ "integrity": "sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
+ "node_modules/@types/normalize-package-data": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
+ "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/unist": {
"version": "2.0.11",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
@@ -1663,9 +1749,9 @@
}
},
"node_modules/@vitest/coverage-v8": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.3.tgz",
- "integrity": "sha512-D1QKzngg8PcDoCE8FHSZhREDuEy+zcKmMiMafYse41RZpBE5EDJyKOTdqK3RQfsV2S2nyKor5KCs8PyPRFqKPg==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz",
+ "integrity": "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1687,8 +1773,8 @@
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
- "@vitest/browser": "3.2.3",
- "vitest": "3.2.3"
+ "@vitest/browser": "3.2.4",
+ "vitest": "3.2.4"
},
"peerDependenciesMeta": {
"@vitest/browser": {
@@ -1697,15 +1783,15 @@
}
},
"node_modules/@vitest/expect": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.3.tgz",
- "integrity": "sha512-W2RH2TPWVHA1o7UmaFKISPvdicFJH+mjykctJFoAkUw+SPTJTGjUNdKscFBrqM7IPnCVu6zihtKYa7TkZS1dkQ==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
+ "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/chai": "^5.2.2",
- "@vitest/spy": "3.2.3",
- "@vitest/utils": "3.2.3",
+ "@vitest/spy": "3.2.4",
+ "@vitest/utils": "3.2.4",
"chai": "^5.2.0",
"tinyrainbow": "^2.0.0"
},
@@ -1714,13 +1800,13 @@
}
},
"node_modules/@vitest/mocker": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.3.tgz",
- "integrity": "sha512-cP6fIun+Zx8he4rbWvi+Oya6goKQDZK+Yq4hhlggwQBbrlOQ4qtZ+G4nxB6ZnzI9lyIb+JnvyiJnPC2AGbKSPA==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz",
+ "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/spy": "3.2.3",
+ "@vitest/spy": "3.2.4",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.17"
},
@@ -1741,9 +1827,9 @@
}
},
"node_modules/@vitest/pretty-format": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.3.tgz",
- "integrity": "sha512-yFglXGkr9hW/yEXngO+IKMhP0jxyFw2/qys/CK4fFUZnSltD+MU7dVYGrH8rvPcK/O6feXQA+EU33gjaBBbAng==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz",
+ "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1754,13 +1840,13 @@
}
},
"node_modules/@vitest/runner": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.3.tgz",
- "integrity": "sha512-83HWYisT3IpMaU9LN+VN+/nLHVBCSIUKJzGxC5RWUOsK1h3USg7ojL+UXQR3b4o4UBIWCYdD2fxuzM7PQQ1u8w==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz",
+ "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/utils": "3.2.3",
+ "@vitest/utils": "3.2.4",
"pathe": "^2.0.3",
"strip-literal": "^3.0.0"
},
@@ -1769,13 +1855,13 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.3.tgz",
- "integrity": "sha512-9gIVWx2+tysDqUmmM1L0hwadyumqssOL1r8KJipwLx5JVYyxvVRfxvMq7DaWbZZsCqZnu/dZedaZQh4iYTtneA==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz",
+ "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "3.2.3",
+ "@vitest/pretty-format": "3.2.4",
"magic-string": "^0.30.17",
"pathe": "^2.0.3"
},
@@ -1784,9 +1870,9 @@
}
},
"node_modules/@vitest/spy": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.3.tgz",
- "integrity": "sha512-JHu9Wl+7bf6FEejTCREy+DmgWe+rQKbK+y32C/k5f4TBIAlijhJbRBIRIOCEpVevgRsCQR2iHRUH2/qKVM/plw==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz",
+ "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1797,14 +1883,14 @@
}
},
"node_modules/@vitest/utils": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.3.tgz",
- "integrity": "sha512-4zFBCU5Pf+4Z6v+rwnZ1HU1yzOKKvDkMXZrymE2PBlbjKJRlrOxbvpfPSvJTGRIwGoahaOGvp+kbCoxifhzJ1Q==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz",
+ "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "3.2.3",
- "loupe": "^3.1.3",
+ "@vitest/pretty-format": "3.2.4",
+ "loupe": "^3.1.4",
"tinyrainbow": "^2.0.0"
},
"funding": {
@@ -1843,9 +1929,9 @@
}
},
"node_modules/ansi-regex": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
- "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.0.tgz",
+ "integrity": "sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1872,14 +1958,11 @@
}
},
"node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
+ "license": "Python-2.0"
},
"node_modules/assertion-error": {
"version": "2.0.1",
@@ -1892,13 +1975,13 @@
}
},
"node_modules/ast-v8-to-istanbul": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.3.tgz",
- "integrity": "sha512-MuXMrSLVVoA6sYN/6Hke18vMzrT4TZNbZIj/hvh0fnYFpO+/kFXcLIaiPwXXWaQUPg4yJD8fj+lfJ7/1EBconw==",
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.4.tgz",
+ "integrity": "sha512-cxrAnZNLBnQwBPByK4CeDaw5sWZtMilJE/Q3iDA0aamgaIVNDF9T6K2/8DfYDZEejZ2jNnDrG9m8MY72HFd0KA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jridgewell/trace-mapping": "^0.3.25",
+ "@jridgewell/trace-mapping": "^0.3.29",
"estree-walker": "^3.0.3",
"js-tokens": "^9.0.1"
}
@@ -1928,27 +2011,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "license": "MIT"
- },
- "node_modules/base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
"license": "MIT"
},
"node_modules/before-after-hook": {
@@ -1986,37 +2049,13 @@
"license": "BSD-2-Clause"
},
"node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/buffer": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
- "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
"license": "MIT",
"dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.2.1"
+ "balanced-match": "^1.0.0"
}
},
"node_modules/bytes": {
@@ -2040,14 +2079,14 @@
}
},
"node_modules/cacheable": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.10.0.tgz",
- "integrity": "sha512-SSgQTAnhd7WlJXnGlIi4jJJOiHzgnM5wRMEPaXAU4kECTAMpBoYKoZ9i5zHmclIEZbxcu3j7yY/CF8DTmwIsHg==",
+ "version": "1.10.4",
+ "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.10.4.tgz",
+ "integrity": "sha512-Gd7ccIUkZ9TE2odLQVS+PDjIvQCdJKUlLdJRVvZu0aipj07Qfx+XIej7hhDrKGGoIxV5m5fT/kOJNJPQhQneRg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "hookified": "^1.8.2",
- "keyv": "^5.3.3"
+ "hookified": "^1.11.0",
+ "keyv": "^5.5.0"
}
},
"node_modules/call-bind-apply-helpers": {
@@ -2093,9 +2132,9 @@
}
},
"node_modules/chai": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
- "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.1.tgz",
+ "integrity": "sha512-48af6xm9gQK8rhIcOxWwdGzIervm8BVTin+yRp9HEvU20BtVZ2lBywlIJBzwaDtvo0FvjeL7QdCADoUoqIbV3A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2106,7 +2145,7 @@
"pathval": "^2.0.0"
},
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/chalk": {
@@ -2405,16 +2444,6 @@
"node": ">= 0.8"
}
},
- "node_modules/error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-arrayish": "^0.2.1"
- }
- },
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
@@ -2456,9 +2485,9 @@
}
},
"node_modules/esbuild": {
- "version": "0.25.5",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
- "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
+ "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -2469,31 +2498,32 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.25.5",
- "@esbuild/android-arm": "0.25.5",
- "@esbuild/android-arm64": "0.25.5",
- "@esbuild/android-x64": "0.25.5",
- "@esbuild/darwin-arm64": "0.25.5",
- "@esbuild/darwin-x64": "0.25.5",
- "@esbuild/freebsd-arm64": "0.25.5",
- "@esbuild/freebsd-x64": "0.25.5",
- "@esbuild/linux-arm": "0.25.5",
- "@esbuild/linux-arm64": "0.25.5",
- "@esbuild/linux-ia32": "0.25.5",
- "@esbuild/linux-loong64": "0.25.5",
- "@esbuild/linux-mips64el": "0.25.5",
- "@esbuild/linux-ppc64": "0.25.5",
- "@esbuild/linux-riscv64": "0.25.5",
- "@esbuild/linux-s390x": "0.25.5",
- "@esbuild/linux-x64": "0.25.5",
- "@esbuild/netbsd-arm64": "0.25.5",
- "@esbuild/netbsd-x64": "0.25.5",
- "@esbuild/openbsd-arm64": "0.25.5",
- "@esbuild/openbsd-x64": "0.25.5",
- "@esbuild/sunos-x64": "0.25.5",
- "@esbuild/win32-arm64": "0.25.5",
- "@esbuild/win32-ia32": "0.25.5",
- "@esbuild/win32-x64": "0.25.5"
+ "@esbuild/aix-ppc64": "0.25.9",
+ "@esbuild/android-arm": "0.25.9",
+ "@esbuild/android-arm64": "0.25.9",
+ "@esbuild/android-x64": "0.25.9",
+ "@esbuild/darwin-arm64": "0.25.9",
+ "@esbuild/darwin-x64": "0.25.9",
+ "@esbuild/freebsd-arm64": "0.25.9",
+ "@esbuild/freebsd-x64": "0.25.9",
+ "@esbuild/linux-arm": "0.25.9",
+ "@esbuild/linux-arm64": "0.25.9",
+ "@esbuild/linux-ia32": "0.25.9",
+ "@esbuild/linux-loong64": "0.25.9",
+ "@esbuild/linux-mips64el": "0.25.9",
+ "@esbuild/linux-ppc64": "0.25.9",
+ "@esbuild/linux-riscv64": "0.25.9",
+ "@esbuild/linux-s390x": "0.25.9",
+ "@esbuild/linux-x64": "0.25.9",
+ "@esbuild/netbsd-arm64": "0.25.9",
+ "@esbuild/netbsd-x64": "0.25.9",
+ "@esbuild/openbsd-arm64": "0.25.9",
+ "@esbuild/openbsd-x64": "0.25.9",
+ "@esbuild/openharmony-arm64": "0.25.9",
+ "@esbuild/sunos-x64": "0.25.9",
+ "@esbuild/win32-arm64": "0.25.9",
+ "@esbuild/win32-ia32": "0.25.9",
+ "@esbuild/win32-x64": "0.25.9"
}
},
"node_modules/escape-html": {
@@ -2564,19 +2594,19 @@
}
},
"node_modules/eventsource-parser": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.2.tgz",
- "integrity": "sha512-6RxOBZ/cYgd8usLwsEl+EC09Au/9BcmCKYF2/xbml6DNczf7nv0MQb+7BA2F+li6//I+28VNlQR37XfQtcAJuA==",
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.5.tgz",
+ "integrity": "sha512-bSRG85ZrMdmWtm7qkF9He9TNRzc/Bm99gEJMaQoHJ9E6Kv9QBbsldh2oMj7iXmYNEAVvNgvv5vPorG6W+XtBhQ==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/expect-type": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz",
- "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz",
+ "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@@ -2627,9 +2657,9 @@
}
},
"node_modules/express-rate-limit": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz",
- "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==",
+ "version": "7.5.1",
+ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz",
+ "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2639,7 +2669,7 @@
"url": "https://github.com/sponsors/express-rate-limit"
},
"peerDependencies": {
- "express": "^4.11 || 5 || ^5.0.0-beta.1"
+ "express": ">= 4.11"
}
},
"node_modules/extend": {
@@ -2725,11 +2755,14 @@
}
},
"node_modules/fdir": {
- "version": "6.4.5",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz",
- "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==",
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
"license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
"peerDependencies": {
"picomatch": "^3 || ^4"
},
@@ -2740,13 +2773,13 @@
}
},
"node_modules/file-entry-cache": {
- "version": "10.1.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.1.1.tgz",
- "integrity": "sha512-zcmsHjg2B2zjuBgjdnB+9q0+cWcgWfykIcsDkWDB4GTPtl1eXUA+gTI6sO0u01AqK3cliHryTU55/b2Ow1hfZg==",
+ "version": "10.1.4",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.1.4.tgz",
+ "integrity": "sha512-5XRUFc0WTtUbjfGzEwXc42tiGxQHBmtbUG1h9L2apu4SulCGN3Hqm//9D6FAolf8MYNL7f/YlJl9vy08pj5JuA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "flat-cache": "^6.1.10"
+ "flat-cache": "^6.1.13"
}
},
"node_modules/finalhandler": {
@@ -2767,29 +2800,29 @@
"node": ">= 0.8"
}
},
- "node_modules/find-up": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
- "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
+ "node_modules/find-up-simple": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz",
+ "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "locate-path": "^2.0.0"
- },
"engines": {
- "node": ">=4"
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/flat-cache": {
- "version": "6.1.10",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.10.tgz",
- "integrity": "sha512-B6/v1f0NwjxzmeOhzfXPGWpKBVA207LS7lehaVKQnFrVktcFRfkzjZZ2gwj2i1TkEUMQht7ZMJbABUT5N+V1Nw==",
+ "version": "6.1.13",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.13.tgz",
+ "integrity": "sha512-gmtS2PaUjSPa4zjObEIn4WWliKyZzYljgxODBfxugpK6q6HU9ClXzgCJ+nlcPKY9Bt090ypTOLIFWkV0jbKFjw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "cacheable": "^1.10.0",
+ "cacheable": "^1.10.4",
"flatted": "^3.3.3",
- "hookified": "^1.9.1"
+ "hookified": "^1.11.0"
}
},
"node_modules/flatted": {
@@ -2972,13 +3005,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/graceful-fs": {
- "version": "4.2.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -3016,18 +3042,24 @@
}
},
"node_modules/hookified": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.9.1.tgz",
- "integrity": "sha512-u3pxtGhKjcSXnGm1CX6aXS9xew535j3lkOCegbA6jdyh0BaAjTbXI4aslKstCr6zUNtoCxFGFKwjbSHdGrMB8g==",
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.11.0.tgz",
+ "integrity": "sha512-aDdIN3GyU5I6wextPplYdfmWCo+aLmjjVbntmX6HLD5RCi/xKsivYEBhnRD+d9224zFf008ZpLMPlWF0ZodYZw==",
"dev": true,
"license": "MIT"
},
"node_modules/hosted-git-info": {
- "version": "2.8.9",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
- "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
+ "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==",
"dev": true,
- "license": "ISC"
+ "license": "ISC",
+ "dependencies": {
+ "lru-cache": "^10.0.1"
+ },
+ "engines": {
+ "node": "^16.14.0 || >=18.0.0"
+ }
},
"node_modules/html-escaper": {
"version": "2.0.2",
@@ -3076,26 +3108,18 @@
"node": ">=0.10.0"
}
},
- "node_modules/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "node_modules/index-to-position": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz",
+ "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==",
"dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "BSD-3-Clause"
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
},
"node_modules/inherits": {
"version": "2.0.4",
@@ -3140,13 +3164,6 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
@@ -3154,22 +3171,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/is-core-module": {
- "version": "2.16.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
- "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "hasown": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-decimal": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
@@ -3219,13 +3220,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/is-utf8": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
- "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/isexe": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
@@ -3276,9 +3270,9 @@
}
},
"node_modules/istanbul-reports": {
- "version": "3.1.7",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
- "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
+ "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -3313,26 +3307,18 @@
"license": "MIT"
},
"node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
+ "argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
- "node_modules/json-parse-better-errors": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
- "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -3354,13 +3340,13 @@
}
},
"node_modules/keyv": {
- "version": "5.3.3",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.3.3.tgz",
- "integrity": "sha512-Rwu4+nXI9fqcxiEHtbkvoes2X+QfkTRo1TMkPfwzipGsJlJO/z69vqB4FNl9xJ3xCpAcbkvmEabZfPzrwN3+gQ==",
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.5.0.tgz",
+ "integrity": "sha512-QG7qR2tijh1ftOvClut4YKKg1iW6cx3GZsKoGyJPxHkGWK9oJhG9P3j5deP0QQOGDowBMVQFaP+Vm4NpGYvmIQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@keyv/serialize": "^1.0.3"
+ "@keyv/serialize": "^1.1.0"
}
},
"node_modules/levn": {
@@ -3377,37 +3363,6 @@
"node": ">= 0.8.0"
}
},
- "node_modules/load-json-file": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
- "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "graceful-fs": "^4.1.2",
- "parse-json": "^2.2.0",
- "pify": "^2.0.0",
- "pinkie-promise": "^2.0.0",
- "strip-bom": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/locate-path": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
- "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-locate": "^2.0.0",
- "path-exists": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@@ -3434,9 +3389,9 @@
}
},
"node_modules/loupe": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz",
- "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.0.tgz",
+ "integrity": "sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==",
"dev": true,
"license": "MIT"
},
@@ -3890,12 +3845,12 @@
}
},
"node_modules/minimatch": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
- "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz",
+ "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==",
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "@isaacs/brace-expansion": "^5.0.0"
},
"engines": {
"node": "20 || >=22"
@@ -3994,26 +3949,18 @@
}
},
"node_modules/normalize-package-data": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
- "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz",
+ "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
- "hosted-git-info": "^2.1.4",
- "resolve": "^1.10.0",
- "semver": "2 || 3 || 4 || 5",
- "validate-npm-package-license": "^3.0.1"
- }
- },
- "node_modules/normalize-package-data/node_modules/semver": {
- "version": "5.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
- "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver"
+ "hosted-git-info": "^7.0.0",
+ "semver": "^7.3.5",
+ "validate-npm-package-license": "^3.0.4"
+ },
+ "engines": {
+ "node": "^16.14.0 || >=18.0.0"
}
},
"node_modules/object-assign": {
@@ -4063,9 +4010,9 @@
}
},
"node_modules/openai": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/openai/-/openai-5.3.0.tgz",
- "integrity": "sha512-VIKmoF7y4oJCDOwP/oHXGzM69+x0dpGFmN9QmYO+uPbLFOmmnwO+x1GbsgUtI+6oraxomGZ566Y421oYVu191w==",
+ "version": "5.12.2",
+ "resolved": "https://registry.npmjs.org/openai/-/openai-5.12.2.tgz",
+ "integrity": "sha512-xqzHHQch5Tws5PcKR2xsZGX9xtch+JQFz5zb14dGqlshmmDAFBFEWmeIpf7wVqWV+w7Emj7jRgkNJakyKE0tYQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -4103,56 +4050,20 @@
}
},
"node_modules/p-limit": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz",
- "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.0.0.tgz",
+ "integrity": "sha512-WeCdPG5OjujcMWjSkOS0kt3bo+LmroXLmOnJ4SPhZfz5pffQxDUNcYscbZgyGwKf9r9z7gRfKjDNno5cZyQAZQ==",
"license": "MIT",
"dependencies": {
- "yocto-queue": "^1.1.1"
+ "yocto-queue": "^1.2.1"
},
"engines": {
- "node": ">=18"
+ "node": ">=20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/p-locate": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
- "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-limit": "^1.1.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/p-locate/node_modules/p-limit": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
- "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-try": "^1.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/p-try": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
- "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
@@ -4180,16 +4091,21 @@
}
},
"node_modules/parse-json": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
- "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz",
+ "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "error-ex": "^1.2.0"
+ "@babel/code-frame": "^7.26.2",
+ "index-to-position": "^1.1.0",
+ "type-fest": "^4.39.1"
},
"engines": {
- "node": ">=0.10.0"
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/parseurl": {
@@ -4202,16 +4118,6 @@
"node": ">= 0.8"
}
},
- "node_modules/path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -4222,13 +4128,6 @@
"node": ">=8"
}
},
- "node_modules/path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/path-scurry": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
@@ -4263,21 +4162,6 @@
"node": ">=16"
}
},
- "node_modules/path-type": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
- "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "graceful-fs": "^4.1.2",
- "pify": "^2.0.0",
- "pinkie-promise": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
@@ -4286,9 +4170,9 @@
"license": "MIT"
},
"node_modules/pathval": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
- "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
+ "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4303,9 +4187,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
- "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4315,39 +4199,6 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
- "node_modules/pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/pinkie": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
- "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/pinkie-promise": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
- "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "pinkie": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/pkce-challenge": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
@@ -4366,9 +4217,9 @@
"license": "MIT"
},
"node_modules/postcss": {
- "version": "8.5.4",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
- "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
+ "version": "8.5.6",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"dev": true,
"funding": [
{
@@ -4483,131 +4334,42 @@
"require-from-string": "^2.0.2"
}
},
- "node_modules/rc-config-loader/node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true,
- "license": "Python-2.0"
- },
- "node_modules/rc-config-loader/node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/read-pkg": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
- "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "load-json-file": "^1.0.0",
- "normalize-package-data": "^2.3.2",
- "path-type": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/read-pkg-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
- "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "find-up": "^2.0.0",
- "read-pkg": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/read-pkg-up/node_modules/load-json-file": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
- "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
+ "node_modules/read-package-up": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz",
+ "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "graceful-fs": "^4.1.2",
- "parse-json": "^4.0.0",
- "pify": "^3.0.0",
- "strip-bom": "^3.0.0"
+ "find-up-simple": "^1.0.0",
+ "read-pkg": "^9.0.0",
+ "type-fest": "^4.6.0"
},
"engines": {
- "node": ">=4"
- }
- },
- "node_modules/read-pkg-up/node_modules/parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "error-ex": "^1.3.1",
- "json-parse-better-errors": "^1.0.1"
+ "node": ">=18"
},
- "engines": {
- "node": ">=4"
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/read-pkg-up/node_modules/path-type": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
- "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "node_modules/read-pkg": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz",
+ "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "pify": "^3.0.0"
+ "@types/normalize-package-data": "^2.4.3",
+ "normalize-package-data": "^6.0.0",
+ "parse-json": "^8.0.0",
+ "type-fest": "^4.6.0",
+ "unicorn-magic": "^0.1.0"
},
"engines": {
- "node": ">=4"
- }
- },
- "node_modules/read-pkg-up/node_modules/pify": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
- "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/read-pkg-up/node_modules/read-pkg": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
- "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "load-json-file": "^4.0.0",
- "normalize-package-data": "^2.3.2",
- "path-type": "^3.0.0"
+ "node": ">=18"
},
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/read-pkg-up/node_modules/strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/remark-footnotes": {
@@ -4689,27 +4451,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/resolve": {
- "version": "1.22.10",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
- "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-core-module": "^2.16.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/resolve-pkg-maps": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
@@ -4721,13 +4462,13 @@
}
},
"node_modules/rollup": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.42.0.tgz",
- "integrity": "sha512-LW+Vse3BJPyGJGAJt1j8pWDKPd73QM8cRXYK1IxOBgL2AGLu7Xd2YOW0M2sLUBCkF5MshXXtMApyEAEzMVMsnw==",
+ "version": "4.46.3",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.3.tgz",
+ "integrity": "sha512-RZn2XTjXb8t5g13f5YclGoilU/kwT696DIkY3sywjdZidNSi3+vseaQov7D7BZXVJCPv3pDWUN69C78GGbXsKw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/estree": "1.0.7"
+ "@types/estree": "1.0.8"
},
"bin": {
"rollup": "dist/bin/rollup"
@@ -4737,36 +4478,29 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.42.0",
- "@rollup/rollup-android-arm64": "4.42.0",
- "@rollup/rollup-darwin-arm64": "4.42.0",
- "@rollup/rollup-darwin-x64": "4.42.0",
- "@rollup/rollup-freebsd-arm64": "4.42.0",
- "@rollup/rollup-freebsd-x64": "4.42.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.42.0",
- "@rollup/rollup-linux-arm-musleabihf": "4.42.0",
- "@rollup/rollup-linux-arm64-gnu": "4.42.0",
- "@rollup/rollup-linux-arm64-musl": "4.42.0",
- "@rollup/rollup-linux-loongarch64-gnu": "4.42.0",
- "@rollup/rollup-linux-powerpc64le-gnu": "4.42.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.42.0",
- "@rollup/rollup-linux-riscv64-musl": "4.42.0",
- "@rollup/rollup-linux-s390x-gnu": "4.42.0",
- "@rollup/rollup-linux-x64-gnu": "4.42.0",
- "@rollup/rollup-linux-x64-musl": "4.42.0",
- "@rollup/rollup-win32-arm64-msvc": "4.42.0",
- "@rollup/rollup-win32-ia32-msvc": "4.42.0",
- "@rollup/rollup-win32-x64-msvc": "4.42.0",
+ "@rollup/rollup-android-arm-eabi": "4.46.3",
+ "@rollup/rollup-android-arm64": "4.46.3",
+ "@rollup/rollup-darwin-arm64": "4.46.3",
+ "@rollup/rollup-darwin-x64": "4.46.3",
+ "@rollup/rollup-freebsd-arm64": "4.46.3",
+ "@rollup/rollup-freebsd-x64": "4.46.3",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.46.3",
+ "@rollup/rollup-linux-arm-musleabihf": "4.46.3",
+ "@rollup/rollup-linux-arm64-gnu": "4.46.3",
+ "@rollup/rollup-linux-arm64-musl": "4.46.3",
+ "@rollup/rollup-linux-loongarch64-gnu": "4.46.3",
+ "@rollup/rollup-linux-ppc64-gnu": "4.46.3",
+ "@rollup/rollup-linux-riscv64-gnu": "4.46.3",
+ "@rollup/rollup-linux-riscv64-musl": "4.46.3",
+ "@rollup/rollup-linux-s390x-gnu": "4.46.3",
+ "@rollup/rollup-linux-x64-gnu": "4.46.3",
+ "@rollup/rollup-linux-x64-musl": "4.46.3",
+ "@rollup/rollup-win32-arm64-msvc": "4.46.3",
+ "@rollup/rollup-win32-ia32-msvc": "4.46.3",
+ "@rollup/rollup-win32-x64-msvc": "4.46.3",
"fsevents": "~2.3.2"
}
},
- "node_modules/rollup/node_modules/@types/estree": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
- "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/router": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
@@ -5048,9 +4782,9 @@
}
},
"node_modules/spdx-license-ids": {
- "version": "3.0.21",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz",
- "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==",
+ "version": "3.0.22",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz",
+ "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==",
"dev": true,
"license": "CC0-1.0"
},
@@ -5189,23 +4923,10 @@
"node": ">=8"
}
},
- "node_modules/strip-bom": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
- "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-utf8": "^0.2.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/strip-json-comments": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.2.tgz",
- "integrity": "sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz",
+ "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -5251,19 +4972,6 @@
"node": ">=8"
}
},
- "node_modules/supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/table": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz",
@@ -5389,45 +5097,44 @@
"license": "MIT"
},
"node_modules/textlint": {
- "version": "14.8.0",
- "resolved": "https://registry.npmjs.org/textlint/-/textlint-14.8.0.tgz",
- "integrity": "sha512-1+Y78J7b509CagmxxhceRRF99KXNuUBjstMIGc2pp/CkjY/vdr6s1AObWMiiWF7asm3UFmgfqMxl+tNIlvuT5Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@modelcontextprotocol/sdk": "^1.12.1",
- "@textlint/ast-node-types": "^14.8.0",
- "@textlint/ast-traverse": "^14.8.0",
- "@textlint/config-loader": "^14.8.0",
- "@textlint/feature-flag": "^14.8.0",
- "@textlint/fixer-formatter": "^14.8.0",
- "@textlint/kernel": "^14.8.0",
- "@textlint/linter-formatter": "^14.8.0",
- "@textlint/module-interop": "^14.8.0",
- "@textlint/resolver": "^14.8.0",
- "@textlint/textlint-plugin-markdown": "^14.8.0",
- "@textlint/textlint-plugin-text": "^14.8.0",
- "@textlint/types": "^14.8.0",
- "@textlint/utils": "^14.8.0",
+ "version": "15.2.1",
+ "resolved": "https://registry.npmjs.org/textlint/-/textlint-15.2.1.tgz",
+ "integrity": "sha512-FChEKsi81lcjv9ZucXpbMNA3HQw27eafUw0F7fyiX56u8eNr2rSb5oAtZO0DF6a+/bNDe8W7NG3BxOAPsWFoDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@modelcontextprotocol/sdk": "^1.15.1",
+ "@textlint/ast-node-types": "15.2.1",
+ "@textlint/ast-traverse": "15.2.1",
+ "@textlint/config-loader": "15.2.1",
+ "@textlint/feature-flag": "15.2.1",
+ "@textlint/fixer-formatter": "15.2.1",
+ "@textlint/kernel": "15.2.1",
+ "@textlint/linter-formatter": "15.2.1",
+ "@textlint/module-interop": "15.2.1",
+ "@textlint/resolver": "15.2.1",
+ "@textlint/textlint-plugin-markdown": "15.2.1",
+ "@textlint/textlint-plugin-text": "15.2.1",
+ "@textlint/types": "15.2.1",
+ "@textlint/utils": "15.2.1",
"debug": "^4.4.1",
- "file-entry-cache": "^10.0.5",
+ "file-entry-cache": "^10.1.1",
"glob": "^10.4.5",
"md5": "^2.3.0",
"mkdirp": "^0.5.6",
- "optionator": "^0.9.3",
+ "optionator": "^0.9.4",
"path-to-glob-pattern": "^2.0.1",
"rc-config-loader": "^4.1.3",
- "read-pkg": "^1.1.0",
- "read-pkg-up": "^3.0.0",
+ "read-package-up": "^11.0.0",
"structured-source": "^4.0.0",
"unique-concat": "^0.2.2",
- "zod": "^3.25.56"
+ "zod": "^3.25.76"
},
"bin": {
"textlint": "bin/textlint.js"
},
"engines": {
- "node": ">=18.14.0"
+ "node": ">=20.0.0"
}
},
"node_modules/textlint-filter-rule-comments": {
@@ -5441,28 +5148,21 @@
}
},
"node_modules/textlint-rule-helper": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/textlint-rule-helper/-/textlint-rule-helper-2.3.1.tgz",
- "integrity": "sha512-b1bijvyiUmKinfFE5hkQMSXs3Ky8jyZ3Y6SOoTRJKV9HLL2LWUVFAUezO7z4FpAkVvYruDYWCwA5qWV8GmvyUw==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/textlint-rule-helper/-/textlint-rule-helper-2.5.0.tgz",
+ "integrity": "sha512-QIbFPtyqLy0g5BJn8mryk9iHzGYicNaFIpLFPiEnb4RXxrEGeQ2W2aARQ9yEXLIAqo+OwK4ndWBAWkbgJEPzTQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@textlint/ast-node-types": "^13.4.1",
+ "@textlint/ast-node-types": "^15.2.1",
"structured-source": "^4.0.0",
"unist-util-visit": "^2.0.3"
}
},
- "node_modules/textlint-rule-helper/node_modules/@textlint/ast-node-types": {
- "version": "13.4.1",
- "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-13.4.1.tgz",
- "integrity": "sha512-qrZyhCh8Ekk6nwArx3BROybm9BnX6vF7VcZbijetV/OM3yfS4rTYhoMWISmhVEP2H2re0CtWEyMl/XF+WdvVLQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/textlint-rule-terminology": {
- "version": "5.2.12",
- "resolved": "https://registry.npmjs.org/textlint-rule-terminology/-/textlint-rule-terminology-5.2.12.tgz",
- "integrity": "sha512-qLyuqbGN7GBqKR7NT2yLyo8mmYmoCkk8bu3szvLxUkM+1Cc0D9G6MDyaYFrMM26GZuNbTREmuFxon/vTBDR/pw==",
+ "version": "5.2.14",
+ "resolved": "https://registry.npmjs.org/textlint-rule-terminology/-/textlint-rule-terminology-5.2.14.tgz",
+ "integrity": "sha512-OYvLq+K+HpQqxWhV9MXb/jnND8oWxUbZK+OmrqO8auO2TWMky22ZlR8qoAmlzYbRMR1S3LJyifFlThZoXbD1uA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5506,9 +5206,9 @@
}
},
"node_modules/tinypool": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.0.tgz",
- "integrity": "sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
+ "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -5567,9 +5267,9 @@
}
},
"node_modules/tsx": {
- "version": "4.19.4",
- "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.4.tgz",
- "integrity": "sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q==",
+ "version": "4.20.4",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.4.tgz",
+ "integrity": "sha512-yyxBKfORQ7LuRt/BQKBXrpcq59ZvSW0XxwfjAt3w2/8PmdxaFzijtMhTawprSHhpzeM5BgU2hXHG3lklIERZXg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5608,6 +5308,19 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/type-fest": {
+ "version": "4.41.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
+ "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/type-is": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
@@ -5624,9 +5337,9 @@
}
},
"node_modules/typescript": {
- "version": "5.8.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
- "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "version": "5.9.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
+ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -5656,6 +5369,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/unicorn-magic": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz",
+ "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/unified": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz",
@@ -5866,24 +5592,24 @@
}
},
"node_modules/vite": {
- "version": "6.3.5",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
- "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.2.tgz",
+ "integrity": "sha512-J0SQBPlQiEXAF7tajiH+rUooJPo0l8KQgyg4/aMunNtrOa7bwuZJsJbDWzeljqQpgftxuq5yNJxQ91O9ts29UQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.25.0",
- "fdir": "^6.4.4",
- "picomatch": "^4.0.2",
- "postcss": "^8.5.3",
- "rollup": "^4.34.9",
- "tinyglobby": "^0.2.13"
+ "fdir": "^6.4.6",
+ "picomatch": "^4.0.3",
+ "postcss": "^8.5.6",
+ "rollup": "^4.43.0",
+ "tinyglobby": "^0.2.14"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
- "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ "node": "^20.19.0 || >=22.12.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
@@ -5892,14 +5618,14 @@
"fsevents": "~2.3.3"
},
"peerDependencies": {
- "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "@types/node": "^20.19.0 || >=22.12.0",
"jiti": ">=1.21.0",
- "less": "*",
+ "less": "^4.0.0",
"lightningcss": "^1.21.0",
- "sass": "*",
- "sass-embedded": "*",
- "stylus": "*",
- "sugarss": "*",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
"terser": "^5.16.0",
"tsx": "^4.8.1",
"yaml": "^2.4.2"
@@ -5941,9 +5667,9 @@
}
},
"node_modules/vite-node": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.3.tgz",
- "integrity": "sha512-gc8aAifGuDIpZHrPjuHyP4dpQmYXqWw7D1GmDnWeNWP654UEXzVfQ5IHPSK5HaHkwB/+p1atpYpSdw/2kOv8iQ==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz",
+ "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5964,20 +5690,20 @@
}
},
"node_modules/vitest": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.3.tgz",
- "integrity": "sha512-E6U2ZFXe3N/t4f5BwUaVCKRLHqUpk1CBWeMh78UT4VaTPH/2dyvH6ALl29JTovEPu9dVKr/K/J4PkXgrMbw4Ww==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz",
+ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/chai": "^5.2.2",
- "@vitest/expect": "3.2.3",
- "@vitest/mocker": "3.2.3",
- "@vitest/pretty-format": "^3.2.3",
- "@vitest/runner": "3.2.3",
- "@vitest/snapshot": "3.2.3",
- "@vitest/spy": "3.2.3",
- "@vitest/utils": "3.2.3",
+ "@vitest/expect": "3.2.4",
+ "@vitest/mocker": "3.2.4",
+ "@vitest/pretty-format": "^3.2.4",
+ "@vitest/runner": "3.2.4",
+ "@vitest/snapshot": "3.2.4",
+ "@vitest/spy": "3.2.4",
+ "@vitest/utils": "3.2.4",
"chai": "^5.2.0",
"debug": "^4.4.1",
"expect-type": "^1.2.1",
@@ -5988,10 +5714,10 @@
"tinybench": "^2.9.0",
"tinyexec": "^0.3.2",
"tinyglobby": "^0.2.14",
- "tinypool": "^1.1.0",
+ "tinypool": "^1.1.1",
"tinyrainbow": "^2.0.0",
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
- "vite-node": "3.2.3",
+ "vite-node": "3.2.4",
"why-is-node-running": "^2.3.0"
},
"bin": {
@@ -6007,8 +5733,8 @@
"@edge-runtime/vm": "*",
"@types/debug": "^4.1.12",
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
- "@vitest/browser": "3.2.3",
- "@vitest/ui": "3.2.3",
+ "@vitest/browser": "3.2.4",
+ "@vitest/ui": "3.2.4",
"happy-dom": "*",
"jsdom": "*"
},
@@ -6193,9 +5919,9 @@
}
},
"node_modules/zod": {
- "version": "3.25.57",
- "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.57.tgz",
- "integrity": "sha512-6tgzLuwVST5oLUxXTmBqoinKMd3JeesgbgseXeFasKKj8Q1FCZrHnbqJOyiEvr4cVAlbug+CgIsmJ8cl/pU5FA==",
+ "version": "3.25.76",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"dev": true,
"license": "MIT",
"funding": {
@@ -6203,9 +5929,9 @@
}
},
"node_modules/zod-to-json-schema": {
- "version": "3.24.5",
- "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz",
- "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==",
+ "version": "3.24.6",
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz",
+ "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==",
"dev": true,
"license": "ISC",
"peerDependencies": {
diff --git a/package.json b/package.json
index 3ff85fb4..c1a52f13 100644
--- a/package.json
+++ b/package.json
@@ -54,20 +54,22 @@
"@octokit/plugin-rest-endpoint-methods": "^16.0.0",
"@octokit/request-error": "^7.0.0",
"minimatch": "^10.0.1",
- "p-limit": "^6.2.0",
+ "p-limit": "^7.0.0",
"which": "^5.0.0"
},
"devDependencies": {
- "@biomejs/biome": "^1.9.4",
+ "@biomejs/biome": "^2.2.0",
"@octokit/types": "^14.0.0",
"@octokit/webhooks-types": "^7.6.1",
- "@types/node": "^22.15.29",
+ "@types/js-yaml": "^4.0.9",
+ "@types/node": "^22.17.2",
"@types/which": "^3.0.4",
"@vercel/ncc": "^0.38.3",
"@vitest/coverage-v8": "^3.1.3",
+ "js-yaml": "^4.1.0",
"make-coverage-badge": "^1.2.0",
"openai": "latest",
- "textlint": "^14.8.0",
+ "textlint": "^15.2.1",
"textlint-filter-rule-comments": "^1.2.2",
"textlint-rule-terminology": "^5.2.12",
"ts-deepmerge": "^7.0.2",
diff --git a/scripts/dev-parse-modules.ts b/scripts/dev-parse-modules.ts
index e395c7fa..f472f80e 100644
--- a/scripts/dev-parse-modules.ts
+++ b/scripts/dev-parse-modules.ts
@@ -37,11 +37,11 @@ async function main() {
process.env['INPUT_MODULE-CHANGE-EXCLUDE-PATTERNS'] = '.gitignore,*.md';
// Initialize
- const config = getConfig();
- const context = getContext();
+ const _config = getConfig();
+ const _context = getContext();
// Test with empty tags and releases for now
- const modules = parseTerraformModules(
+ const _modules = parseTerraformModules(
[
{
message: 'feat: add screenshots for documentation',
diff --git a/src/config.ts b/src/config.ts
index 4a620f18..f5e21e8e 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -1,30 +1,11 @@
import type { Config } from '@/types';
-import { endGroup, getBooleanInput, getInput, info, startGroup } from '@actions/core';
+import { VALID_TAG_DIRECTORY_SEPARATORS, VERSION_TAG_REGEX } from '@/utils/constants';
+import { createConfigFromInputs } from '@/utils/metadata';
+import { endGroup, info, startGroup } from '@actions/core';
// Keep configInstance private to this module
let configInstance: Config | null = null;
-/**
- * Retrieves an array of values from a comma-separated input string. Duplicates any empty values
- * are removed and each value is trimmed of whitespace.
- *
- * @param inputName - Name of the input to retrieve.
- * @param required - Whether the input is required.
- * @returns An array of trimmed and filtered values.
- */
-const getArrayInput = (inputName: string, required: boolean): string[] => {
- const input = getInput(inputName, { required });
-
- return Array.from(
- new Set(
- input
- .split(',')
- .map((item: string) => item.trim())
- .filter(Boolean),
- ),
- );
-};
-
/**
* Clears the cached config instance during testing.
*
@@ -58,24 +39,8 @@ function initializeConfig(): Config {
try {
startGroup('Initializing Config');
- // Initialize the config instance
- configInstance = {
- majorKeywords: getArrayInput('major-keywords', true),
- minorKeywords: getArrayInput('minor-keywords', true),
- patchKeywords: getArrayInput('patch-keywords', true),
- defaultFirstTag: getInput('default-first-tag', { required: true }),
- terraformDocsVersion: getInput('terraform-docs-version', { required: true }),
- deleteLegacyTags: getBooleanInput('delete-legacy-tags', { required: true }),
- disableWiki: getBooleanInput('disable-wiki', { required: true }),
- wikiSidebarChangelogMax: Number.parseInt(getInput('wiki-sidebar-changelog-max', { required: true }), 10),
- disableBranding: getBooleanInput('disable-branding', { required: true }),
- githubToken: getInput('github_token', { required: true }),
- modulePathIgnore: getArrayInput('module-path-ignore', false),
- moduleChangeExcludePatterns: getArrayInput('module-change-exclude-patterns', false),
- moduleAssetExcludePatterns: getArrayInput('module-asset-exclude-patterns', false),
- useSSHSourceFormat: getBooleanInput('use-ssh-source-format', { required: true }),
- wikiUsageTemplate: getInput('wiki-usage-template', { required: false }),
- };
+ // Initialize the config instance using action metadata
+ configInstance = createConfigFromInputs();
// Validate that *.tf is not in excludePatterns
if (configInstance.moduleChangeExcludePatterns.some((pattern) => pattern === '*.tf')) {
@@ -85,13 +50,35 @@ function initializeConfig(): Config {
throw new TypeError('Asset exclude patterns cannot contain "*.tf" as these files are required');
}
- // Validate that we have a valid first tag. For now, must be v#.#.#
-
// Validate WikiSidebar Changelog Max is a number and greater than zero
if (configInstance.wikiSidebarChangelogMax < 1 || Number.isNaN(configInstance.wikiSidebarChangelogMax)) {
throw new TypeError('Wiki Sidebar Change Log Max must be an integer greater than or equal to one');
}
+ // Validate tag directory separator
+ if (configInstance.tagDirectorySeparator.length !== 1) {
+ throw new TypeError('Tag directory separator must be exactly one character');
+ }
+ if (!VALID_TAG_DIRECTORY_SEPARATORS.includes(configInstance.tagDirectorySeparator)) {
+ throw new TypeError(
+ `Tag directory separator must be one of: ${VALID_TAG_DIRECTORY_SEPARATORS.join(', ')}. Got: '${
+ configInstance.tagDirectorySeparator
+ }'`,
+ );
+ }
+ // Validate default first tag format
+ if (!VERSION_TAG_REGEX.test(configInstance.defaultFirstTag)) {
+ throw new TypeError(
+ `Default first tag must be in format v#.#.# or #.#.# (e.g., v1.0.0 or 1.0.0). Got: '${configInstance.defaultFirstTag}'`,
+ );
+ }
+
+ // If we aren't using "v" prefix but the default first tag was specified with a "v"
+ // prefix, then strip this to enforce.
+ if (!configInstance.useVersionPrefix && configInstance.defaultFirstTag.startsWith('v')) {
+ configInstance.defaultFirstTag = configInstance.defaultFirstTag.substring(1);
+ }
+
info(`Major Keywords: ${configInstance.majorKeywords.join(', ')}`);
info(`Minor Keywords: ${configInstance.minorKeywords.join(', ')}`);
info(`Patch Keywords: ${configInstance.patchKeywords.join(', ')}`);
@@ -104,6 +91,8 @@ function initializeConfig(): Config {
info(`Module Change Exclude Patterns: ${configInstance.moduleChangeExcludePatterns.join(', ')}`);
info(`Module Asset Exclude Patterns: ${configInstance.moduleAssetExcludePatterns.join(', ')}`);
info(`Use SSH Source Format: ${configInstance.useSSHSourceFormat}`);
+ info(`Tag Directory Separator: ${configInstance.tagDirectorySeparator}`);
+ info(`Use Version Prefix: ${configInstance.useVersionPrefix}`);
return configInstance;
} finally {
@@ -118,7 +107,7 @@ export function getConfig(): Config {
// For backward compatibility and existing usage
export const config: Config = new Proxy({} as Config, {
- get(target, prop) {
+ get(_target, prop) {
return getConfig()[prop as keyof Config];
},
});
diff --git a/src/context.ts b/src/context.ts
index a4d76a65..0da5df19 100644
--- a/src/context.ts
+++ b/src/context.ts
@@ -165,7 +165,7 @@ export const getContext = (): Context => {
// For backward compatibility and existing usage
export const context: Context = new Proxy({} as Context, {
- get(target, prop) {
+ get(_target, prop) {
return getContext()[prop as keyof Context];
},
});
diff --git a/src/templating.ts b/src/templating.ts
deleted file mode 100644
index da3eec67..00000000
--- a/src/templating.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * Renders a template string by replacing placeholders with provided values.
- *
- * @param template The template string containing placeholders in the format `{{key}}`.
- * @param variables An object where keys correspond to placeholder names and values are their replacements.
- * @returns The rendered string with placeholders replaced.
- */
-export const render = (template: string, variables: Record): string => {
- return template.replace(/\{\{(\w+)\}\}/g, (placeholder, key) => {
- return key in variables ? variables[key] : placeholder;
- });
-};
diff --git a/src/terraform-module.ts b/src/terraform-module.ts
index 7da8f36f..c18d017b 100644
--- a/src/terraform-module.ts
+++ b/src/terraform-module.ts
@@ -2,8 +2,14 @@ import { relative } from 'node:path';
import { config } from '@/config';
import { context } from '@/context';
import type { CommitDetails, GitHubRelease, ReleaseReason, ReleaseType } from '@/types';
-import { MODULE_TAG_REGEX, RELEASE_REASON, RELEASE_TYPE, VERSION_TAG_REGEX } from '@/utils/constants';
-import { removeTrailingCharacters } from '@/utils/string';
+import {
+ MODULE_TAG_REGEX,
+ RELEASE_REASON,
+ RELEASE_TYPE,
+ VALID_TAG_DIRECTORY_SEPARATORS,
+ VERSION_TAG_REGEX,
+} from '@/utils/constants';
+import { removeLeadingCharacters, removeTrailingCharacters } from '@/utils/string';
import { endGroup, info, startGroup } from '@actions/core';
/**
@@ -213,11 +219,14 @@ export class TerraformModule {
* @returns {string | null} The version string including any prefixes (e.g., 'v1.2.3' or '1.2.3'), or null if no tags exist.
*/
public getLatestTagVersion(): string | null {
- if (this.tags.length === 0) {
+ const latestTag = this.getLatestTag();
+ if (latestTag === null) {
return null;
}
- return this.tags[0].replace(`${this.name}/`, '');
+ const match = MODULE_TAG_REGEX.exec(latestTag);
+
+ return match ? match[3] : null;
}
/**
@@ -452,8 +461,7 @@ export class TerraformModule {
semver[2]++;
}
- // Hard coding "v" for now. Potentially fixing in the future.
- return `v${semver.join('.')}`;
+ return `${config.useVersionPrefix ? 'v' : ''}${semver.join('.')}`;
}
/**
@@ -476,41 +484,49 @@ export class TerraformModule {
return null;
}
- return `${this.name}/${releaseTagVersion}`;
+ return `${this.name}${config.tagDirectorySeparator}${releaseTagVersion}`;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Helper
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
/**
- * Safely extracts the numerical version string from a tag, avoiding regex vulnerabilities.
- * Handles tags in format: moduleName/vX.Y.Z or moduleName/X.Y.Z
- * Also validates that tag format matches expected pattern and returns only the numerical part.
+ * Extracts and validates the version string from a Terraform module tag.
*
- * @param {string} tag - The tag string to extract version from
- * @returns {string} The numerical version string (e.g., "1.2.3")
- * @throws {Error} If the tag does not match the required format
+ * Uses the MODULE_TAG_REGEX to validate the tag format and extract version components.
+ * This method leverages the static validation logic to ensure consistent tag processing
+ * across different separator formats (/, -, _, .).
+ *
+ * @param {string} tag - The tag string to extract version from (e.g., "module/v1.2.3", "module-v1.2.3")
+ * @returns {string} The numerical version string without prefix (e.g., "1.2.3")
+ * @throws {Error} If the tag does not match the required format or is not associated with this module
*/
private extractVersionFromTag(tag: string): string {
- // Validate tag format - must start with module name followed by slash
- if (!tag.startsWith(`${this.name}/`)) {
+ // Use the static validation method to ensure the tag is associated with this module
+ if (!TerraformModule.isModuleAssociatedWithTag(this.name, tag)) {
throw new Error(
- `Invalid tag format: '${tag}'. Expected format: '${this.name}/v#.#.#' or '${this.name}/#.#.#' for module.`,
+ `Invalid tag format: '${tag}'. Expected format: '${this.name}[separator]v#.#.#' or '${this.name}[separator]#.#.#'.`,
);
}
- // Extract everything after the last slash
- const versionPart = tag.substring(tag.lastIndexOf('/') + 1);
-
- // Validate that the version part matches the expected format
- if (!VERSION_TAG_REGEX.test(versionPart)) {
+ // Parse the tag using MODULE_TAG_REGEX to extract version components
+ // Note: This will never be null since TerraformModule.isModuleAssociatedWithTag already checks for this;
+ // however, for typing, we'll just recheck.
+ const match = MODULE_TAG_REGEX.exec(tag);
+ /* v8 ignore next 5 */
+ if (!match) {
throw new Error(
- `Invalid tag format: '${tag}'. Expected format: '${this.name}/v#.#.#' or '${this.name}/#.#.#' for module.`,
+ `Invalid tag format: '${tag}'. Expected format: '${this.name}[separator]v#.#.#' or '${this.name}[separator]#.#.#'.`,
);
}
- // Return only the numerical part, stripping the 'v' prefix if present
- return versionPart.startsWith('v') ? versionPart.substring(1) : versionPart;
+ // Extract the numerical version components (groups 4, 5, 6 are major.minor.patch)
+ const major = match[4];
+ const minor = match[5];
+ const patch = match[6];
+
+ return `${major}.${minor}.${patch}`;
}
/**
@@ -614,50 +630,68 @@ export class TerraformModule {
*
* The function transforms the directory path by:
* - Trimming whitespace
- * - Replacing invalid characters with hyphens
- * - Normalizing slashes
- * - Removing leading/trailing slashes
- * - Handling consecutive dots and hyphens
- * - Removing any remaining whitespace
* - Converting to lowercase (for consistency)
- * - Removing trailing dots, hyphens, and underscores
+ * - Normalizing path separators (both backslashes and forward slashes) to the configured tag directory separator
+ * - Replacing invalid characters with hyphens (preserving only alphanumeric, "/", ".", "-", "_")
+ * - Normalizing consecutive special characters ("/", ".", "-", "_") to single instances
+ * - Removing leading/trailing special characters ("/", ".", "-", "_") using safe string operations
*
* @param {string} terraformDirectory - The relative directory path from which to generate the module name.
* @returns {string} A valid Terraform module name based on the provided directory path.
*/
public static getTerraformModuleNameFromRelativePath(terraformDirectory: string): string {
- const cleanedDirectory = terraformDirectory
+ let name = terraformDirectory
.trim()
- .replace(/[^a-zA-Z0-9/_-]+/g, '-')
- .replace(/\/{2,}/g, '/')
- .replace(/\/\.+/g, '/')
- .replace(/(^\/|\/$)/g, '')
- .replace(/\.\.+/g, '.')
- .replace(/--+/g, '-')
- .replace(/\s+/g, '')
- .toLowerCase();
- return removeTrailingCharacters(cleanedDirectory, ['.', '-', '_']);
+ .toLowerCase()
+ .replace(/[/\\]/g, config.tagDirectorySeparator) // Normalize backslashes and forward slashes to configured separator
+ .replace(/[^a-zA-Z0-9/._-]+/g, '-') // Replace invalid characters with hyphens (preserve alphanumeric, /, ., _, -)
+ .replace(/[/._-]{2,}/g, (match) => match[0]); // Normalize consecutive special characters to single instances
+
+ // Remove leading/trailing special characters safely without regex backtracking
+ name = removeLeadingCharacters(name, VALID_TAG_DIRECTORY_SEPARATORS);
+ name = removeTrailingCharacters(name, VALID_TAG_DIRECTORY_SEPARATORS);
+
+ return name;
}
/**
* Static utility to check if a tag is associated with a given module name.
- * Supports both versioned tags ({moduleName}/v#.#.#) and non-versioned tags ({moduleName}/#.#.#).
+ * Supports multiple directory separators and handles cases where tagging schemes
+ * may have changed over time (e.g., from 'module-name/v1.0.0' to 'module-name-v1.1.0').
*
- * @param {string} moduleName - The Terraform module name
+ * @param {string} moduleName - The Terraform module name (assumed to be cleaned)
* @param {string} tag - The tag to check
* @returns {boolean} True if the tag belongs to the module and has valid version format
*/
public static isModuleAssociatedWithTag(moduleName: string, tag: string): boolean {
- // Check if tag starts with exactly the module name followed by a slash
- if (!tag.startsWith(`${moduleName}/`)) {
+ // Use the existing MODULE_TAG_REGEX to parse the tag and extract module name + version
+ const match = MODULE_TAG_REGEX.exec(tag);
+ if (!match) {
+ // The tag doesn't match the expected "module-name/version" format
return false;
}
- // Extract the version part after the module name and slash
- const versionPart = tag.substring(moduleName.length + 1);
+ // Extract the module name part from the tag (group 1)
+ const moduleNameFromTag = match[1];
+
+ // Define a consistent separator to normalize module names
+ const NORMALIZE_SEPARATOR = '|';
+
+ // Normalize both the input moduleName and the extracted module name from the tag.
+ // This allows for comparison even if the tagging scheme changed over time
+ // (e.g., from 'my/module/v1.0.0' to 'my-module-v1.1.0').
+ const normalizeName = (name: string): string => {
+ // Replace all valid tag directory separators with a consistent separator
+ // This handles cases where different separators were used in different tags
+ let normalized = name;
+ for (const separator of VALID_TAG_DIRECTORY_SEPARATORS) {
+ normalized = normalized.replaceAll(separator, NORMALIZE_SEPARATOR);
+ }
+ return normalized;
+ };
- // Check if version part matches either v#.#.# or #.#.# format
- return VERSION_TAG_REGEX.test(versionPart);
+ // Compare the normalized names to determine if they match
+ return normalizeName(moduleName) === normalizeName(moduleNameFromTag);
}
/**
@@ -696,8 +730,9 @@ export class TerraformModule {
* Determines an array of Terraform tags that need to be deleted.
*
* Identifies tags that belong to modules no longer present in the current
- * module list by filtering tags that match the pattern {moduleName}/vX.Y.Z
- * where the module name is not in the current modules.
+ * module list by checking if any current module is associated with each tag.
+ * This approach leverages the robust tag association logic that handles
+ * different separator schemes over time.
*
* @param {string[]} allTags - A list of all tags associated with the modules.
* @param {TerraformModule[]} terraformModules - An array of Terraform modules.
@@ -706,16 +741,12 @@ export class TerraformModule {
public static getTagsToDelete(allTags: string[], terraformModules: TerraformModule[]): string[] {
startGroup('Finding all Terraform tags that should be deleted');
- // Get module names from current terraformModules (these exist in source)
- const moduleNamesFromModules = new Set(terraformModules.map((module) => module.name));
-
- // Filter tags that belong to modules no longer in the current module list
+ // Filter tags that are not associated with any current module
const tagsToRemove = allTags
.filter((tag) => {
- // Extract the Terraform module name from tag by removing the version suffix
- const match = MODULE_TAG_REGEX.exec(tag);
- const moduleName = match ? match[1] : tag;
- return !moduleNamesFromModules.has(moduleName);
+ // Check if ANY current module is associated with this tag
+ // This handles cases where tagging schemes changed over time
+ return !terraformModules.some((module) => TerraformModule.isModuleAssociatedWithTag(module.name, tag));
})
.sort((a, b) => a.localeCompare(b));
@@ -731,8 +762,9 @@ export class TerraformModule {
* Determines an array of Terraform releases that need to be deleted.
*
* Identifies releases that belong to modules no longer present in the current
- * module list by filtering releases that match the pattern {moduleName}/vX.Y.Z
- * where the module name is not in the current modules.
+ * module list by checking if any current module is associated with each release tag.
+ * This approach leverages the robust tag association logic that handles
+ * different separator schemes over time.
*
* @param {GitHubRelease[]} allReleases - A list of all releases associated with the modules.
* @param {TerraformModule[]} terraformModules - An array of Terraform modules.
@@ -749,16 +781,14 @@ export class TerraformModule {
): GitHubRelease[] {
startGroup('Finding all Terraform releases that should be deleted');
- // Get module names from current terraformModules (these exist in source)
- const moduleNamesFromModules = new Set(terraformModules.map((module) => module.name));
-
- // Filter releases that belong to modules no longer in the current module list
+ // Filter releases that are not associated with any current module
const releasesToRemove = allReleases
.filter((release) => {
- // Extract module name from versioned release tag
- const match = MODULE_TAG_REGEX.exec(release.tagName);
- const moduleName = match ? match[1] : release.tagName;
- return !moduleNamesFromModules.has(moduleName);
+ // Check if ANY current module is associated with this release tag
+ // This handles cases where tagging schemes changed over time
+ return !terraformModules.some((module) =>
+ TerraformModule.isModuleAssociatedWithTag(module.name, release.tagName),
+ );
})
.sort((a, b) => a.tagName.localeCompare(b.tagName));
diff --git a/src/types/config.types.ts b/src/types/config.types.ts
index 32543a88..06332070 100644
--- a/src/types/config.types.ts
+++ b/src/types/config.types.ts
@@ -26,7 +26,8 @@ export interface Config {
/**
* Default first tag for initializing repositories without existing tags.
- * This serves as the fallback tag when no tags are found in the repository.
+ * This serves as the fallback tag when no tags are found in the repository. Note this may
+ * be in the format of `v#.#.#` or `#.#.#` (e.g., `v1.0.0` or `1.0.0`).
*/
defaultFirstTag: string;
@@ -52,6 +53,17 @@ export interface Config {
*/
wikiSidebarChangelogMax: number;
+ /**
+ * A raw, multi-line string to override the default 'Usage' section in the generated wiki.
+ * If not provided, a default usage block will be generated. Supports template variables like:
+ * - {{module_name}}: The name of the module
+ * - {{latest_tag}}: The latest git tag for the module
+ * - {{latest_tag_version_number}}: The version number from the latest tag
+ * - {{module_source}}: The source URL for the module
+ * - {{module_name_terraform}}: The module name formatted for Terraform usage (alphanumeric and underscores only)
+ */
+ wikiUsageTemplate: string;
+
/**
* Flag to control whether the small branding link should be disabled or not in the
* pull request (PR) comments. When branding is enabled, a link to the action's
@@ -67,6 +79,13 @@ export interface Config {
*/
githubToken: string;
+ /**
+ * A list of module paths to completely ignore when processing. Any module whose path matches
+ * one of these patterns will not be processed for versioning, release, or documentation.
+ * Paths are relative to the workspace directory.
+ */
+ modulePathIgnore: string[];
+
/**
* A comma-separated list of file patterns to exclude from triggering version changes in Terraform modules.
* These patterns follow glob syntax (e.g., ".gitignore,*.md") and are relative to each Terraform module directory within
@@ -97,15 +116,38 @@ export interface Config {
useSSHSourceFormat: boolean;
/**
- * A list of module paths to completely ignore when processing. Any module whose path matches
- * one of these patterns will not be processed for versioning, release, or documentation.
- * Paths are relative to the workspace directory.
+ * The character used to separate directory path components when creating Git tags from module paths.
+ * This separator is applied throughout the entire directory structure conversion process, not just
+ * between the module name and version.
+ *
+ * Must be a single character and one of: -, _, /, .
+ *
+ * When converting a module path like 'modules/aws/s3-bucket' to a Git tag, this separator determines
+ * how directory separators (/) are replaced in the tag name portion:
+ *
+ * Examples with module path 'modules/aws/s3-bucket' and version 'v1.0.0':
+ * - "/" (default): modules/aws/s3-bucket/v1.0.0
+ * - "-": modules-aws-s3-bucket-v1.0.0
+ * - "_": modules_aws_s3_bucket_v1.0.0
+ * - ".": modules.aws.s3-bucket.v1.0.0
+ *
+ * This setting affects tag creation, tag parsing, and tag association logic throughout the system.
*/
- modulePathIgnore: string[];
+ tagDirectorySeparator: string;
/**
- * A raw, multi-line string to override the default 'Usage' section in the generated wiki.
- * If not provided, a default usage block will be generated.
+ * Whether to include the "v" prefix in version tags.
+ *
+ * When true (default), version tags will include the "v" prefix:
+ * - Example: module/v1.2.3
+ *
+ * When false, version tags will not include the "v" prefix:
+ * - Example: module/1.2.3
+ *
+ * For initial releases, this setting takes precedence over any "v" prefix specified in the
+ * defaultFirstTag configuration. If useVersionPrefix is false and defaultFirstTag contains
+ * a "v" prefix (e.g., "v1.0.0"), the "v" will be automatically removed to ensure consistency
+ * with the useVersionPrefix setting (resulting in "1.0.0").
*/
- wikiUsageTemplate?: string;
+ useVersionPrefix: boolean;
}
diff --git a/src/types/context.types.ts b/src/types/context.types.ts
index fa1c805a..9528f304 100644
--- a/src/types/context.types.ts
+++ b/src/types/context.types.ts
@@ -1,4 +1,4 @@
-import type { OctokitRestApi, Repo } from './github.types';
+import type { OctokitRestApi, Repo } from '@/types/github.types';
/**
* Context and runtime related types
diff --git a/src/types/index.ts b/src/types/index.ts
index 1cd04a7b..dd55ef10 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -1,3 +1,6 @@
+// Action metadata types
+export * from './metadata.types';
+
// Common types
export * from './common.types';
diff --git a/src/types/metadata.types.ts b/src/types/metadata.types.ts
new file mode 100644
index 00000000..4ebfff8e
--- /dev/null
+++ b/src/types/metadata.types.ts
@@ -0,0 +1,41 @@
+import type { Config } from '@/types/config.types';
+
+/**
+ * Metadata definition for GitHub Action inputs that enables dynamic configuration mapping.
+ *
+ * This interface serves as the translation layer between GitHub Action inputs defined in
+ * action.yml and our internal Config type. It provides the necessary metadata to:
+ * - Parse input values according to their expected types
+ * - Map action inputs to the corresponding config property names
+ * - Enforce required/optional input validation
+ * - Support dynamic config creation in createConfigFromInputs()
+ *
+ * The metadata is used by the ACTION_INPUTS constant in metadata.ts to create a
+ * comprehensive mapping of all action inputs, which then drives the automatic
+ * config generation process.
+ *
+ * @see {@link /workspaces/terraform-module-releaser/src/utils/metadata.ts} for usage
+ * @see {@link https://docs.github.com/en/actions/reference/metadata-syntax-for-github-actions#inputs} GitHub Actions input reference
+ */
+export interface ActionInputMetadata {
+ /**
+ * The config property name this input maps to.
+ * Must be a valid key from the Config interface.
+ */
+ configKey: keyof Config;
+
+ /**
+ * Whether this input is required by the GitHub Action.
+ * When true, the action will fail if the input is not provided.
+ */
+ required: boolean;
+
+ /**
+ * The expected data type of the input for proper parsing and validation.
+ * - 'string': Direct string value
+ * - 'boolean': Parsed using getBooleanInput for proper true/false handling
+ * - 'number': Parsed using parseInt for integer conversion
+ * - 'array': Comma-separated string parsed into array with deduplication
+ */
+ type: 'string' | 'boolean' | 'number' | 'array';
+}
diff --git a/src/types/wiki.types.ts b/src/types/wiki.types.ts
index 2377b2c8..5a554276 100644
--- a/src/types/wiki.types.ts
+++ b/src/types/wiki.types.ts
@@ -1,5 +1,5 @@
+import type { ExecSyncError } from '@/types/node-child-process.types';
import type { WIKI_STATUS } from '@/utils/constants';
-import type { ExecSyncError } from './node-child-process.types';
/**
* Represents the status of wiki operations.
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 922f45dc..7ed67192 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -1,3 +1,19 @@
+/**
+ * Defines valid separator characters for tag directory paths in Terraform module releases.
+ *
+ * When finding a Terraform module like `modules/aws/s3-bucket`, the release tag would typically be
+ * `modules/aws/s3-bucket/v1.0.0`. This constant allows for alternative separators in the tag path.
+ *
+ * For example, with these separators, the following tag formats would all be valid:
+ * - `modules/aws/s3-bucket/v1.0.0` (using '/')
+ * - `modules-aws-s3-bucket-v1.0.0` (using '-')
+ * - `modules_aws_s3_bucket_v1.0.0` (using '_')
+ * - `modules.aws.s3.bucket.v1.0.0` (using '.')
+ *
+ * The default separator is '/' as defined in action.yml.dddd
+ */
+export const VALID_TAG_DIRECTORY_SEPARATORS = ['-', '_', '/', '.'];
+
/**
* Regular expression that matches version tags in the format of semantic versioning.
* This regex validates version strings like "1.2.3" or "v1.2.3" and includes capture groups.
@@ -8,13 +24,32 @@
* It allows either a numerical portion (e.g., "1.2.3") or one prefixed with 'v' (e.g., "v1.2.3"),
* which is the proper semver default format.
*/
-export const VERSION_TAG_REGEX = /^v?(\d+)\.(\d+)\.(\d+)$/;
+export const VERSION_TAG_REGEX = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
/**
* Matches a Terraform module tag in the format: module-name/v1.2.3 or module-name/1.2.3
* Group 1: module name, Group 2: version (with or without 'v' prefix)
*/
-export const MODULE_TAG_REGEX = /^(.+)\/(v?\d+\.\d+\.\d+)$/;
+/**
+ * Regular expression pattern to match a module tag in the format: prefix + separator + version
+ * Where:
+ * - Group 1: prefix (e.g., "module", "feature")
+ * - Group 2: separator (one of: '-', '_', '/', '.')
+ * - Group 3: Complete version string with optional 'v' prefix (e.g., "v1.0.0", "1.0.0")
+ * - Group 4: Major version number
+ * - Group 5: Minor version number
+ * - Group 6: Patch version number
+ *
+ * Example matches:
+ * - "module-v1.0.0" → ["module-v1.0.0", "module", "-", "v1.0.0", "1", "0", "0"]
+ * - "feature_2.3.4" → ["feature_2.3.4", "feature", "_", "2.3.4", "2", "3", "4"]
+ * - "service/v0.1.0" → ["service/v0.1.0", "service", "/", "v0.1.0", "0", "1", "0"]
+ *
+ * Note: In the character class [-_/.], only the dot (.) requires escaping to match literal periods.
+ * The hyphen (-) doesn't need escaping when at the start/end of the character class.
+ * The forward slash (/) doesn't need escaping in JavaScript regex character classes.
+ */
+export const MODULE_TAG_REGEX = /^(.+)([-_/.])(v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*))$/;
/**
* Release type constants for semantic versioning
diff --git a/src/utils/metadata.ts b/src/utils/metadata.ts
new file mode 100644
index 00000000..07c32530
--- /dev/null
+++ b/src/utils/metadata.ts
@@ -0,0 +1,115 @@
+import type { ActionInputMetadata, Config } from '@/types';
+import { getBooleanInput, getInput } from '@actions/core';
+
+/**
+ * Factory functions to reduce duplication in ACTION_INPUTS metadata definitions.
+ * These functions create standardized metadata objects for common input patterns.
+ */
+const requiredString = (configKey: keyof Config): ActionInputMetadata => ({
+ configKey,
+ required: true,
+ type: 'string',
+});
+
+const requiredBoolean = (configKey: keyof Config): ActionInputMetadata => ({
+ configKey,
+ required: true,
+ type: 'boolean',
+});
+
+const requiredArray = (configKey: keyof Config): ActionInputMetadata => ({
+ configKey,
+ required: true,
+ type: 'array',
+});
+
+const requiredNumber = (configKey: keyof Config): ActionInputMetadata => ({
+ configKey,
+ required: true,
+ type: 'number',
+});
+
+const optionalArray = (configKey: keyof Config): ActionInputMetadata => ({
+ configKey,
+ required: false,
+ type: 'array',
+});
+
+/**
+ * Complete mapping of all GitHub Action inputs to their metadata.
+ * This is the single source of truth for input configuration.
+ * Note: defaultValue is removed as defaults come from action.yml at runtime
+ */
+export const ACTION_INPUTS: Record = {
+ 'major-keywords': requiredArray('majorKeywords'),
+ 'minor-keywords': requiredArray('minorKeywords'),
+ 'patch-keywords': requiredArray('patchKeywords'),
+ 'default-first-tag': requiredString('defaultFirstTag'),
+ 'terraform-docs-version': requiredString('terraformDocsVersion'),
+ 'delete-legacy-tags': requiredBoolean('deleteLegacyTags'),
+ 'disable-wiki': requiredBoolean('disableWiki'),
+ 'wiki-sidebar-changelog-max': requiredNumber('wikiSidebarChangelogMax'),
+ 'wiki-usage-template': requiredString('wikiUsageTemplate'),
+ 'disable-branding': requiredBoolean('disableBranding'),
+ 'module-path-ignore': optionalArray('modulePathIgnore'),
+ 'module-change-exclude-patterns': optionalArray('moduleChangeExcludePatterns'),
+ 'module-asset-exclude-patterns': optionalArray('moduleAssetExcludePatterns'),
+ 'use-ssh-source-format': requiredBoolean('useSSHSourceFormat'),
+ github_token: requiredString('githubToken'),
+ 'tag-directory-separator': requiredString('tagDirectorySeparator'),
+ 'use-version-prefix': requiredBoolean('useVersionPrefix'),
+} as const;
+
+/**
+ * Creates a config object by reading inputs using GitHub Actions API and converting them
+ * according to the metadata definitions. This provides a dynamic way to build the config
+ * without manually mapping each input.
+ */
+export function createConfigFromInputs(): Config {
+ const config = {} as Config;
+
+ for (const [inputName, metadata] of Object.entries(ACTION_INPUTS)) {
+ const { configKey, required, type } = metadata;
+
+ try {
+ let value: unknown;
+
+ if (type === 'boolean') {
+ // Use getBooleanInput for boolean types for proper parsing
+ value = getBooleanInput(inputName, { required });
+ } else if (type === 'array') {
+ // Handle array inputs with special parsing
+ const input = getInput(inputName, { required });
+
+ if (!input || input.trim() === '') {
+ value = [];
+ } else {
+ value = Array.from(
+ new Set(
+ input
+ .split(',')
+ .map((item: string) => item.trim())
+ .filter(Boolean),
+ ),
+ );
+ }
+ } else if (type === 'number') {
+ // Handle number inputs with parseInt
+ const input = getInput(inputName, { required });
+ value = Number.parseInt(input, 10);
+ } else {
+ // Handle string inputs
+ value = getInput(inputName, { required });
+ }
+
+ // Safely assign to config using the configKey
+ Object.assign(config, { [configKey]: value });
+ } catch (error) {
+ throw new Error(
+ `Failed to process input '${inputName}': ${error instanceof Error ? error.message : String(error)}`,
+ );
+ }
+ }
+
+ return config;
+}
diff --git a/src/utils/string.ts b/src/utils/string.ts
index 95e88172..6b0a7546 100644
--- a/src/utils/string.ts
+++ b/src/utils/string.ts
@@ -1,35 +1,3 @@
-/**
- * Removes any leading and trailing slashes (/) from the given string.
- *
- * @param {string} str - The input string from which to trim slashes.
- * @returns {string} - The string without leading or trailing slashes.
- *
- * @example
- * // Returns "example/path"
- * trimSlashes("/example/path/");
- *
- * @example
- * // Returns "another/example"
- * trimSlashes("///another/example///");
- */
-export function trimSlashes(str: string): string {
- let start = 0;
- let end = str.length;
-
- // Remove leading slashes by adjusting start index
- while (start < end && str[start] === '/') {
- start++;
- }
-
- // Remove trailing slashes by adjusting end index
- while (end > start && str[end - 1] === '/') {
- end--;
- }
-
- // Return the substring without leading and trailing slashes
- return str.slice(start, end);
-}
-
/**
* Removes trailing characters from a string without using regex.
*
@@ -55,5 +23,56 @@ export function removeTrailingCharacters(input: string, charactersToRemove: stri
while (endIndex > 0 && charactersToRemove.includes(input[endIndex - 1])) {
endIndex--;
}
+
return input.slice(0, endIndex);
}
+
+/**
+ * Removes leading characters from a string without using regex.
+ *
+ * This function iteratively checks each character from the beginning of the string
+ * and removes any consecutive characters that match the specified characters to remove.
+ * It uses a direct character-by-character approach instead of regex to avoid potential
+ * backtracking issues and ensure consistent O(n) performance.
+ *
+ * @param {string} input - The string to process
+ * @param {string[]} charactersToRemove - Array of characters to remove from the beginning
+ * @returns {string} The input string with all leading specified characters removed
+ *
+ * @example
+ * // Returns "example"
+ * removeLeadingCharacters("...example", ["."])
+ *
+ * @example
+ * // Returns "module-name"
+ * removeLeadingCharacters("._-module-name", [".", "-", "_"])
+ */
+export function removeLeadingCharacters(input: string, charactersToRemove: string[]): string {
+ let startIndex = 0;
+ while (startIndex < input.length && charactersToRemove.includes(input[startIndex])) {
+ startIndex++;
+ }
+
+ return input.slice(startIndex);
+}
+
+/**
+ * Renders a template string by replacing placeholders with provided values.
+ *
+ * @param template The template string containing placeholders in the format `{{key}}`.
+ * @param variables An object where keys correspond to placeholder names and values are their replacements.
+ * @returns The rendered string with placeholders replaced.
+ *
+ * @example
+ * // Returns "Hello, World!"
+ * renderTemplate("Hello, {{name}}!", { name: "World" })
+ *
+ * @example
+ * // Returns "Hi, There!"
+ * renderTemplate("{{greeting}}, {{name}}!", { greeting: "Hi", name: "There" })
+ */
+export function renderTemplate(template: string, variables: Record): string {
+ return template.replace(/\{\{(\w+)\}\}/g, (placeholder, key) => {
+ return key in variables ? variables[key] : placeholder;
+ });
+}
diff --git a/src/wiki.ts b/src/wiki.ts
index 49ba5f4c..19c08af9 100644
--- a/src/wiki.ts
+++ b/src/wiki.ts
@@ -7,7 +7,7 @@ import { join, resolve } from 'node:path';
import { getTerraformModuleFullReleaseChangelog } from '@/changelog';
import { config } from '@/config';
import { context } from '@/context';
-import { render } from '@/templating';
+import { renderTemplate } from '@/utils/string';
import { generateTerraformDocs } from '@/terraform-docs';
import type { TerraformModule } from '@/terraform-module';
import type { ExecSyncError, WikiStatusResult } from '@/types';
@@ -306,10 +306,10 @@ async function generateWikiTerraformModule(terraformModule: TerraformModule): Pr
const tfDocs = await generateTerraformDocs(terraformModule);
const moduleSource = getModuleSource(context.repoUrl, config.useSSHSourceFormat);
- const usage = render(config.wikiUsageTemplate, {
+ const usage = renderTemplate(config.wikiUsageTemplate, {
module_name: terraformModule.name,
- latest_tag: terraformModule.getLatestTag(),
- latest_tag_version_number: terraformModule.getLatestTagVersionNumber(),
+ latest_tag: terraformModule.getLatestTag() ?? '',
+ latest_tag_version_number: terraformModule.getLatestTagVersionNumber() ?? '',
module_source: moduleSource,
module_name_terraform: terraformModule.name.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase(),
});