2026-04-10

- corvée: met à jour les deps
- corvée: formate
This commit is contained in:
gcch 2026-04-10 17:21:57 +02:00
commit d50de6d534
85 changed files with 132090 additions and 31346 deletions

View file

@ -7,253 +7,257 @@ use PhpCsFixer\Finder;
use PhpCsFixer\Runner; use PhpCsFixer\Runner;
$finder = new Finder()->in(__DIR__)->exclude([ $finder = new Finder()->in(__DIR__)->exclude([
'vendor', 'vendor',
'web/vendor', 'web/vendor',
'web/wp', 'web/wp',
'web/app/languages', 'web/app/languages',
'web/app/plugins', 'web/app/plugins',
'web/app/mu-plugins', 'web/app/mu-plugins',
]); ]);
return new Config() return new Config()
->setRiskyAllowed(true) ->setRiskyAllowed(true)
->setRules([ ->setRules([
'array_syntax' => ['syntax' => 'short'], 'array_syntax' => ['syntax' => 'short'],
'assign_null_coalescing_to_coalesce_equal' => true, 'assign_null_coalescing_to_coalesce_equal' => true,
'attribute_empty_parentheses' => ['use_parentheses' => true], 'attribute_empty_parentheses' => ['use_parentheses' => true],
'blank_line_after_namespace' => true, 'blank_line_after_namespace' => true,
'blank_lines_before_namespace' => ['min_line_breaks' => 1, 'max_line_breaks' => 2], 'blank_lines_before_namespace' => ['min_line_breaks' => 1, 'max_line_breaks' => 2],
'cast_spaces' => true, 'cast_spaces' => true,
'class_attributes_separation' => ['elements' => [ 'class_attributes_separation' => ['elements' => [
'case' => 'none', 'case' => 'none',
'const' => 'none', 'const' => 'none',
'method' => 'one', 'method' => 'one',
'property' => 'one', 'property' => 'one',
'trait_import' => 'none', 'trait_import' => 'none',
]], ]],
'class_reference_name_casing' => true, 'class_reference_name_casing' => true,
'clean_namespace' => true, 'clean_namespace' => true,
'combine_consecutive_issets' => true, 'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true, 'combine_consecutive_unsets' => true,
'combine_nested_dirname' => true, 'combine_nested_dirname' => true,
'comment_to_phpdoc' => true, 'comment_to_phpdoc' => true,
'constant_case' => true, 'constant_case' => true,
'date_time_immutable' => true, 'date_time_immutable' => true,
'declare_equal_normalize' => true, 'declare_equal_normalize' => true,
'declare_parentheses' => true, 'declare_parentheses' => true,
'declare_strict_types' => true, 'declare_strict_types' => true,
'dir_constant' => true, 'dir_constant' => true,
'echo_tag_syntax' => true, 'echo_tag_syntax' => true,
'encoding' => true, 'encoding' => true,
'ereg_to_preg' => true, 'ereg_to_preg' => true,
'error_suppression' => true, 'error_suppression' => true,
'explicit_indirect_variable' => true, 'explicit_indirect_variable' => true,
'explicit_string_variable' => true, 'explicit_string_variable' => true,
'final_class' => true, 'final_class' => true,
'final_internal_class' => true, 'final_internal_class' => true,
'full_opening_tag' => true, 'full_opening_tag' => true,
'fully_qualified_strict_types' => ['import_symbols' => true], 'fully_qualified_strict_types' => ['import_symbols' => true],
'function_to_constant' => true, 'function_to_constant' => true,
'global_namespace_import' => ['import_classes' => true, 'import_constants' => true, 'import_functions' => true], 'global_namespace_import' => ['import_classes' => true, 'import_constants' => true, 'import_functions' => true],
'heredoc_to_nowdoc' => true, 'heredoc_to_nowdoc' => true,
'integer_literal_case' => true, 'integer_literal_case' => true,
'lambda_not_used_import' => true, 'lambda_not_used_import' => true,
'list_syntax' => true, 'list_syntax' => true,
'logical_operators' => true, 'logical_operators' => true,
'long_to_shorthand_operator' => true, 'long_to_shorthand_operator' => true,
'lowercase_cast' => true, 'lowercase_cast' => true,
'lowercase_keywords' => true, 'lowercase_keywords' => true,
'lowercase_static_reference' => true, 'lowercase_static_reference' => true,
'magic_constant_casing' => true, 'magic_constant_casing' => true,
'magic_method_casing' => true, 'magic_method_casing' => true,
'mb_str_functions' => true, 'mb_str_functions' => true,
'modernize_strpos' => ['modernize_stripos' => true], 'modernize_strpos' => ['modernize_stripos' => true],
'modernize_types_casting' => true, 'modernize_types_casting' => true,
'modifier_keywords' => true, 'modifier_keywords' => true,
'multiline_comment_opening_closing' => true, 'multiline_comment_opening_closing' => true,
'native_constant_invocation' => true, 'native_constant_invocation' => true,
'native_function_casing' => true, 'native_function_casing' => true,
'native_function_invocation' => ['include' => ['@compiler_optimized'], 'scope' => 'namespaced', 'strict' => true], 'native_function_invocation' => [
'native_type_declaration_casing' => true, 'include' => ['@compiler_optimized'],
'new_expression_parentheses' => true, 'scope' => 'namespaced',
'no_alias_functions' => ['sets' => ['@all']], 'strict' => true,
'no_alias_language_construct_call' => true, ],
'no_alternative_syntax' => true, 'native_type_declaration_casing' => true,
'no_binary_string' => true, 'new_expression_parentheses' => true,
'no_closing_tag' => true, 'no_alias_functions' => ['sets' => ['@all']],
'no_empty_comment' => true, 'no_alias_language_construct_call' => true,
'no_homoglyph_names' => true, 'no_alternative_syntax' => true,
'no_leading_import_slash' => true, 'no_binary_string' => true,
'no_mixed_echo_print' => ['use' => 'echo'], 'no_closing_tag' => true,
'no_multiline_whitespace_around_double_arrow' => true, 'no_empty_comment' => true,
'no_multiple_statements_per_line' => true, 'no_homoglyph_names' => true,
'no_null_property_initialization' => true, 'no_leading_import_slash' => true,
'no_php4_constructor' => true, 'no_mixed_echo_print' => ['use' => 'echo'],
'no_short_bool_cast' => true, 'no_multiline_whitespace_around_double_arrow' => true,
'no_trailing_comma_in_singleline' => true, 'no_multiple_statements_per_line' => true,
'no_trailing_whitespace_in_comment' => true, 'no_null_property_initialization' => true,
'no_unneeded_braces' => ['namespaces' => true], 'no_php4_constructor' => true,
'no_unneeded_control_parentheses' => ['statements' => [ 'no_short_bool_cast' => true,
'break', 'no_trailing_comma_in_singleline' => true,
'clone', 'no_trailing_whitespace_in_comment' => true,
'continue', 'no_unneeded_braces' => ['namespaces' => true],
'echo_print', 'no_unneeded_control_parentheses' => ['statements' => [
'negative_instanceof', 'break',
'others', 'clone',
'return', 'continue',
'switch_case', 'echo_print',
'yield', 'negative_instanceof',
'yield_from', 'others',
]], 'return',
'no_unneeded_final_method' => true, 'switch_case',
'no_unneeded_import_alias' => true, 'yield',
'no_unreachable_default_argument_value' => true, 'yield_from',
'no_unset_cast' => true, ]],
'no_unset_on_property' => true, 'no_unneeded_final_method' => true,
'no_unused_imports' => true, 'no_unneeded_import_alias' => true,
'no_useless_concat_operator' => true, 'no_unreachable_default_argument_value' => true,
'no_useless_nullsafe_operator' => true, 'no_unset_cast' => true,
'no_useless_printf' => true, 'no_unset_on_property' => true,
'no_useless_return' => true, 'no_unused_imports' => true,
'no_useless_sprintf' => true, 'no_useless_concat_operator' => true,
'no_whitespace_before_comma_in_array' => ['after_heredoc' => true], 'no_useless_nullsafe_operator' => true,
'non_printable_character' => true, 'no_useless_printf' => true,
'normalize_index_brace' => true, 'no_useless_return' => true,
'nullable_type_declaration' => ['syntax' => 'union'], 'no_useless_sprintf' => true,
'nullable_type_declaration_for_default_null_value' => true, 'no_whitespace_before_comma_in_array' => ['after_heredoc' => true],
'numeric_literal_separator' => ['override_existing' => true, 'strategy' => 'use_separator'], 'non_printable_character' => true,
'ordered_attributes' => true, 'normalize_index_brace' => true,
'ordered_class_elements' => ['case_sensitive' => false, 'sort_algorithm' => 'alpha'], 'nullable_type_declaration' => ['syntax' => 'union'],
'ordered_imports' => ['case_sensitive' => true], 'nullable_type_declaration_for_default_null_value' => true,
'ordered_interfaces' => true, 'numeric_literal_separator' => ['override_existing' => true, 'strategy' => 'use_separator'],
'ordered_traits' => true, 'ordered_attributes' => true,
'ordered_types' => ['null_adjustment' => 'always_last'], 'ordered_class_elements' => ['case_sensitive' => false, 'sort_algorithm' => 'alpha'],
'phpdoc_readonly_class_comment_to_keyword' => true, 'ordered_imports' => ['case_sensitive' => true],
'phpdoc_to_param_type' => true, 'ordered_interfaces' => true,
'phpdoc_to_property_type' => true, 'ordered_traits' => true,
'phpdoc_to_return_type' => true, 'ordered_types' => ['null_adjustment' => 'always_last'],
'pow_to_exponentiation' => true, 'phpdoc_readonly_class_comment_to_keyword' => true,
'protected_to_private' => true, 'phpdoc_to_param_type' => true,
'psr_autoloading' => true, 'phpdoc_to_property_type' => true,
'random_api_migration' => ['replacements' => [ 'phpdoc_to_return_type' => true,
'getrandmax' => 'mt_getrandmax', 'pow_to_exponentiation' => true,
'rand' => 'mt_rand', 'protected_to_private' => true,
'srand' => 'mt_srand', 'psr_autoloading' => true,
]], 'random_api_migration' => ['replacements' => [
'return_assignment' => true, 'getrandmax' => 'mt_getrandmax',
'self_accessor' => true, 'rand' => 'mt_rand',
'self_static_accessor' => true, 'srand' => 'mt_srand',
'set_type_to_cast' => true, ]],
'short_scalar_cast' => true, 'return_assignment' => true,
'simple_to_complex_string_variable' => true, 'self_accessor' => true,
'simplified_null_return' => true, 'self_static_accessor' => true,
'single_class_element_per_statement' => true, 'set_type_to_cast' => true,
'single_import_per_statement' => true, 'short_scalar_cast' => true,
'single_line_after_imports' => true, 'simple_to_complex_string_variable' => true,
'single_line_comment_spacing' => true, 'simplified_null_return' => true,
'single_line_comment_style' => true, 'single_class_element_per_statement' => true,
'single_line_empty_body' => true, 'single_import_per_statement' => true,
'single_trait_insert_per_statement' => true, 'single_line_after_imports' => true,
'standardize_not_equals' => true, 'single_line_comment_spacing' => true,
'static_lambda' => true, 'single_line_comment_style' => true,
'strict_comparison' => true, 'single_line_empty_body' => true,
'strict_param' => true, 'single_trait_insert_per_statement' => true,
'string_implicit_backslashes' => true, 'standardize_not_equals' => true,
'string_length_to_empty' => true, 'static_lambda' => true,
'switch_continue_to_break' => true, 'strict_comparison' => true,
'ternary_to_null_coalescing' => true, 'strict_param' => true,
'trim_array_spaces' => true, 'string_implicit_backslashes' => true,
'use_arrow_functions' => true, 'string_length_to_empty' => true,
'void_return' => true, 'switch_continue_to_break' => true,
'whitespace_after_comma_in_array' => ['ensure_single_space' => true], 'ternary_to_null_coalescing' => true,
// --- 'trim_array_spaces' => true,
// Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one. 'use_arrow_functions' => true,
'align_multiline_comment' => ['comment_type' => 'all_multiline'], 'void_return' => true,
// There should not be blank lines between docblock and the documented element. 'whitespace_after_comma_in_array' => ['ensure_single_space' => true],
'no_blank_lines_after_phpdoc' => true, // ---
// There should not be empty PHPDoc blocks. // Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one.
'no_empty_phpdoc' => true, 'align_multiline_comment' => ['comment_type' => 'all_multiline'],
// Removes @param, @return and @var tags that don't provide any useful information. // There should not be blank lines between docblock and the documented element.
'no_superfluous_phpdoc_tags' => [ 'no_blank_lines_after_phpdoc' => true,
'allow_hidden_params' => false, // There should not be empty PHPDoc blocks.
'allow_mixed' => false, 'no_empty_phpdoc' => true,
'allow_unused_params' => false, // Removes @param, @return and @var tags that don't provide any useful information.
], 'no_superfluous_phpdoc_tags' => [
// PHPDoc should contain @param for all params. 'allow_hidden_params' => false,
'phpdoc_add_missing_param_annotation' => ['only_untyped' => false], 'allow_mixed' => false,
// All items of the given PHPDoc tags must be either left-aligned or (by default) aligned vertically. 'allow_unused_params' => false,
'phpdoc_align' => true, ],
// PHPDoc annotation descriptions should not be a sentence. // PHPDoc should contain @param for all params.
'phpdoc_annotation_without_dot' => true, 'phpdoc_add_missing_param_annotation' => ['only_untyped' => false],
// PHPDoc array<T> type must be used instead of T[]. // All items of the given PHPDoc tags must be either left-aligned or (by default) aligned vertically.
'phpdoc_array_type' => true, 'phpdoc_align' => true,
// Docblocks should have the same indentation as the documented subject. // PHPDoc annotation descriptions should not be a sentence.
'phpdoc_indent' => true, 'phpdoc_annotation_without_dot' => true,
// Fixes PHPDoc inline tags. // PHPDoc array<T> type must be used instead of T[].
'phpdoc_inline_tag_normalizer' => true, 'phpdoc_array_type' => true,
// Changes doc blocks from single to multi line, or reversed. Works for class constants, properties and methods only. // Docblocks should have the same indentation as the documented subject.
'phpdoc_line_span' => ['const' => 'single', 'method' => 'multi', 'property' => 'single'], 'phpdoc_indent' => true,
// PHPDoc list type must be used instead of array without a key. // Fixes PHPDoc inline tags.
'phpdoc_list_type' => false, 'phpdoc_inline_tag_normalizer' => true,
// @access annotations must be removed from PHPDoc. // Changes doc blocks from single to multi line, or reversed. Works for class constants, properties and methods only.
'phpdoc_no_access' => true, 'phpdoc_line_span' => ['const' => 'single', 'method' => 'multi', 'property' => 'single'],
// No alias PHPDoc tags should be used. // PHPDoc list type must be used instead of array without a key.
'phpdoc_no_alias_tag' => true, 'phpdoc_list_type' => false,
// @return void and @return null annotations must be removed from PHPDoc. // @access annotations must be removed from PHPDoc.
'phpdoc_no_empty_return' => false, 'phpdoc_no_access' => true,
// @package and @subpackage annotations must be removed from PHPDoc. // No alias PHPDoc tags should be used.
'phpdoc_no_package' => true, 'phpdoc_no_alias_tag' => true,
// Classy that does not inherit must not have @inheritdoc tags. // @return void and @return null annotations must be removed from PHPDoc.
'phpdoc_no_useless_inheritdoc' => true, 'phpdoc_no_empty_return' => false,
// Annotations in PHPDoc should be ordered in defined sequence. // @package and @subpackage annotations must be removed from PHPDoc.
'phpdoc_order' => true, 'phpdoc_no_package' => true,
// Order PHPDoc tags by value. // Classy that does not inherit must not have @inheritdoc tags.
'phpdoc_order_by_value' => true, 'phpdoc_no_useless_inheritdoc' => true,
// Orders all @param annotations in DocBlocks according to method signature. // Annotations in PHPDoc should be ordered in defined sequence.
'phpdoc_param_order' => true, 'phpdoc_order' => true,
// The type of @return annotations of methods returning a reference to itself must the configured one. // Order PHPDoc tags by value.
'phpdoc_return_self_reference' => true, 'phpdoc_order_by_value' => true,
// Scalar types should always be written in the same form. int not integer, bool not boolean, float not real or double. // Orders all @param annotations in DocBlocks according to method signature.
'phpdoc_scalar' => ['types' => [ 'phpdoc_param_order' => true,
'boolean', // The type of @return annotations of methods returning a reference to itself must the configured one.
'callback', 'phpdoc_return_self_reference' => true,
'double', // Scalar types should always be written in the same form. int not integer, bool not boolean, float not real or double.
'integer', 'phpdoc_scalar' => ['types' => [
'never-return', 'boolean',
'never-returns', 'callback',
'no-return', 'double',
'real', 'integer',
'str', 'never-return',
]], 'never-returns',
// Annotations in PHPDoc should be grouped together so that annotations of the same type immediately follow each other. Annotations of a different type are separated by a single blank line. 'no-return',
'phpdoc_separation' => [ 'real',
'groups' => [ 'str',
['Annotation', 'NamedArgumentConstructor', 'Target'], ]],
['author', 'copyright', 'license'], // Annotations in PHPDoc should be grouped together so that annotations of the same type immediately follow each other. Annotations of a different type are separated by a single blank line.
['category', 'package', 'subpackage'], 'phpdoc_separation' => [
['property', 'property-read', 'property-write'], 'groups' => [
['deprecated', 'link', 'see', 'since'], ['Annotation', 'NamedArgumentConstructor', 'Target'],
], ['author', 'copyright', 'license'],
'skip_unlisted_annotations' => false, ['category', 'package', 'subpackage'],
], ['property', 'property-read', 'property-write'],
// Single line @var PHPDoc should have proper spacing. ['deprecated', 'link', 'see', 'since'],
'phpdoc_single_line_var_spacing' => true, ],
// PHPDoc summary should end in either a full stop, exclamation mark, or question mark. 'skip_unlisted_annotations' => false,
'phpdoc_summary' => true, ],
// Docblocks should only be used on structural elements. // Single line @var PHPDoc should have proper spacing.
'phpdoc_to_comment' => false, 'phpdoc_single_line_var_spacing' => true,
// PHPDoc should start and end with content, excluding the very first and last line of the docblocks. // PHPDoc summary should end in either a full stop, exclamation mark, or question mark.
'phpdoc_trim' => true, 'phpdoc_summary' => true,
// Removes extra blank lines after summary and after description in PHPDoc. // Docblocks should only be used on structural elements.
'phpdoc_trim_consecutive_blank_line_separation' => true, 'phpdoc_to_comment' => false,
// The correct case must be used for standard PHP types in PHPDoc. // PHPDoc should start and end with content, excluding the very first and last line of the docblocks.
'phpdoc_types' => true, 'phpdoc_trim' => true,
// Sorts PHPDoc types. // Removes extra blank lines after summary and after description in PHPDoc.
'phpdoc_types_order' => ['null_adjustment' => 'always_last'], 'phpdoc_trim_consecutive_blank_line_separation' => true,
// @var and @type annotations must have type and name in the correct order. // The correct case must be used for standard PHP types in PHPDoc.
'phpdoc_var_annotation_correct_order' => true, 'phpdoc_types' => true,
// @var and @type annotations of classy properties should not contain the name. // Sorts PHPDoc types.
'phpdoc_var_without_name' => true, 'phpdoc_types_order' => ['null_adjustment' => 'always_last'],
]) // @var and @type annotations must have type and name in the correct order.
->setFinder($finder) 'phpdoc_var_annotation_correct_order' => true,
->setParallelConfig(Runner\Parallel\ParallelConfigFactory::detect()); // @var and @type annotations of classy properties should not contain the name.
'phpdoc_var_without_name' => true,
])
->setFinder($finder)
->setParallelConfig(Runner\Parallel\ParallelConfigFactory::detect());

View file

@ -1,9 +1,9 @@
{ {
"$schema": "./phpactor.schema.json", "$schema": "./phpactor.schema.json",
"indexer.exclude_patterns": [ "indexer.exclude_patterns": [
"/vendor/**/Tests/**/*",
"/vendor/**/tests/**/*",
"/var/cache/**/*", "/var/cache/**/*",
"/vendor/**/tests/**/*",
"/vendor/**/Tests/**/*",
"/vendor/composer/**/*" "/vendor/composer/**/*"
], ],
"language_server.diagnostic_outsource_timeout": 5, "language_server.diagnostic_outsource_timeout": 5,

View file

@ -15,9 +15,9 @@
"initialization_options": { "initialization_options": {
"settings": { "settings": {
"configPath": "cfg/oxlint.config.ts", "configPath": "cfg/oxlint.config.ts",
"run": "onType",
"disableNestedConfig": false, "disableNestedConfig": false,
"fixKind": "safe_fix", "fixKind": "safe_fix",
"run": "onType",
"unusedDisableDirectives": "deny" "unusedDisableDirectives": "deny"
} }
} }

200
bun.lock
View file

@ -8,14 +8,14 @@
"@mobily/ts-belt": "v4.0.0-rc.5", "@mobily/ts-belt": "v4.0.0-rc.5",
"@sentry/browser": "^10.47.0", "@sentry/browser": "^10.47.0",
"a11y-dialog": "^8.1.5", "a11y-dialog": "^8.1.5",
"effect": "^4.0.0-beta.43", "effect": "^4.0.0-beta.46",
"lit-html": "^3.3.2", "lit-html": "^3.3.2",
"purify-ts": "2.1.2", "purify-ts": "2.1.2",
"ts-pattern": "^5.9.0", "ts-pattern": "^5.9.0",
"valibot": "1.1.0", "valibot": "1.1.0",
}, },
"devDependencies": { "devDependencies": {
"@effect/language-service": "^0.84.3", "@effect/language-service": "^0.85.0",
"@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274", "@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274",
"@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#0968f683", "@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#0968f683",
"@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#8de937e801", "@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#8de937e801",
@ -54,7 +54,7 @@
"stylelint-plugin-logical-css": "^2.1.0", "stylelint-plugin-logical-css": "^2.1.0",
"typescript": "6.0.2", "typescript": "6.0.2",
"typescript-eslint": "^8.58.1", "typescript-eslint": "^8.58.1",
"vite": "^8.0.7", "vite": "^8.0.8",
"vite-tsconfig-paths": "^6.1.1", "vite-tsconfig-paths": "^6.1.1",
}, },
}, },
@ -266,13 +266,13 @@
"@csstools/selector-specificity": ["@csstools/selector-specificity@6.0.0", "", { "peerDependencies": { "postcss-selector-parser": "^7.1.1" } }, "sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA=="], "@csstools/selector-specificity": ["@csstools/selector-specificity@6.0.0", "", { "peerDependencies": { "postcss-selector-parser": "^7.1.1" } }, "sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA=="],
"@effect/language-service": ["@effect/language-service@0.84.3", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-zpxi6rLCwst/cBQd7ElwDvt36Y6Jvz8v6bCLnNiOL6OXvdLmqjOFWyzWZdMh92vvBQA/aVKhfIAAOP3o4wKt0A=="], "@effect/language-service": ["@effect/language-service@0.85.1", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-EXnJjIy6zQ3nUO/MZ+ynWUb8B895KZPotd1++oTs9JjDkplwM7cb6zo8Zq2zU6piwq+KflO7amXbEfj1UMpHkw=="],
"@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" } }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="], "@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="],
"@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], "@emnapi/runtime": ["@emnapi/runtime@1.9.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw=="],
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="], "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
"@es-joy/jsdoccomment": ["@es-joy/jsdoccomment@0.86.0", "", { "dependencies": { "@types/estree": "^1.0.8", "@typescript-eslint/types": "^8.58.0", "comment-parser": "1.4.6", "esquery": "^1.7.0", "jsdoc-type-pratt-parser": "~7.2.0" } }, "sha512-ukZmRQ81WiTpDWO6D/cTBM7XbrNtutHKvAVnZN/8pldAwLoJArGOvkNyxPTBGsPjsoaQBJxlH+tE2TNA/92Qgw=="], "@es-joy/jsdoccomment": ["@es-joy/jsdoccomment@0.86.0", "", { "dependencies": { "@types/estree": "^1.0.8", "@typescript-eslint/types": "^8.58.0", "comment-parser": "1.4.6", "esquery": "^1.7.0", "jsdoc-type-pratt-parser": "~7.2.0" } }, "sha512-ukZmRQ81WiTpDWO6D/cTBM7XbrNtutHKvAVnZN/8pldAwLoJArGOvkNyxPTBGsPjsoaQBJxlH+tE2TNA/92Qgw=="],
@ -282,17 +282,17 @@
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="],
"@eslint/config-array": ["@eslint/config-array@0.23.4", "", { "dependencies": { "@eslint/object-schema": "^3.0.4", "debug": "^4.3.1", "minimatch": "^10.2.4" } }, "sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow=="], "@eslint/config-array": ["@eslint/config-array@0.23.5", "", { "dependencies": { "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", "minimatch": "^10.2.4" } }, "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.5.4", "", { "dependencies": { "@eslint/core": "^1.2.0" } }, "sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg=="], "@eslint/config-helpers": ["@eslint/config-helpers@0.5.5", "", { "dependencies": { "@eslint/core": "^1.2.1" } }, "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w=="],
"@eslint/core": ["@eslint/core@1.2.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A=="], "@eslint/core": ["@eslint/core@1.2.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ=="],
"@eslint/js": ["@eslint/js@10.0.1", "", { "peerDependencies": { "eslint": "^10.0.0" }, "optionalPeers": ["eslint"] }, "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA=="], "@eslint/js": ["@eslint/js@10.0.1", "", { "peerDependencies": { "eslint": "^10.0.0" }, "optionalPeers": ["eslint"] }, "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA=="],
"@eslint/object-schema": ["@eslint/object-schema@3.0.4", "", {}, "sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw=="], "@eslint/object-schema": ["@eslint/object-schema@3.0.5", "", {}, "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.7.0", "", { "dependencies": { "@eslint/core": "^1.2.0", "levn": "^0.4.1" } }, "sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg=="], "@eslint/plugin-kit": ["@eslint/plugin-kit@0.7.1", "", { "dependencies": { "@eslint/core": "^1.2.1", "levn": "^0.4.1" } }, "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ=="],
"@gcch/configuration-eslint": ["@gcch/configuration-eslint@git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274f0bfebd5135a728960644f4b1cdcb8", { "dependencies": { "@eslint/js": "^10.0.1", "astro-eslint-parser": "^1.3.0", "eslint": "^10.0.3", "eslint-plugin-astro": "^1.6.0", "eslint-plugin-functional": "^9.0.4", "eslint-plugin-jsdoc": "^62.8.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-perfectionist": "^5.6.0", "eslint-plugin-sonarjs": "^4.0.2", "eslint-plugin-unicorn": "^63.0.0", "globals": "^17.4.0", "typescript-eslint": "^8.57.0" }, "peerDependencies": { "eslint": "^10.0.3", "typescript": "^6.0.1-rc" } }, "62ee424274f0bfebd5135a728960644f4b1cdcb8"], "@gcch/configuration-eslint": ["@gcch/configuration-eslint@git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274f0bfebd5135a728960644f4b1cdcb8", { "dependencies": { "@eslint/js": "^10.0.1", "astro-eslint-parser": "^1.3.0", "eslint": "^10.0.3", "eslint-plugin-astro": "^1.6.0", "eslint-plugin-functional": "^9.0.4", "eslint-plugin-jsdoc": "^62.8.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-perfectionist": "^5.6.0", "eslint-plugin-sonarjs": "^4.0.2", "eslint-plugin-unicorn": "^63.0.0", "globals": "^17.4.0", "typescript-eslint": "^8.57.0" }, "peerDependencies": { "eslint": "^10.0.3", "typescript": "^6.0.1-rc" } }, "62ee424274f0bfebd5135a728960644f4b1cdcb8"],
@ -338,7 +338,7 @@
"@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ=="], "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ=="],
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.2", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw=="], "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.3", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
@ -512,49 +512,49 @@
"@reteps/dockerfmt": ["@reteps/dockerfmt@0.5.2", "", {}, "sha512-Hbr7yen4fP5TxGM54ucXa4o5NwWXatJ6Bd9I8gp0PValYbI4Rug2Gu+rVv7K7o/efQc3F5ctqWJz47rYaa8zBw=="], "@reteps/dockerfmt": ["@reteps/dockerfmt@0.5.2", "", {}, "sha512-Hbr7yen4fP5TxGM54ucXa4o5NwWXatJ6Bd9I8gp0PValYbI4Rug2Gu+rVv7K7o/efQc3F5ctqWJz47rYaa8zBw=="],
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.13", "", { "os": "android", "cpu": "arm64" }, "sha512-5ZiiecKH2DXAVJTNN13gNMUcCDg4Jy8ZjbXEsPnqa248wgOVeYRX0iqXXD5Jz4bI9BFHgKsI2qmyJynstbmr+g=="], "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.15", "", { "os": "android", "cpu": "arm64" }, "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA=="],
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tz/v/8G77seu8zAB3A5sK3UFoOl06zcshEzhUO62sAEtrEuW/H1CcyoupOrD+NbQJytYgA4CppXPzlrmp4JZKA=="], "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg=="],
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-8DakphqOz8JrMYWTJmWA+vDJxut6LijZ8Xcdc4flOlAhU7PNVwo2MaWBF9iXjJAPo5rC/IxEFZDhJ3GC7NHvug=="], "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw=="],
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.13", "", { "os": "freebsd", "cpu": "x64" }, "sha512-4wBQFfjDuXYN/SVI8inBF3Aa+isq40rc6VMFbk5jcpolUBTe5cYnMsHZ51nFWsx3PVyyNN3vgoESki0Hmr/4BA=="], "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.15", "", { "os": "freebsd", "cpu": "x64" }, "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw=="],
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.13", "", { "os": "linux", "cpu": "arm" }, "sha512-JW/e4yPIXLms+jmnbwwy5LA/LxVwZUWLN8xug+V200wzaVi5TEGIWQlh8o91gWYFxW609euI98OCCemmWGuPrw=="], "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15", "", { "os": "linux", "cpu": "arm" }, "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA=="],
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-ZfKWpXiUymDnavepCaM6KG/uGydJ4l2nBmMxg60Ci4CbeefpqjPWpfaZM7PThOhk2dssqBAcwLc6rAyr0uTdXg=="], "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w=="],
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-bmRg3O6Z0gq9yodKKWCIpnlH051sEfdVwt+6m5UDffAQMUUqU0xjnQqqAUm+Gu7ofAAly9DqiQDtKu2nPDEABA=="], "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ=="],
"@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.13", "", { "os": "linux", "cpu": "ppc64" }, "sha512-8Wtnbw4k7pMYN9B/mOEAsQ8HOiq7AZ31Ig4M9BKn2So4xRaFEhtCSa4ZJaOutOWq50zpgR4N5+L/opnlaCx8wQ=="], "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15", "", { "os": "linux", "cpu": "ppc64" }, "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ=="],
"@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0-rc.13", "", { "os": "linux", "cpu": "s390x" }, "sha512-D/0Nlo8mQuxSMohNJUF2lDXWRsFDsHldfRRgD9bRgktj+EndGPj4DOV37LqDKPYS+osdyhZEH7fTakTAEcW7qg=="], "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15", "", { "os": "linux", "cpu": "s390x" }, "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ=="],
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.13", "", { "os": "linux", "cpu": "x64" }, "sha512-eRrPvat2YaVQcwwKi/JzOP6MKf1WRnOCr+VaI3cTWz3ZoLcP/654z90lVCJ4dAuMEpPdke0n+qyAqXDZdIC4rA=="], "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.15", "", { "os": "linux", "cpu": "x64" }, "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA=="],
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.13", "", { "os": "linux", "cpu": "x64" }, "sha512-PsdONiFRp8hR8KgVjTWjZ9s7uA3uueWL0t74/cKHfM4dR5zXYv4AjB8BvA+QDToqxAFg4ZkcVEqeu5F7inoz5w=="], "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.15", "", { "os": "linux", "cpu": "x64" }, "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw=="],
"@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.13", "", { "os": "none", "cpu": "arm64" }, "sha512-hCNXgC5dI3TVOLrPT++PKFNZ+1EtS0mLQwfXXXSUD/+rGlB65gZDwN/IDuxLpQP4x8RYYHqGomlUXzpO8aVI2w=="], "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.15", "", { "os": "none", "cpu": "arm64" }, "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg=="],
"@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.13", "", { "dependencies": { "@emnapi/core": "1.9.1", "@emnapi/runtime": "1.9.1", "@napi-rs/wasm-runtime": "^1.1.2" }, "cpu": "none" }, "sha512-viLS5C5et8NFtLWw9Sw3M/w4vvnVkbWkO7wSNh3C+7G1+uCkGpr6PcjNDSFcNtmXY/4trjPBqUfcOL+P3sWy/g=="], "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.15", "", { "dependencies": { "@emnapi/core": "1.9.2", "@emnapi/runtime": "1.9.2", "@napi-rs/wasm-runtime": "^1.1.3" }, "cpu": "none" }, "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q=="],
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-Fqa3Tlt1xL4wzmAYxGNFV36Hb+VfPc9PYU+E25DAnswXv3ODDu/yyWjQDbXMo5AGWkQVjLgQExuVu8I/UaZhPQ=="], "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA=="],
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.13", "", { "os": "win32", "cpu": "x64" }, "sha512-/pLI5kPkGEi44TDlnbio3St/5gUFeN51YWNAk/Gnv6mEQBOahRBh52qVFVBpmrnU01n2yysvBML9Ynu7K4kGAQ=="], "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.15", "", { "os": "win32", "cpu": "x64" }, "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g=="],
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.13", "", {}, "sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA=="], "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.15", "", {}, "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g=="],
"@sentry-internal/browser-utils": ["@sentry-internal/browser-utils@10.47.0", "", { "dependencies": { "@sentry/core": "10.47.0" } }, "sha512-bVFRAeJWMBcBCvJKIFCMJ1/yQToL4vPGqfmlnDZeypcxkqUDKQ/Y3ziLHXoDL2sx0lagcgU2vH1QhCQ67Aujjw=="], "@sentry-internal/browser-utils": ["@sentry-internal/browser-utils@10.48.0", "", { "dependencies": { "@sentry/core": "10.48.0" } }, "sha512-SCiTLBXzugFKxev6NoKYBIhQoDk0gUh0AVVVepCBqfCJiWBG01Zvv0R5tCVohr4cWRllkQ8mlBdNQd/I7s9tdA=="],
"@sentry-internal/feedback": ["@sentry-internal/feedback@10.47.0", "", { "dependencies": { "@sentry/core": "10.47.0" } }, "sha512-pdvMmi4dQpX5S/vAAzrhHPIw3T3HjUgDNgUiCBrlp7N9/6zGO2gNPhUnNekP+CjgI/z0rvf49RLqlDenpNrMOg=="], "@sentry-internal/feedback": ["@sentry-internal/feedback@10.48.0", "", { "dependencies": { "@sentry/core": "10.48.0" } }, "sha512-tGkEyOM1HDS9qebDphUMEnyk3qq/50AnuTBiFmMJyjNzowylVGmRRk0sr3xkmbVHCDXQCiYnDmSVlJ2x4SDMrQ=="],
"@sentry-internal/replay": ["@sentry-internal/replay@10.47.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.47.0", "@sentry/core": "10.47.0" } }, "sha512-ScdovxP7hJxgMt70+7hFvwT02GIaIUAxdEM/YPsayZBeCoAukPW8WiwztJfoKtsfPyKJ5A6f0H3PIxTPcA9Row=="], "@sentry-internal/replay": ["@sentry-internal/replay@10.48.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.48.0", "@sentry/core": "10.48.0" } }, "sha512-sevRTePfuk4PNuz9KAKpmTZEomAU0aLXyIhOwA0OnUDdxPhkY8kq5lwDbuxTHv6DQUjUX3YgFbY45VH1JEqHKA=="],
"@sentry-internal/replay-canvas": ["@sentry-internal/replay-canvas@10.47.0", "", { "dependencies": { "@sentry-internal/replay": "10.47.0", "@sentry/core": "10.47.0" } }, "sha512-A5OY8friSe6g8WAK4L8IeOPiEd9D3Ps40DzRH5j2f6SUja0t90mKMvHRcRf8zq0d4BkdB+JM7tjOkwxpuv8heA=="], "@sentry-internal/replay-canvas": ["@sentry-internal/replay-canvas@10.48.0", "", { "dependencies": { "@sentry-internal/replay": "10.48.0", "@sentry/core": "10.48.0" } }, "sha512-9nWuN2z4O+iwbTfuYV5ZmngBgJU/ZxfOo47A5RJP3Nu/kl59aJ1lUhILYOKyeNOIC/JyeERmpIcTxnlPXQzZ3Q=="],
"@sentry/browser": ["@sentry/browser@10.47.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.47.0", "@sentry-internal/feedback": "10.47.0", "@sentry-internal/replay": "10.47.0", "@sentry-internal/replay-canvas": "10.47.0", "@sentry/core": "10.47.0" } }, "sha512-rC0agZdxKA5XWfL4VwPOr/rJMogXDqZgnVzr93YWpFn9DMZT/7LzxSJVPIJwRUjx3bFEby3PcTa3YaX7pxm1AA=="], "@sentry/browser": ["@sentry/browser@10.48.0", "", { "dependencies": { "@sentry-internal/browser-utils": "10.48.0", "@sentry-internal/feedback": "10.48.0", "@sentry-internal/replay": "10.48.0", "@sentry-internal/replay-canvas": "10.48.0", "@sentry/core": "10.48.0" } }, "sha512-4jt2zX2ExgFcNe2x+W+/k81fmDUsOrquGtt028CiGuDuma6kEsWBI4JbooT1jhj2T+eeUxe3YGbM23Zhh7Ghhw=="],
"@sentry/core": ["@sentry/core@10.47.0", "", {}, "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA=="], "@sentry/core": ["@sentry/core@10.48.0", "", {}, "sha512-h8F+fXVwYC9ro5ZaO8V+v3vqc0awlXHGblEAuVxSGgh4IV/oFX+QVzXeDTTrFOFS6v/Vn5vAyu240eJrJAS6/g=="],
"@sindresorhus/base62": ["@sindresorhus/base62@1.0.0", "", {}, "sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA=="], "@sindresorhus/base62": ["@sindresorhus/base62@1.0.0", "", {}, "sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA=="],
@ -566,7 +566,7 @@
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
"@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="], "@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="],
"@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="], "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="],
@ -580,7 +580,7 @@
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/node": ["@types/node@25.5.2", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg=="], "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
"@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
@ -592,17 +592,17 @@
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.58.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.58.1", "@typescript-eslint/types": "^8.58.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g=="], "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.58.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.58.1", "@typescript-eslint/types": "^8.58.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.58.0", "", { "dependencies": { "@typescript-eslint/types": "8.58.0", "@typescript-eslint/visitor-keys": "8.58.0" } }, "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ=="], "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.58.1", "", { "dependencies": { "@typescript-eslint/types": "8.58.1", "@typescript-eslint/visitor-keys": "8.58.1" } }, "sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.58.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw=="], "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.58.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.58.0", "", { "dependencies": { "@typescript-eslint/types": "8.58.0", "@typescript-eslint/typescript-estree": "8.58.0", "@typescript-eslint/utils": "8.58.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg=="], "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.58.1", "", { "dependencies": { "@typescript-eslint/types": "8.58.1", "@typescript-eslint/typescript-estree": "8.58.1", "@typescript-eslint/utils": "8.58.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.58.0", "", {}, "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww=="], "@typescript-eslint/types": ["@typescript-eslint/types@8.58.1", "", {}, "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.58.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.58.1", "@typescript-eslint/tsconfig-utils": "8.58.1", "@typescript-eslint/types": "8.58.1", "@typescript-eslint/visitor-keys": "8.58.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg=="], "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.58.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.58.1", "@typescript-eslint/tsconfig-utils": "8.58.1", "@typescript-eslint/types": "8.58.1", "@typescript-eslint/visitor-keys": "8.58.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.58.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.58.0", "@typescript-eslint/types": "8.58.0", "@typescript-eslint/typescript-estree": "8.58.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA=="], "@typescript-eslint/utils": ["@typescript-eslint/utils@8.58.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.58.1", "@typescript-eslint/types": "8.58.1", "@typescript-eslint/typescript-estree": "8.58.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.58.1", "", { "dependencies": { "@typescript-eslint/types": "8.58.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ=="], "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.58.1", "", { "dependencies": { "@typescript-eslint/types": "8.58.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ=="],
@ -694,7 +694,7 @@
"balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.13", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw=="], "baseline-browser-mapping": ["baseline-browser-mapping@2.10.17", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-HdrkN8eVG2CXxeifv/VdJ4A4RSra1DTW8dc/hdxzhGHN8QePs6gKaWM9pHPcpCoxYZJuOZ8drHmbdpLHjCYjLA=="],
"better-typescript-lib": ["better-typescript-lib@2.12.0", "", { "dependencies": { "@typescript/lib-decorators": "npm:@better-typescript-lib/decorators@2.12.0", "@typescript/lib-dom": "npm:@better-typescript-lib/dom@2.12.0", "@typescript/lib-es2015": "npm:@better-typescript-lib/es2015@2.12.0", "@typescript/lib-es2016": "npm:@better-typescript-lib/es2016@2.12.0", "@typescript/lib-es2017": "npm:@better-typescript-lib/es2017@2.12.0", "@typescript/lib-es2018": "npm:@better-typescript-lib/es2018@2.12.0", "@typescript/lib-es2019": "npm:@better-typescript-lib/es2019@2.12.0", "@typescript/lib-es2020": "npm:@better-typescript-lib/es2020@2.12.0", "@typescript/lib-es2021": "npm:@better-typescript-lib/es2021@2.12.0", "@typescript/lib-es2022": "npm:@better-typescript-lib/es2022@2.12.0", "@typescript/lib-es2023": "npm:@better-typescript-lib/es2023@2.12.0", "@typescript/lib-es2024": "npm:@better-typescript-lib/es2024@2.12.0", "@typescript/lib-es5": "npm:@better-typescript-lib/es5@2.12.0", "@typescript/lib-es6": "npm:@better-typescript-lib/es6@2.12.0", "@typescript/lib-esnext": "npm:@better-typescript-lib/esnext@2.12.0", "@typescript/lib-scripthost": "npm:@better-typescript-lib/scripthost@2.12.0", "@typescript/lib-webworker": "npm:@better-typescript-lib/webworker@2.12.0" }, "peerDependencies": { "typescript": ">=4.5.2" } }, "sha512-f7eO5Xs6Cczfx5eDRuDw/JYCrsdiC6gXdleB2KFZ5ZYgU/RRoev9swjt/eD0xo9PRDqNDwyjKx0n27CDHRZwvQ=="], "better-typescript-lib": ["better-typescript-lib@2.12.0", "", { "dependencies": { "@typescript/lib-decorators": "npm:@better-typescript-lib/decorators@2.12.0", "@typescript/lib-dom": "npm:@better-typescript-lib/dom@2.12.0", "@typescript/lib-es2015": "npm:@better-typescript-lib/es2015@2.12.0", "@typescript/lib-es2016": "npm:@better-typescript-lib/es2016@2.12.0", "@typescript/lib-es2017": "npm:@better-typescript-lib/es2017@2.12.0", "@typescript/lib-es2018": "npm:@better-typescript-lib/es2018@2.12.0", "@typescript/lib-es2019": "npm:@better-typescript-lib/es2019@2.12.0", "@typescript/lib-es2020": "npm:@better-typescript-lib/es2020@2.12.0", "@typescript/lib-es2021": "npm:@better-typescript-lib/es2021@2.12.0", "@typescript/lib-es2022": "npm:@better-typescript-lib/es2022@2.12.0", "@typescript/lib-es2023": "npm:@better-typescript-lib/es2023@2.12.0", "@typescript/lib-es2024": "npm:@better-typescript-lib/es2024@2.12.0", "@typescript/lib-es5": "npm:@better-typescript-lib/es5@2.12.0", "@typescript/lib-es6": "npm:@better-typescript-lib/es6@2.12.0", "@typescript/lib-esnext": "npm:@better-typescript-lib/esnext@2.12.0", "@typescript/lib-scripthost": "npm:@better-typescript-lib/scripthost@2.12.0", "@typescript/lib-webworker": "npm:@better-typescript-lib/webworker@2.12.0" }, "peerDependencies": { "typescript": ">=4.5.2" } }, "sha512-f7eO5Xs6Cczfx5eDRuDw/JYCrsdiC6gXdleB2KFZ5ZYgU/RRoev9swjt/eD0xo9PRDqNDwyjKx0n27CDHRZwvQ=="],
@ -712,13 +712,13 @@
"builtin-modules": ["builtin-modules@3.3.0", "", {}, "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw=="], "builtin-modules": ["builtin-modules@3.3.0", "", {}, "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw=="],
"bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], "bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="],
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
"cacheable": ["cacheable@2.3.4", "", { "dependencies": { "@cacheable/memory": "^2.0.8", "@cacheable/utils": "^2.4.0", "hookified": "^1.15.0", "keyv": "^5.6.0", "qified": "^0.9.0" } }, "sha512-djgxybDbw9fL/ZWMI3+CE8ZilNxcwFkVtDc1gJ+IlOSSWkSMPQabhV/XCHTQ6pwwN6aivXPZ43omTooZiX06Ew=="], "cacheable": ["cacheable@2.3.4", "", { "dependencies": { "@cacheable/memory": "^2.0.8", "@cacheable/utils": "^2.4.0", "hookified": "^1.15.0", "keyv": "^5.6.0", "qified": "^0.9.0" } }, "sha512-djgxybDbw9fL/ZWMI3+CE8ZilNxcwFkVtDc1gJ+IlOSSWkSMPQabhV/XCHTQ6pwwN6aivXPZ43omTooZiX06Ew=="],
"call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], "call-bind": ["call-bind@1.0.9", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" } }, "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ=="],
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
@ -796,9 +796,9 @@
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
"effect": ["effect@4.0.0-beta.43", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }, "sha512-AJYyDimIwJOn87uUz/JzmgDc5GfjxJbXvEbTvNzMa+M3Uer344bLo/O5mMRkqc1vBleA+Ygs4+dbE3QsqOkKTQ=="], "effect": ["effect@4.0.0-beta.46", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }, "sha512-3f6gXvvUMtEueCRY0tU76Vq2Pej1SAwwE+s0Owd5nD53yS5n4RZhUA1rlCGFuSbQFA225pGy8vO72+lpvu7u5A=="],
"electron-to-chromium": ["electron-to-chromium@1.5.331", "", {}, "sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q=="], "electron-to-chromium": ["electron-to-chromium@1.5.334", "", {}, "sha512-mgjZAz7Jyx1SRCwEpy9wefDS7GvNPazLthHg8eQMJ76wBdGQQDW33TCrUTvQ4wzpmOrv2zrFoD3oNufMdyMpog=="],
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
@ -808,7 +808,7 @@
"error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="],
"es-abstract": ["es-abstract@1.24.1", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw=="], "es-abstract": ["es-abstract@1.24.2", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg=="],
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
@ -830,7 +830,7 @@
"eslint-compat-utils": ["eslint-compat-utils@0.6.5", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ=="], "eslint-compat-utils": ["eslint-compat-utils@0.6.5", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ=="],
"eslint-plugin-astro": ["eslint-plugin-astro@1.6.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@jridgewell/sourcemap-codec": "^1.4.14", "@typescript-eslint/types": "^7.7.1 || ^8", "astro-eslint-parser": "^1.3.0", "eslint-compat-utils": "^0.6.0", "globals": "^16.0.0", "postcss": "^8.4.14", "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "eslint": ">=8.57.0" } }, "sha512-yGIbLHuj5MOUXa0s4sZ6cVhv6ehb+WLF80tsrGaxMk6VTUExruMzubQDzhOYt8fbR1c9vILCCRSCsKI7M1whig=="], "eslint-plugin-astro": ["eslint-plugin-astro@1.7.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@jridgewell/sourcemap-codec": "^1.4.14", "@typescript-eslint/types": "^7.7.1 || ^8", "astro-eslint-parser": "^1.3.0", "eslint-compat-utils": "^0.6.0", "globals": "^16.0.0", "postcss": "^8.4.14", "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "eslint": ">=8.57.0" } }, "sha512-89xpAn528UKCdmyysbg0AHHqi6sqcK89wXnJIpu4F0mFBN03zATEBNK7pRtMfl6gwtMOm5ECXs+Wz5qDHhwTFw=="],
"eslint-plugin-functional": ["eslint-plugin-functional@9.0.4", "", { "dependencies": { "@typescript-eslint/utils": "^8.26.0", "deepmerge-ts": "^7.1.5", "escape-string-regexp": "^5.0.0", "is-immutable-type": "^5.0.1", "ts-api-utils": "^2.0.1", "ts-declaration-location": "^1.0.6" }, "peerDependencies": { "eslint": "^9.0.0 || ^10.0.0", "typescript": ">=4.7.4" }, "optionalPeers": ["typescript"] }, "sha512-zm4qaoqb2r50V4WXxt0Mj92buXGMECYvMxGQ6sSb+XeJ+Eec6zCHuMY2+AWK1mqiApvUz2tCtp1P3zcEPU0huw=="], "eslint-plugin-functional": ["eslint-plugin-functional@9.0.4", "", { "dependencies": { "@typescript-eslint/utils": "^8.26.0", "deepmerge-ts": "^7.1.5", "escape-string-regexp": "^5.0.0", "is-immutable-type": "^5.0.1", "ts-api-utils": "^2.0.1", "ts-declaration-location": "^1.0.6" }, "peerDependencies": { "eslint": "^9.0.0 || ^10.0.0", "typescript": ">=4.7.4" }, "optionalPeers": ["typescript"] }, "sha512-zm4qaoqb2r50V4WXxt0Mj92buXGMECYvMxGQ6sSb+XeJ+Eec6zCHuMY2+AWK1mqiApvUz2tCtp1P3zcEPU0huw=="],
@ -1290,7 +1290,7 @@
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
"postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], "postcss": ["postcss@8.5.9", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw=="],
"postcss-media-query-parser": ["postcss-media-query-parser@0.2.3", "", {}, "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig=="], "postcss-media-query-parser": ["postcss-media-query-parser@0.2.3", "", {}, "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig=="],
@ -1308,7 +1308,7 @@
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
"prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], "prettier": ["prettier@3.8.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q=="],
"prettier-plugin-curly": ["prettier-plugin-curly@0.4.1", "", { "peerDependencies": { "prettier": "^3" } }, "sha512-Xc7zatoD0/08zYFv+hwnlqT5ekM81DCbBr73CWAsr1Fmx7qLQT/M0wfPx6w/+zfnmXH009xYvjzLUPcwzq7Fbw=="], "prettier-plugin-curly": ["prettier-plugin-curly@0.4.1", "", { "peerDependencies": { "prettier": "^3" } }, "sha512-Xc7zatoD0/08zYFv+hwnlqT5ekM81DCbBr73CWAsr1Fmx7qLQT/M0wfPx6w/+zfnmXH009xYvjzLUPcwzq7Fbw=="],
@ -1354,7 +1354,7 @@
"regjsgen": ["regjsgen@0.8.0", "", {}, "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q=="], "regjsgen": ["regjsgen@0.8.0", "", {}, "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q=="],
"regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="], "regjsparser": ["regjsparser@0.13.1", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw=="],
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
@ -1368,7 +1368,7 @@
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
"rolldown": ["rolldown@1.0.0-rc.13", "", { "dependencies": { "@oxc-project/types": "=0.123.0", "@rolldown/pluginutils": "1.0.0-rc.13" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.13", "@rolldown/binding-darwin-arm64": "1.0.0-rc.13", "@rolldown/binding-darwin-x64": "1.0.0-rc.13", "@rolldown/binding-freebsd-x64": "1.0.0-rc.13", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.13", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.13", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.13", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.13", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.13", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.13", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.13", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.13", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.13", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.13", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.13" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-bvVj8YJmf0rq4pSFmH7laLa6pYrhghv3PRzrCdRAr23g66zOKVJ4wkvFtgohtPLWmthgg8/rkaqRHrpUEh0Zbw=="], "rolldown": ["rolldown@1.0.0-rc.15", "", { "dependencies": { "@oxc-project/types": "=0.124.0", "@rolldown/pluginutils": "1.0.0-rc.15" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-x64": "1.0.0-rc.15", "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g=="],
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
@ -1438,7 +1438,7 @@
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], "side-channel-list": ["side-channel-list@1.0.1", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4" } }, "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w=="],
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
@ -1490,7 +1490,7 @@
"stylelint-config-recommended": ["stylelint-config-recommended@18.0.0", "", { "peerDependencies": { "stylelint": "^17.0.0" } }, "sha512-mxgT2XY6YZ3HWWe3Di8umG6aBmWmHTblTgu/f10rqFXnyWxjKWwNdjSWkgkwCtxIKnqjSJzvFmPT5yabVIRxZg=="], "stylelint-config-recommended": ["stylelint-config-recommended@18.0.0", "", { "peerDependencies": { "stylelint": "^17.0.0" } }, "sha512-mxgT2XY6YZ3HWWe3Di8umG6aBmWmHTblTgu/f10rqFXnyWxjKWwNdjSWkgkwCtxIKnqjSJzvFmPT5yabVIRxZg=="],
"stylelint-config-recommended-scss": ["stylelint-config-recommended-scss@17.0.0", "", { "dependencies": { "postcss-scss": "^4.0.9", "stylelint-config-recommended": "^18.0.0", "stylelint-scss": "^7.0.0" }, "peerDependencies": { "postcss": "^8.3.3", "stylelint": "^17.0.0" }, "optionalPeers": ["postcss"] }, "sha512-VkVD9r7jfUT/dq3mA3/I1WXXk2U71rO5wvU2yIil9PW5o1g3UM7Xc82vHmuVJHV7Y8ok5K137fmW5u3HbhtTOA=="], "stylelint-config-recommended-scss": ["stylelint-config-recommended-scss@17.0.1", "", { "dependencies": { "postcss-scss": "^4.0.9", "stylelint-config-recommended": "^18.0.0", "stylelint-scss": "^7.0.0" }, "peerDependencies": { "postcss": "^8.3.3", "stylelint": "^17.0.0" }, "optionalPeers": ["postcss"] }, "sha512-x5DVehzJudcwF0od3sGpgkln2PLLranFE7twwbp7dqDINCyZvwzFkMc6TLhNOvazRiVBJYATQLouJY0xPGB8WA=="],
"stylelint-config-sass-guidelines": ["stylelint-config-sass-guidelines@13.0.0", "", { "dependencies": { "@stylistic/stylelint-plugin": "^5.0.1", "postcss-scss": "^4.0.9", "stylelint-scss": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4.21", "stylelint": "^17.1.0" } }, "sha512-YJT0X8h0OqyEo7ys3EycV5CGWt2rrkEYE8sHSN6sFnrxbXvHiy4KJFHDOWfyb3eWR6wtYpM+yIyvR2Plc8+pCg=="], "stylelint-config-sass-guidelines": ["stylelint-config-sass-guidelines@13.0.0", "", { "dependencies": { "@stylistic/stylelint-plugin": "^5.0.1", "postcss-scss": "^4.0.9", "stylelint-scss": "^7.0.0" }, "peerDependencies": { "postcss": "^8.4.21", "stylelint": "^17.1.0" } }, "sha512-YJT0X8h0OqyEo7ys3EycV5CGWt2rrkEYE8sHSN6sFnrxbXvHiy4KJFHDOWfyb3eWR6wtYpM+yIyvR2Plc8+pCg=="],
@ -1526,7 +1526,7 @@
"terser": ["terser@5.46.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ=="], "terser": ["terser@5.46.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ=="],
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="],
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
@ -1562,7 +1562,7 @@
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
"unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="], "unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="],
@ -1588,7 +1588,7 @@
"varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="], "varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="],
"vite": ["vite@8.0.7", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.13", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-P1PbweD+2/udplnThz3btF4cf6AgPky7kk23RtHUkJIU5BIxwPprhRGmOAHs6FTI7UiGbTNrgNP6jSYD6JaRnw=="], "vite": ["vite@8.0.8", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.15", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw=="],
"vite-tsconfig-paths": ["vite-tsconfig-paths@6.1.1", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg=="], "vite-tsconfig-paths": ["vite-tsconfig-paths@6.1.1", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg=="],
@ -1632,38 +1632,10 @@
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@gcch/configuration-eslint/eslint": ["eslint@10.1.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.3", "@eslint/config-helpers": "^0.5.3", "@eslint/core": "^1.1.1", "@eslint/plugin-kit": "^0.6.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA=="],
"@gcch/configuration-eslint/typescript-eslint": ["typescript-eslint@8.58.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.58.0", "@typescript-eslint/parser": "8.58.0", "@typescript-eslint/typescript-estree": "8.58.0", "@typescript-eslint/utils": "8.58.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA=="],
"@gcch/configuration-prettier/prettier-plugin-sh": ["prettier-plugin-sh@0.18.0", "", { "dependencies": { "@reteps/dockerfmt": "^0.3.6", "sh-syntax": "^0.5.8" }, "peerDependencies": { "prettier": "^3.6.0" } }, "sha512-cW1XL27FOJQ/qGHOW6IHwdCiNWQsAgK+feA8V6+xUTaH0cD3Mh+tFAtBvEEWvuY6hTDzRV943Fzeii+qMOh7nQ=="],
"@keyv/bigmap/keyv": ["keyv@5.6.0", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw=="], "@keyv/bigmap/keyv": ["keyv@5.6.0", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw=="],
"@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.58.1", "", { "dependencies": { "@typescript-eslint/types": "8.58.1", "@typescript-eslint/visitor-keys": "8.58.1" } }, "sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w=="],
"@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.58.1", "", { "dependencies": { "@typescript-eslint/types": "8.58.1", "@typescript-eslint/typescript-estree": "8.58.1", "@typescript-eslint/utils": "8.58.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w=="],
"@typescript-eslint/eslint-plugin/@typescript-eslint/utils": ["@typescript-eslint/utils@8.58.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.58.1", "@typescript-eslint/types": "8.58.1", "@typescript-eslint/typescript-estree": "8.58.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ=="],
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.58.1", "", { "dependencies": { "@typescript-eslint/types": "8.58.1", "@typescript-eslint/visitor-keys": "8.58.1" } }, "sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w=="],
"@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.58.1", "", {}, "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw=="],
"@typescript-eslint/project-service/@typescript-eslint/types": ["@typescript-eslint/types@8.58.1", "", {}, "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw=="],
"@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.58.0", "", { "dependencies": { "@typescript-eslint/types": "8.58.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ=="],
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.58.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.58.0", "@typescript-eslint/tsconfig-utils": "8.58.0", "@typescript-eslint/types": "8.58.0", "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA=="],
"@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.58.1", "", {}, "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.58.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.58.0", "@typescript-eslint/tsconfig-utils": "8.58.0", "@typescript-eslint/types": "8.58.0", "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA=="],
"@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.58.1", "", {}, "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw=="],
"astro-eslint-parser/eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], "astro-eslint-parser/eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
"astro-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], "astro-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
@ -1672,8 +1644,6 @@
"babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"browserslist/caniuse-lite": ["caniuse-lite@1.0.30001784", "", {}, "sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw=="],
"browserslist-to-esbuild/meow": ["meow@13.2.0", "", {}, "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA=="], "browserslist-to-esbuild/meow": ["meow@13.2.0", "", {}, "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA=="],
"cacheable/keyv": ["keyv@5.6.0", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw=="], "cacheable/keyv": ["keyv@5.6.0", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw=="],
@ -1702,7 +1672,7 @@
"qified/hookified": ["hookified@2.1.1", "", {}, "sha512-AHb76R16GB5EsPBE2J7Ko5kiEyXwviB9P5SMrAKcuAu4vJPZttViAbj9+tZeaQE5zjDme+1vcHP78Yj/WoAveA=="], "qified/hookified": ["hookified@2.1.1", "", {}, "sha512-AHb76R16GB5EsPBE2J7Ko5kiEyXwviB9P5SMrAKcuAu4vJPZttViAbj9+tZeaQE5zjDme+1vcHP78Yj/WoAveA=="],
"rolldown/@oxc-project/types": ["@oxc-project/types@0.123.0", "", {}, "sha512-YtECP/y8Mj1lSHiUWGSRzy/C6teUKlS87dEfuVKT09LgQbUsBW1rNg+MiJ4buGu3yuADV60gbIvo9/HplA56Ew=="], "rolldown/@oxc-project/types": ["@oxc-project/types@0.124.0", "", {}, "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg=="],
"stylelint/file-entry-cache": ["file-entry-cache@11.1.2", "", { "dependencies": { "flat-cache": "^6.1.20" } }, "sha512-N2WFfK12gmrK1c1GXOqiAJ1tc5YE+R53zvQ+t5P8S5XhnmKYVB5eZEiLNZKDSmoG8wqqbF9EXYBBW/nef19log=="], "stylelint/file-entry-cache": ["file-entry-cache@11.1.2", "", { "dependencies": { "flat-cache": "^6.1.20" } }, "sha512-N2WFfK12gmrK1c1GXOqiAJ1tc5YE+R53zvQ+t5P8S5XhnmKYVB5eZEiLNZKDSmoG8wqqbF9EXYBBW/nef19log=="],
@ -1718,44 +1688,8 @@
"table/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "table/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.58.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.58.1", "@typescript-eslint/types": "8.58.1", "@typescript-eslint/typescript-estree": "8.58.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ=="],
"vite/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "vite/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"@gcch/configuration-eslint/eslint/@eslint/config-array": ["@eslint/config-array@0.23.3", "", { "dependencies": { "@eslint/object-schema": "^3.0.3", "debug": "^4.3.1", "minimatch": "^10.2.4" } }, "sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw=="],
"@gcch/configuration-eslint/eslint/@eslint/config-helpers": ["@eslint/config-helpers@0.5.3", "", { "dependencies": { "@eslint/core": "^1.1.1" } }, "sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw=="],
"@gcch/configuration-eslint/eslint/@eslint/core": ["@eslint/core@1.1.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ=="],
"@gcch/configuration-eslint/eslint/@eslint/plugin-kit": ["@eslint/plugin-kit@0.6.1", "", { "dependencies": { "@eslint/core": "^1.1.1", "levn": "^0.4.1" } }, "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ=="],
"@gcch/configuration-eslint/typescript-eslint/@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.58.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.58.0", "@typescript-eslint/type-utils": "8.58.0", "@typescript-eslint/utils": "8.58.0", "@typescript-eslint/visitor-keys": "8.58.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.58.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg=="],
"@gcch/configuration-eslint/typescript-eslint/@typescript-eslint/parser": ["@typescript-eslint/parser@8.58.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.58.0", "@typescript-eslint/types": "8.58.0", "@typescript-eslint/typescript-estree": "8.58.0", "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA=="],
"@gcch/configuration-eslint/typescript-eslint/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.58.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.58.0", "@typescript-eslint/tsconfig-utils": "8.58.0", "@typescript-eslint/types": "8.58.0", "@typescript-eslint/visitor-keys": "8.58.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA=="],
"@gcch/configuration-prettier/prettier-plugin-sh/@reteps/dockerfmt": ["@reteps/dockerfmt@0.3.6", "", {}, "sha512-Tb5wIMvBf/nLejTQ61krK644/CEMB/cpiaIFXqGApfGqO3GwcR3qnI0DbmkFVCl2OyEp8LnLX3EkucoL0+tbFg=="],
"@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.58.1", "", {}, "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw=="],
"@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.58.1", "", {}, "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw=="],
"@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.58.1", "", {}, "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw=="],
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.58.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.58.0", "@typescript-eslint/types": "^8.58.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg=="],
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.58.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A=="],
"@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.58.0", "", { "dependencies": { "@typescript-eslint/types": "8.58.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.58.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.58.0", "@typescript-eslint/types": "^8.58.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.58.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.58.0", "", { "dependencies": { "@typescript-eslint/types": "8.58.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ=="],
"eslint-plugin-jsx-a11y/minimatch/brace-expansion": ["brace-expansion@1.1.13", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w=="], "eslint-plugin-jsx-a11y/minimatch/brace-expansion": ["brace-expansion@1.1.13", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w=="],
"stylelint/file-entry-cache/flat-cache": ["flat-cache@6.1.22", "", { "dependencies": { "cacheable": "^2.3.4", "flatted": "^3.4.2", "hookified": "^1.15.0" } }, "sha512-N2dnzVJIphnNsjHcrxGW7DePckJ6haPrSFqpsBUhHYgwtKGVq4JrBGielEGD2fCVnsGm1zlBVZ8wGhkyuetgug=="], "stylelint/file-entry-cache/flat-cache": ["flat-cache@6.1.22", "", { "dependencies": { "cacheable": "^2.3.4", "flatted": "^3.4.2", "hookified": "^1.15.0" } }, "sha512-N2dnzVJIphnNsjHcrxGW7DePckJ6haPrSFqpsBUhHYgwtKGVq4JrBGielEGD2fCVnsGm1zlBVZ8wGhkyuetgug=="],
@ -1766,24 +1700,6 @@
"table/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "table/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.58.1", "", { "dependencies": { "@typescript-eslint/types": "8.58.1", "@typescript-eslint/visitor-keys": "8.58.1" } }, "sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w=="],
"typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.58.1", "", {}, "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw=="],
"@gcch/configuration-eslint/eslint/@eslint/config-array/@eslint/object-schema": ["@eslint/object-schema@3.0.3", "", {}, "sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ=="],
"@gcch/configuration-eslint/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.58.0", "", { "dependencies": { "@typescript-eslint/types": "8.58.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ=="],
"@gcch/configuration-eslint/typescript-eslint/@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"@gcch/configuration-eslint/typescript-eslint/@typescript-eslint/parser/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.58.0", "", { "dependencies": { "@typescript-eslint/types": "8.58.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ=="],
"@gcch/configuration-eslint/typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.58.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.58.0", "@typescript-eslint/types": "^8.58.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg=="],
"@gcch/configuration-eslint/typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.58.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A=="],
"@gcch/configuration-eslint/typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.58.0", "", { "dependencies": { "@typescript-eslint/types": "8.58.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ=="],
"eslint-plugin-jsx-a11y/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "eslint-plugin-jsx-a11y/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
} }
} }

View file

@ -1,5 +1,5 @@
import gcchConfig from "@gcch/configuration-oxlint"; import gcchConfig from "@gcch/configuration-oxlint";
import { OxlintConfig } from "oxlint"; import type { OxlintConfig } from "oxlint";
const config: OxlintConfig = { const config: OxlintConfig = {
...gcchConfig, ...gcchConfig,

View file

@ -5,7 +5,7 @@ export default defineConfig({
projects: [ projects: [
{ {
name: "desktop-chromium-1920", name: "desktop-chromium-1920",
use: { ...devices["Desktop Chrome"], viewport: { width: 1920, height: 1080 } }, use: { ...devices["Desktop Chrome"], viewport: { height: 1080, width: 1920 } },
}, },
// { // {
// name: "desktop-chromium-1536", // name: "desktop-chromium-1536",
@ -17,7 +17,7 @@ export default defineConfig({
// }, // },
{ {
name: "desktop-firefox-1920", name: "desktop-firefox-1920",
use: { ...devices["Desktop Firefox"], viewport: { width: 1920, height: 1080 } }, use: { ...devices["Desktop Firefox"], viewport: { height: 1080, width: 1920 } },
}, },
// { // {
// name: "desktop-firefox-1536", // name: "desktop-firefox-1536",
@ -51,7 +51,6 @@ export default defineConfig({
use: { use: {
/* Base URL to use in actions like `await page.goto('/')`. */ /* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "https://haikuatelier.gcch.local", baseURL: "https://haikuatelier.gcch.local",
trace: "retry-with-trace",
clientCertificates: [ clientCertificates: [
{ {
origin: "https://haikuatelier.gcch.local", origin: "https://haikuatelier.gcch.local",
@ -60,6 +59,7 @@ export default defineConfig({
}, },
], ],
ignoreHTTPSErrors: true, ignoreHTTPSErrors: true,
trace: "retry-with-trace",
}, },
workers: "100%", workers: "100%",
}); });

View file

@ -1,4 +1,4 @@
import { pipe, Array as FxArray } from "effect"; import { Array as FxArray, pipe } from "effect";
import type stylelint from "stylelint"; import type stylelint from "stylelint";
import { propertyGroups } from "stylelint-config-clean-order"; import { propertyGroups } from "stylelint-config-clean-order";

View file

@ -1,9 +1,4 @@
{ {
"autoload": {
"psr-4": {
"HaikuAtelier\\": "web/app/themes/haiku-atelier-2024/src/inc/"
}
},
"authors": [ "authors": [
{ {
"email": "scott.walkinshaw@gmail.com", "email": "scott.walkinshaw@gmail.com",
@ -16,6 +11,11 @@
"name": "Ben Word" "name": "Ben Word"
} }
], ],
"autoload": {
"psr-4": {
"HaikuAtelier\\": "web/app/themes/haiku-atelier-2024/src/inc/"
}
},
"config": { "config": {
"allow-plugins": { "allow-plugins": {
"carthage-software/mago": true, "carthage-software/mago": true,
@ -31,28 +31,45 @@
"description": "WordPress boilerplate with Composer, easier configuration, and an improved folder structure", "description": "WordPress boilerplate with Composer, easier configuration, and an improved folder structure",
"extra": { "extra": {
"installer-paths": { "installer-paths": {
"web/app/mu-plugins/{$name}/": ["type:wordpress-muplugin"], "web/app/mu-plugins/{$name}/": [
"web/app/plugins/{$name}/": ["type:wordpress-plugin"], "type:wordpress-muplugin"
"web/app/themes/{$name}/": ["type:wordpress-theme"], ],
"web/vendor/{$vendor}/{$name}": ["htmlburger/carbon-fields"] "web/app/plugins/{$name}/": [
"type:wordpress-plugin"
],
"web/app/themes/{$name}/": [
"type:wordpress-theme"
],
"web/vendor/{$vendor}/{$name}": [
"htmlburger/carbon-fields"
]
}, },
"wordpress-install-dir": "web/wp" "wordpress-install-dir": "web/wp"
}, },
"homepage": "https://roots.io/bedrock/", "homepage": "https://roots.io/bedrock/",
"keywords": ["bedrock", "composer", "roots", "wordpress", "wp", "wp-config"], "keywords": [
"bedrock",
"composer",
"roots",
"wordpress",
"wp",
"wp-config"
],
"license": "MIT", "license": "MIT",
"minimum-stability": "dev", "minimum-stability": "dev",
"name": "roots/bedrock", "name": "roots/bedrock",
"prefer-stable": true, "prefer-stable": true,
"repositories": [ "repositories": [
{ {
"only": ["wpackagist-plugin/*", "wpackagist-theme/*"], "only": [
"wpackagist-plugin/*",
"wpackagist-theme/*"
],
"type": "composer", "type": "composer",
"url": "https://wpackagist.org" "url": "https://wpackagist.org"
} }
], ],
"require": { "require": {
"php": ">=8.5",
"composer/installers": "^2.3", "composer/installers": "^2.3",
"crell/fp": "^1.0", "crell/fp": "^1.0",
"htmlburger/carbon-fields": "^3.6.9", "htmlburger/carbon-fields": "^3.6.9",
@ -63,10 +80,11 @@
"mnsami/composer-custom-directory-installer": "^2.0", "mnsami/composer-custom-directory-installer": "^2.0",
"nesbot/carbon": "^3.11.3", "nesbot/carbon": "^3.11.3",
"oscarotero/env": "^2.1.1", "oscarotero/env": "^2.1.1",
"php": ">=8.5",
"php-standard-library/php-standard-library": "^6.1.1",
"roots/bedrock-autoloader": "^1.1.0", "roots/bedrock-autoloader": "^1.1.0",
"roots/bedrock-disallow-indexing": "^2.1", "roots/bedrock-disallow-indexing": "^2.1",
"roots/wordpress": "^6.9.4", "roots/wordpress": "^6.9.4",
"php-standard-library/php-standard-library": "^6.1.1",
"roots/wp-config": "^1.0", "roots/wp-config": "^1.0",
"stripe/stripe-php": "^19.4.1", "stripe/stripe-php": "^19.4.1",
"symfony/uid": "^8.0.8", "symfony/uid": "^8.0.8",

35
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "8fa8994b91f6fdfb99db59a67eb54ac5", "content-hash": "bf6e098198b957782555eeb97479b37e",
"packages": [ "packages": [
{ {
"name": "carbonphp/carbon-doctrine-types", "name": "carbonphp/carbon-doctrine-types",
@ -5129,12 +5129,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git", "url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "7c570124dcf5c6834d78348d6817f32cd6b537d7" "reference": "d830a949e5c180e97c2245221daf8b589552cc2c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/7c570124dcf5c6834d78348d6817f32cd6b537d7", "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/d830a949e5c180e97c2245221daf8b589552cc2c",
"reference": "7c570124dcf5c6834d78348d6817f32cd6b537d7", "reference": "d830a949e5c180e97c2245221daf8b589552cc2c",
"shasum": "" "shasum": ""
}, },
"conflict": { "conflict": {
@ -5190,7 +5190,6 @@
"auth0/wordpress": "<=5.5", "auth0/wordpress": "<=5.5",
"automad/automad": "<2.0.0.0-alpha5", "automad/automad": "<2.0.0.0-alpha5",
"automattic/jetpack": "<9.8", "automattic/jetpack": "<9.8",
"avideo/avideo": "<=26",
"awesome-support/awesome-support": "<=6.0.7", "awesome-support/awesome-support": "<=6.0.7",
"aws/aws-sdk-php": "<=3.371.3", "aws/aws-sdk-php": "<=3.371.3",
"ayacoo/redirect-tab": "<2.1.2|>=3,<3.1.7|>=4,<4.0.5", "ayacoo/redirect-tab": "<2.1.2|>=3,<3.1.7|>=4,<4.0.5",
@ -5249,7 +5248,7 @@
"cesnet/simplesamlphp-module-proxystatistics": "<3.1", "cesnet/simplesamlphp-module-proxystatistics": "<3.1",
"chriskacerguis/codeigniter-restserver": "<=2.7.1", "chriskacerguis/codeigniter-restserver": "<=2.7.1",
"chrome-php/chrome": "<1.14", "chrome-php/chrome": "<1.14",
"ci4-cms-erp/ci4ms": "<=0.31.1", "ci4-cms-erp/ci4ms": "<=0.31.3",
"civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3", "civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3",
"ckeditor/ckeditor": "<4.25", "ckeditor/ckeditor": "<4.25",
"clickstorm/cs-seo": ">=6,<6.8|>=7,<7.5|>=8,<8.4|>=9,<9.3", "clickstorm/cs-seo": ">=6,<6.8|>=7,<7.5|>=8,<8.4|>=9,<9.3",
@ -5544,6 +5543,7 @@
"juzaweb/cms": "<=3.4.2", "juzaweb/cms": "<=3.4.2",
"jweiland/events2": "<8.3.8|>=9,<9.0.6", "jweiland/events2": "<8.3.8|>=9,<9.0.6",
"jweiland/kk-downloader": "<1.2.2", "jweiland/kk-downloader": "<1.2.2",
"kantorge/yaffa": "<=2",
"kazist/phpwhois": "<=4.2.6", "kazist/phpwhois": "<=4.2.6",
"kelvinmo/simplejwt": "<=1.1", "kelvinmo/simplejwt": "<=1.1",
"kelvinmo/simplexrd": "<3.1.1", "kelvinmo/simplexrd": "<3.1.1",
@ -5567,6 +5567,7 @@
"laravel/fortify": "<1.11.1", "laravel/fortify": "<1.11.1",
"laravel/framework": "<10.48.29|>=11,<11.44.1|>=12,<12.1.1", "laravel/framework": "<10.48.29|>=11,<11.44.1|>=12,<12.1.1",
"laravel/laravel": ">=5.4,<5.4.22", "laravel/laravel": ">=5.4,<5.4.22",
"laravel/passport": "<13.7.1",
"laravel/pulse": "<1.3.1", "laravel/pulse": "<1.3.1",
"laravel/reverb": "<1.7", "laravel/reverb": "<1.7",
"laravel/socialite": ">=1,<2.0.10", "laravel/socialite": ">=1,<2.0.10",
@ -5747,7 +5748,7 @@
"phpoffice/phpexcel": "<=1.8.2", "phpoffice/phpexcel": "<=1.8.2",
"phpoffice/phpspreadsheet": "<1.30|>=2,<2.1.12|>=2.2,<2.4|>=3,<3.10|>=4,<5", "phpoffice/phpspreadsheet": "<1.30|>=2,<2.1.12|>=2.2,<2.4|>=3,<3.10|>=4,<5",
"phppgadmin/phppgadmin": "<=7.13", "phppgadmin/phppgadmin": "<=7.13",
"phpseclib/phpseclib": "<=2.0.51|>=3,<=3.0.49", "phpseclib/phpseclib": "<2.0.53|>=3,<3.0.51",
"phpservermon/phpservermon": "<3.6", "phpservermon/phpservermon": "<3.6",
"phpsysinfo/phpsysinfo": "<3.4.3", "phpsysinfo/phpsysinfo": "<3.4.3",
"phpunit/phpunit": "<8.5.52|>=9,<9.6.33|>=10,<10.5.62|>=11,<11.5.50|>=12,<12.5.8", "phpunit/phpunit": "<8.5.52|>=9,<9.6.33|>=10,<10.5.62|>=11,<11.5.50|>=12,<12.5.8",
@ -5809,11 +5810,11 @@
"rap2hpoutre/laravel-log-viewer": "<0.13", "rap2hpoutre/laravel-log-viewer": "<0.13",
"react/http": ">=0.7,<1.9", "react/http": ">=0.7,<1.9",
"really-simple-plugins/complianz-gdpr": "<6.4.2", "really-simple-plugins/complianz-gdpr": "<6.4.2",
"redaxo/source": "<=5.20.1", "redaxo/source": "<5.21",
"remdex/livehelperchat": "<4.29", "remdex/livehelperchat": "<4.29",
"renolit/reint-downloadmanager": "<4.0.2|>=5,<5.0.1", "renolit/reint-downloadmanager": "<4.0.2|>=5,<5.0.1",
"reportico-web/reportico": "<=8.1", "reportico-web/reportico": "<=8.1",
"rhukster/dom-sanitizer": "<1.0.7", "rhukster/dom-sanitizer": "<1.0.10",
"rmccue/requests": ">=1.6,<1.8", "rmccue/requests": ">=1.6,<1.8",
"roadiz/documents": "<2.3.42|>=2.4,<2.5.44|>=2.6,<2.6.28|>=2.7,<2.7.9", "roadiz/documents": "<2.3.42|>=2.4,<2.5.44|>=2.6,<2.6.28|>=2.7,<2.7.9",
"robrichards/xmlseclibs": "<3.1.5", "robrichards/xmlseclibs": "<3.1.5",
@ -6171,7 +6172,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-04-06T23:13:58+00:00" "time": "2026-04-10T21:13:58+00:00"
}, },
{ {
"name": "sebastian/diff", "name": "sebastian/diff",
@ -7410,16 +7411,16 @@
}, },
{ {
"name": "webmozart/assert", "name": "webmozart/assert",
"version": "2.1.6", "version": "2.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/webmozarts/assert.git", "url": "https://github.com/webmozarts/assert.git",
"reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8" "reference": "1b99650e7ffcad232624a260bc7fbdec2ffc407c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/ff31ad6efc62e66e518fbab1cde3453d389bcdc8", "url": "https://api.github.com/repos/webmozarts/assert/zipball/1b99650e7ffcad232624a260bc7fbdec2ffc407c",
"reference": "ff31ad6efc62e66e518fbab1cde3453d389bcdc8", "reference": "1b99650e7ffcad232624a260bc7fbdec2ffc407c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -7466,9 +7467,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/webmozarts/assert/issues", "issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/2.1.6" "source": "https://github.com/webmozarts/assert/tree/2.2.0"
}, },
"time": "2026-02-27T10:28:38+00:00" "time": "2026-04-09T16:54:47+00:00"
} }
], ],
"aliases": [], "aliases": [],
@ -7483,5 +7484,5 @@
"php": ">=8.5" "php": ">=8.5"
}, },
"platform-dev": {}, "platform-dev": {},
"plugin-api-version": "2.9.0" "plugin-api-version": "2.6.0"
} }

View file

@ -37,16 +37,16 @@ $webroot_dir = $root_dir . '/web';
* .env.local will override .env if it exists * .env.local will override .env if it exists
*/ */
if (file_exists($root_dir . '/.env')) { if (file_exists($root_dir . '/.env')) {
$env_files = file_exists($root_dir . '/.env.local') ? ['.env', '.env.local'] : ['.env']; $env_files = file_exists($root_dir . '/.env.local') ? ['.env', '.env.local'] : ['.env'];
$dotenv = Dotenv\Dotenv::createImmutable($root_dir, $env_files, false); $dotenv = Dotenv\Dotenv::createImmutable($root_dir, $env_files, false);
$dotenv->load(); $dotenv->load();
$dotenv->required(['WP_HOME', 'WP_SITEURL']); $dotenv->required(['WP_HOME', 'WP_SITEURL']);
if (!env('DATABASE_URL')) { if (!env('DATABASE_URL')) {
$dotenv->required(['DB_NAME', 'DB_USER', 'DB_PASSWORD']); $dotenv->required(['DB_NAME', 'DB_USER', 'DB_PASSWORD']);
} }
} }
/* /*
@ -57,7 +57,7 @@ define('WP_ENV', env('WP_ENV') ?: 'production');
// Infer WP_ENVIRONMENT_TYPE based on WP_ENV // Infer WP_ENVIRONMENT_TYPE based on WP_ENV
if (!env('WP_ENVIRONMENT_TYPE') && in_array(WP_ENV, ['production', 'staging', 'development', 'local'], true)) { if (!env('WP_ENVIRONMENT_TYPE') && in_array(WP_ENV, ['production', 'staging', 'development', 'local'], true)) {
Config::define('WP_ENVIRONMENT_TYPE', WP_ENV); Config::define('WP_ENVIRONMENT_TYPE', WP_ENV);
} }
// URLs // URLs
@ -71,7 +71,7 @@ Config::define('WP_CONTENT_URL', Config::get('WP_HOME') . Config::get('CONTENT_D
// DB settings // DB settings
if (env('DB_SSL')) { if (env('DB_SSL')) {
Config::define('MYSQL_CLIENT_FLAGS', MYSQLI_CLIENT_SSL); Config::define('MYSQL_CLIENT_FLAGS', MYSQLI_CLIENT_SSL);
} }
Config::define('DB_NAME', env('DB_NAME')); Config::define('DB_NAME', env('DB_NAME'));
@ -83,12 +83,12 @@ Config::define('DB_COLLATE', '');
$table_prefix = env('DB_PREFIX') ?: 'wp_'; $table_prefix = env('DB_PREFIX') ?: 'wp_';
if (env('DATABASE_URL')) { if (env('DATABASE_URL')) {
$dsn = (object) parse_url(env('DATABASE_URL')); $dsn = (object) parse_url(env('DATABASE_URL'));
Config::define('DB_NAME', mb_substr($dsn->path, 1)); Config::define('DB_NAME', mb_substr($dsn->path, 1));
Config::define('DB_USER', $dsn->user); Config::define('DB_USER', $dsn->user);
Config::define('DB_PASSWORD', $dsn->pass ?? null); Config::define('DB_PASSWORD', $dsn->pass ?? null);
Config::define('DB_HOST', isset($dsn->port) ? "{$dsn->host}:{$dsn->port}" : $dsn->host); Config::define('DB_HOST', isset($dsn->port) ? "{$dsn->host}:{$dsn->port}" : $dsn->host);
} }
// Authentication Unique Keys and Salts // Authentication Unique Keys and Salts
@ -129,18 +129,18 @@ Config::define('WP_PLUGIN_DIR', Config::get('WP_CONTENT_DIR') . '/plugins');
* See https://codex.wordpress.org/Function_Reference/is_ssl#Notes * See https://codex.wordpress.org/Function_Reference/is_ssl#Notes
*/ */
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO']) { if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO']) {
$_SERVER['HTTPS'] = 'on'; $_SERVER['HTTPS'] = 'on';
} }
$env_config = __DIR__ . '/environments/' . WP_ENV . '.php'; $env_config = __DIR__ . '/environments/' . WP_ENV . '.php';
if (file_exists($env_config)) { if (file_exists($env_config)) {
include_once $env_config; include_once $env_config;
} }
Config::apply(); Config::apply();
// Bootstrap WordPress // Bootstrap WordPress
if (!defined('ABSPATH')) { if (!defined('ABSPATH')) {
define('ABSPATH', $webroot_dir . '/wp/'); define('ABSPATH', $webroot_dir . '/wp/');
} }

View file

@ -1,49 +1,52 @@
{ {
"dictionaries": ["fr-fr", "en-gb"], "dictionaries": [
"en-gb",
"fr-fr"
],
"userWords": [ "userWords": [
"lightningcss", "codesniffer",
"curryfication",
"eilandert",
"ERRMODE",
"gcch",
"giftcard",
"haikuatelier", "haikuatelier",
"healthcheck", "healthcheck",
"traefik",
"innodb", "innodb",
"jaegertracing", "jaegertracing",
"eilandert",
"valkey",
"somaxconn",
"woocommerce",
"Squiz",
"twentytwentyfour",
"symfony",
"phpstan",
"codesniffer",
"muplugin",
"wpautop",
"ERRMODE",
"laravel", "laravel",
"multishipping", "lightningcss",
"multiformats", "multiformats",
"curryfication", "multishipping",
"giftcard", "muplugin",
"taplo",
"phpactor", "phpactor",
"gcch" "phpstan",
"somaxconn",
"Squiz",
"symfony",
"taplo",
"traefik",
"twentytwentyfour",
"valkey",
"woocommerce",
"wpautop"
], ],
"words": [ "words": [
"GLITCHTIP", "classlike",
"Vali", "Crell",
"Eles",
"fdir", "fdir",
"friendsofphp",
"GLITCHTIP",
"htmlburger",
"logtape",
"mobily", "mobily",
"oxlint", "oxlint",
"valibot",
"zstandard",
"Eles",
"logtape",
"wpackagist",
"phpdotenv", "phpdotenv",
"friendsofphp", "Vali",
"htmlburger", "valibot",
"Crell", "wpackagist",
"wpdb", "wpdb",
"classlike" "zstandard"
] ]
} }

View file

@ -105,6 +105,12 @@ lint-js:
--config cfg/oxlint.config.ts \ --config cfg/oxlint.config.ts \
--format stylish --format stylish
fix-js:
bun --bun oxlint \
--config cfg/oxlint.config.ts \
--format stylish \
--fix --fix-suggestions --fix-dangerously
# Vérifie le code Sass avec Stylelint. # Vérifie le code Sass avec Stylelint.
[group('css')] [group('css')]
[group('qualité')] [group('qualité')]

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,10 @@
"baseline": { "baseline": {
"default": null, "default": null,
"description": "Path to a baseline file to ignore listed issues.", "description": "Path to a baseline file to ignore listed issues.",
"type": ["string", "null"] "type": [
"null",
"string"
]
}, },
"baseline-variant": { "baseline-variant": {
"$ref": "#/$defs/BaselineVariant", "$ref": "#/$defs/BaselineVariant",
@ -135,7 +138,10 @@
}, },
"perform-heuristic-checks": { "perform-heuristic-checks": {
"description": "**Deprecated**: Use `check-missing-override` and `find-unused-parameters` instead.\n\nWhen set to `true`, enables both `check-missing-override` and `find-unused-parameters`.\nWhen set to `false`, disables both.\n\nThis option is kept for backwards compatibility with existing configurations.", "description": "**Deprecated**: Use `check-missing-override` and `find-unused-parameters` instead.\n\nWhen set to `true`, enables both `check-missing-override` and `find-unused-parameters`.\nWhen set to `false`, disables both.\n\nThis option is kept for backwards compatibility with existing configurations.",
"type": ["boolean", "null"], "type": [
"boolean",
"null"
],
"writeOnly": true "writeOnly": true
}, },
"performance": { "performance": {
@ -200,11 +206,18 @@
"type": "object" "type": "object"
}, },
"ArrayStyleOption": { "ArrayStyleOption": {
"enum": ["short", "long"], "enum": [
"long",
"short"
],
"type": "string" "type": "string"
}, },
"AssertionStyle": { "AssertionStyle": {
"enum": ["static", "self_", "this"], "enum": [
"self_",
"static",
"this"
],
"type": "string" "type": "string"
}, },
"BaselineVariant": { "BaselineVariant": {
@ -224,7 +237,11 @@
}, },
"BraceStyle": { "BraceStyle": {
"description": "Specifies brace placement style for various constructs.\n\n- `SameLine`: Opening brace on the same line as the declaration\n- `NextLine`: Opening brace on the next line for single-line signatures;\n on the same line when the signature breaks across multiple lines\n- `AlwaysNextLine`: Opening brace always on the next line, regardless of\n whether the signature breaks", "description": "Specifies brace placement style for various constructs.\n\n- `SameLine`: Opening brace on the same line as the declaration\n- `NextLine`: Opening brace on the next line for single-line signatures;\n on the same line when the signature breaks across multiple lines\n- `AlwaysNextLine`: Opening brace always on the next line, regardless of\n whether the signature breaks",
"enum": ["same_line", "next_line", "always_next_line"], "enum": [
"always_next_line",
"next_line",
"same_line"
],
"type": "string" "type": "string"
}, },
"DisallowedEntry": { "DisallowedEntry": {
@ -237,13 +254,18 @@
"description": "Entry with name and optional help message.", "description": "Entry with name and optional help message.",
"properties": { "properties": {
"help": { "help": {
"type": ["string", "null"] "type": [
"null",
"string"
]
}, },
"name": { "name": {
"type": "string" "type": "string"
} }
}, },
"required": ["name"], "required": [
"name"
],
"type": "object" "type": "object"
} }
], ],
@ -251,7 +273,12 @@
}, },
"EndOfLine": { "EndOfLine": {
"description": "Specifies the style of line endings.", "description": "Specifies the style of line endings.",
"enum": ["auto", "lf", "crlf", "cr"], "enum": [
"auto",
"cr",
"crlf",
"lf"
],
"type": "string" "type": "string"
}, },
"FormatterConfiguration": { "FormatterConfiguration": {
@ -735,7 +762,10 @@
"baseline": { "baseline": {
"default": null, "default": null,
"description": "Path to a baseline file to ignore listed issues.", "description": "Path to a baseline file to ignore listed issues.",
"type": ["string", "null"] "type": [
"null",
"string"
]
}, },
"baseline-variant": { "baseline-variant": {
"$ref": "#/$defs/BaselineVariant", "$ref": "#/$defs/BaselineVariant",
@ -815,7 +845,10 @@
"type": "array" "type": "array"
} }
}, },
"required": ["code", "in"], "required": [
"code",
"in"
],
"type": "object" "type": "object"
} }
], ],
@ -852,7 +885,10 @@
"baseline": { "baseline": {
"default": null, "default": null,
"description": "Path to a baseline file to ignore listed issues.", "description": "Path to a baseline file to ignore listed issues.",
"type": ["string", "null"] "type": [
"null",
"string"
]
}, },
"baseline-variant": { "baseline-variant": {
"$ref": "#/$defs/BaselineVariant", "$ref": "#/$defs/BaselineVariant",
@ -994,11 +1030,11 @@
"level": "Help" "level": "Help"
}, },
"halstead": { "halstead": {
"difficulty-threshold": 12.0, "difficulty-threshold": 12,
"effort-threshold": 5000.0, "effort-threshold": 5000,
"enabled": true, "enabled": true,
"level": "Warning", "level": "Warning",
"volume-threshold": 1000.0 "volume-threshold": 1000
}, },
"identity-comparison": { "identity-comparison": {
"enabled": true, "enabled": true,
@ -1514,7 +1550,9 @@
}, },
"tainted-data-to-sink": { "tainted-data-to-sink": {
"enabled": true, "enabled": true,
"known-sink-functions": ["printf"], "known-sink-functions": [
"printf"
],
"level": "Error" "level": "Error"
}, },
"too-many-enum-cases": { "too-many-enum-cases": {
@ -1585,12 +1623,19 @@
"type": "object" "type": "object"
}, },
"MethodChainBreakingStyle": { "MethodChainBreakingStyle": {
"enum": ["same_line", "next_line"], "enum": [
"next_line",
"same_line"
],
"type": "string" "type": "string"
}, },
"NullTypeHint": { "NullTypeHint": {
"description": "Specifies null type hint style.", "description": "Specifies null type hint style.",
"enum": ["null_pipe", "null_pipe_last", "question"], "enum": [
"null_pipe",
"null_pipe_last",
"question"
],
"type": "string" "type": "string"
}, },
"PHPVersion": { "PHPVersion": {
@ -1697,7 +1742,10 @@
"type": "array" "type": "array"
} }
}, },
"required": ["namespace", "permit"], "required": [
"namespace",
"permit"
],
"type": "object" "type": "object"
}, },
"PerimeterSettings": { "PerimeterSettings": {
@ -1747,14 +1795,22 @@
"$ref": "#/$defs/Path" "$ref": "#/$defs/Path"
} }
}, },
"required": ["path", "kinds"], "required": [
"kinds",
"path"
],
"type": "object" "type": "object"
} }
] ]
}, },
"PermittedDependencyKind": { "PermittedDependencyKind": {
"description": "Represents the specific types of symbols allowed from a path.", "description": "Represents the specific types of symbols allowed from a path.",
"enum": ["class-like", "function", "constant", "attribute"], "enum": [
"attribute",
"class-like",
"constant",
"function"
],
"type": "string" "type": "string"
}, },
"RuleSettings": { "RuleSettings": {
@ -2654,7 +2710,9 @@
"type": "array" "type": "array"
}, },
"known-sink-functions": { "known-sink-functions": {
"default": ["printf"], "default": [
"printf"
],
"items": { "items": {
"type": "string" "type": "string"
}, },
@ -2758,7 +2816,10 @@
"description": "Maximum cyclomatic complexity allowed for a single method.\n\nWhen set, each method in a class-like is checked individually against this threshold,\nin addition to the class-level `threshold` check.\n\nDefault: `None` (methods are only checked as part of the class-level total).", "description": "Maximum cyclomatic complexity allowed for a single method.\n\nWhen set, each method in a class-like is checked individually against this threshold,\nin addition to the class-level `threshold` check.\n\nDefault: `None` (methods are only checked as part of the class-level total).",
"format": "uint", "format": "uint",
"minimum": 0, "minimum": 0,
"type": ["integer", "null"] "type": [
"integer",
"null"
]
}, },
"threshold": { "threshold": {
"default": 15, "default": 15,
@ -3308,7 +3369,10 @@
"description": "Maximum nesting depth allowed inside a single function, method, closure, or arrow function.\n\nWhen set, each function-like body is checked independently against this threshold,\nwith nesting counted from the function body (not the file root).\n\nDefault: `None` (function-like bodies are only checked against the global `threshold`).", "description": "Maximum nesting depth allowed inside a single function, method, closure, or arrow function.\n\nWhen set, each function-like body is checked independently against this threshold,\nwith nesting counted from the function body (not the file root).\n\nDefault: `None` (function-like bodies are only checked against the global `threshold`).",
"format": "uint", "format": "uint",
"minimum": 0, "minimum": 0,
"type": ["integer", "null"] "type": [
"integer",
"null"
]
}, },
"level": { "level": {
"$ref": "#/$defs/Level", "$ref": "#/$defs/Level",
@ -3331,7 +3395,10 @@
"format": "uint8", "format": "uint8",
"maximum": 255, "maximum": 255,
"minimum": 0, "minimum": 0,
"type": ["integer", "null"] "type": [
"integer",
"null"
]
}, },
"enabled": { "enabled": {
"default": true, "default": true,
@ -3401,12 +3468,12 @@
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"difficulty-threshold": { "difficulty-threshold": {
"default": 12.0, "default": 12,
"format": "double", "format": "double",
"type": "number" "type": "number"
}, },
"effort-threshold": { "effort-threshold": {
"default": 5000.0, "default": 5000,
"format": "double", "format": "double",
"type": "number" "type": "number"
}, },
@ -3425,7 +3492,7 @@
"default": "Warning" "default": "Warning"
}, },
"volume-threshold": { "volume-threshold": {
"default": 1000.0, "default": 1000,
"format": "double", "format": "double",
"type": "number" "type": "number"
} }
@ -5417,11 +5484,11 @@
"halstead": { "halstead": {
"$ref": "#/$defs/RuleSettings20", "$ref": "#/$defs/RuleSettings20",
"default": { "default": {
"difficulty-threshold": 12.0, "difficulty-threshold": 12,
"effort-threshold": 5000.0, "effort-threshold": 5000,
"enabled": true, "enabled": true,
"level": "Warning", "level": "Warning",
"volume-threshold": 1000.0 "volume-threshold": 1000
} }
}, },
"identity-comparison": { "identity-comparison": {
@ -6303,7 +6370,9 @@
"$ref": "#/$defs/RuleSettings136", "$ref": "#/$defs/RuleSettings136",
"default": { "default": {
"enabled": true, "enabled": true,
"known-sink-functions": ["printf"], "known-sink-functions": [
"printf"
],
"level": "Error" "level": "Error"
} }
}, },
@ -6423,7 +6492,9 @@
"type": "array" "type": "array"
}, },
"extensions": { "extensions": {
"default": ["php"], "default": [
"php"
],
"description": "File extensions to filter by.\n\nDefaults to `[\".php\"]`.", "description": "File extensions to filter by.\n\nDefaults to `[\".php\"]`.",
"items": { "items": {
"type": "string" "type": "string"
@ -6461,7 +6532,9 @@
"type": "string" "type": "string"
} }
}, },
"required": ["workspace"], "required": [
"workspace"
],
"type": "object" "type": "object"
}, },
"StructuralInheritanceConstraint": { "StructuralInheritanceConstraint": {
@ -6504,27 +6577,42 @@
"items": { "items": {
"$ref": "#/$defs/StructuralSymbolKind" "$ref": "#/$defs/StructuralSymbolKind"
}, },
"type": ["array", "null"] "type": [
"array",
"null"
]
}, },
"must-be-abstract": { "must-be-abstract": {
"default": null, "default": null,
"description": "If true, the symbol must be declared `abstract`.", "description": "If true, the symbol must be declared `abstract`.",
"type": ["boolean", "null"] "type": [
"boolean",
"null"
]
}, },
"must-be-final": { "must-be-final": {
"default": null, "default": null,
"description": "If true, the symbol must be declared `final`.", "description": "If true, the symbol must be declared `final`.",
"type": ["boolean", "null"] "type": [
"boolean",
"null"
]
}, },
"must-be-named": { "must-be-named": {
"default": null, "default": null,
"description": "Optional naming pattern the symbol's name must match.", "description": "Optional naming pattern the symbol's name must match.",
"type": ["string", "null"] "type": [
"null",
"string"
]
}, },
"must-be-readonly": { "must-be-readonly": {
"default": null, "default": null,
"description": "If true, the symbol must be declared `readonly`.", "description": "If true, the symbol must be declared `readonly`.",
"type": ["boolean", "null"] "type": [
"boolean",
"null"
]
}, },
"must-extend": { "must-extend": {
"anyOf": [ "anyOf": [
@ -6577,7 +6665,10 @@
"not-on": { "not-on": {
"default": null, "default": null,
"description": "An optional exclusion pattern; if the namespace matches this, the rule is skipped.", "description": "An optional exclusion pattern; if the namespace matches this, the rule is skipped.",
"type": ["string", "null"] "type": [
"null",
"string"
]
}, },
"on": { "on": {
"default": "", "default": "",
@ -6587,7 +6678,10 @@
"reason": { "reason": {
"default": null, "default": null,
"description": "A human-readable reason for this rule.", "description": "A human-readable reason for this rule.",
"type": ["string", "null"] "type": [
"null",
"string"
]
}, },
"target": { "target": {
"anyOf": [ "anyOf": [
@ -6619,7 +6713,15 @@
"type": "object" "type": "object"
}, },
"StructuralSymbolKind": { "StructuralSymbolKind": {
"enum": ["class-like", "class", "interface", "trait", "enum", "constant", "function"], "enum": [
"class",
"class-like",
"constant",
"enum",
"function",
"interface",
"trait"
],
"type": "string" "type": "string"
} }
}, },
@ -6682,7 +6784,10 @@
"editor-url": { "editor-url": {
"default": null, "default": null,
"description": "Editor URL template for OSC 8 terminal hyperlinks on file paths in diagnostics.\n\nWhen set, file paths in diagnostic output become clickable links in terminals\nthat support OSC 8 hyperlinks (e.g., iTerm2, Wezterm, Kitty, Windows Terminal).\n\nSupported placeholders:\n- `%file%` — absolute file path\n- `%line%` — line number\n- `%column%` — column number\n\nCan be set via `MAGO_EDITOR_URL` environment variable or `editor-url` in `mago.toml`.", "description": "Editor URL template for OSC 8 terminal hyperlinks on file paths in diagnostics.\n\nWhen set, file paths in diagnostic output become clickable links in terminals\nthat support OSC 8 hyperlinks (e.g., iTerm2, Wezterm, Kitty, Windows Terminal).\n\nSupported placeholders:\n- `%file%` — absolute file path\n- `%line%` — line number\n- `%column%` — column number\n\nCan be set via `MAGO_EDITOR_URL` environment variable or `editor-url` in `mago.toml`.",
"type": ["string", "null"] "type": [
"null",
"string"
]
}, },
"formatter": { "formatter": {
"$ref": "#/$defs/FormatterConfiguration", "$ref": "#/$defs/FormatterConfiguration",
@ -6830,11 +6935,11 @@
"level": "Help" "level": "Help"
}, },
"halstead": { "halstead": {
"difficulty-threshold": 12.0, "difficulty-threshold": 12,
"effort-threshold": 5000.0, "effort-threshold": 5000,
"enabled": true, "enabled": true,
"level": "Warning", "level": "Warning",
"volume-threshold": 1000.0 "volume-threshold": 1000
}, },
"identity-comparison": { "identity-comparison": {
"enabled": true, "enabled": true,
@ -7350,7 +7455,9 @@
}, },
"tainted-data-to-sink": { "tainted-data-to-sink": {
"enabled": true, "enabled": true,
"known-sink-functions": ["printf"], "known-sink-functions": [
"printf"
],
"level": "Error" "level": "Error"
}, },
"too-many-enum-cases": { "too-many-enum-cases": {
@ -7434,7 +7541,9 @@
"$ref": "#/$defs/SourceConfiguration", "$ref": "#/$defs/SourceConfiguration",
"default": { "default": {
"excludes": [], "excludes": [],
"extensions": ["php"], "extensions": [
"php"
],
"glob": { "glob": {
"backslash-escape": true, "backslash-escape": true,
"case-insensitive": false, "case-insensitive": false,

View file

@ -5,7 +5,9 @@ stack-size = 0
threads = 0 threads = 0
[source] [source]
excludes = ["web/wp/wp-admin/includes/noop.php"] excludes = [
"web/wp/wp-admin/includes/noop.php",
]
extensions = ["php"] extensions = ["php"]
includes = ["config", "vendor", "web/app/plugins", "web/vendor", "web/wp"] includes = ["config", "vendor", "web/app/plugins", "web/vendor", "web/wp"]
paths = ["web/app/themes/haiku-atelier-2024"] paths = ["web/app/themes/haiku-atelier-2024"]
@ -66,3 +68,9 @@ threads = 0
negation-complexity-threshold = 8192 negation-complexity-threshold = 8192
saturation-complexity-threshold = 16384 saturation-complexity-threshold = 16384
string-combination-threshold = 256 string-combination-threshold = 256
[formatter]
excludes = [
"web/app/mu-plugins",
"web/app/plugins",
]

View file

@ -14,14 +14,14 @@
"@mobily/ts-belt": "v4.0.0-rc.5", "@mobily/ts-belt": "v4.0.0-rc.5",
"@sentry/browser": "^10.47.0", "@sentry/browser": "^10.47.0",
"a11y-dialog": "^8.1.5", "a11y-dialog": "^8.1.5",
"effect": "^4.0.0-beta.43", "effect": "^4.0.0-beta.46",
"lit-html": "^3.3.2", "lit-html": "^3.3.2",
"purify-ts": "2.1.2", "purify-ts": "2.1.2",
"ts-pattern": "^5.9.0", "ts-pattern": "^5.9.0",
"valibot": "1.1.0" "valibot": "1.1.0"
}, },
"devDependencies": { "devDependencies": {
"@effect/language-service": "^0.84.3", "@effect/language-service": "^0.85.0",
"@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274", "@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#62ee424274",
"@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#0968f683", "@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#0968f683",
"@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#8de937e801", "@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#8de937e801",
@ -60,7 +60,7 @@
"stylelint-plugin-logical-css": "^2.1.0", "stylelint-plugin-logical-css": "^2.1.0",
"typescript": "6.0.2", "typescript": "6.0.2",
"typescript-eslint": "^8.58.1", "typescript-eslint": "^8.58.1",
"vite": "^8.0.7", "vite": "^8.0.8",
"vite-tsconfig-paths": "^6.1.1" "vite-tsconfig-paths": "^6.1.1"
}, },
"browserslist": [ "browserslist": [

View file

@ -1,12 +1,12 @@
{ {
"$schema": "https:\/\/json-schema.org\/draft-07\/schema", "$schema": "https://json-schema.org/draft-07/schema",
"properties": { "properties": {
"$schema": { "$schema": {
"default": "", "default": "",
"description": "Path to JSON schema, which can be used for config autocompletion, use phpactor config:initialize to update" "description": "Path to JSON schema, which can be used for config autocompletion, use phpactor config:initialize to update"
}, },
"behat.config_path": { "behat.config_path": {
"default": "%project_root%\/behat.yml", "default": "%project_root%/behat.yml",
"description": "Path to the main behat.yml (including the filename behat.yml)" "description": "Path to the main behat.yml (including the filename behat.yml)"
}, },
"behat.symfony.di_xml_path": { "behat.symfony.di_xml_path": {
@ -61,11 +61,19 @@
"description": "Object fill refactoring: use named parameters" "description": "Object fill refactoring: use named parameters"
}, },
"code_transform.template_paths": { "code_transform.template_paths": {
"default": ["%project_config%\/templates", "%config%\/templates"], "default": [
"%config%/templates",
"%project_config%/templates"
],
"description": "Paths in which to look for code templates" "description": "Paths in which to look for code templates"
}, },
"command": { "description": "Internal use only - name of the command which was executed" }, "command": {
"completion.dedupe": { "default": true, "description": "If results should be de-duplicated" }, "description": "Internal use only - name of the command which was executed"
},
"completion.dedupe": {
"default": true,
"description": "If results should be de-duplicated"
},
"completion.dedupe_match_fqn": { "completion.dedupe_match_fqn": {
"default": true, "default": true,
"description": "If ``completion.dedupe``, consider the class FQN in addition to the completion suggestion" "description": "If ``completion.dedupe``, consider the class FQN in addition to the completion suggestion"
@ -73,9 +81,14 @@
"completion.label_formatter": { "completion.label_formatter": {
"default": "helpful", "default": "helpful",
"description": "Definition of how to format entries in the completion list", "description": "Definition of how to format entries in the completion list",
"enum": ["helpful", "fqn"] "enum": [
"fqn",
"helpful"
]
},
"completion.limit": {
"description": "Sets a limit on the number of completion suggestions for any request"
}, },
"completion.limit": { "description": "Sets a limit on the number of completion suggestions for any request" },
"completion_worse.completor.attribute.enabled": { "completion_worse.completor.attribute.enabled": {
"default": true, "default": true,
"description": "Enable or disable the ``attribute`` completor.\n\nCompletion for attribute class names." "description": "Enable or disable the ``attribute`` completor.\n\nCompletion for attribute class names."
@ -92,7 +105,10 @@
"default": true, "default": true,
"description": "Enable or disable the ``class_member`` completor.\n\nCompletion for class members." "description": "Enable or disable the ``class_member`` completor.\n\nCompletion for class members."
}, },
"completion_worse.completor.constant.enabled": { "default": false, "description": null }, "completion_worse.completor.constant.enabled": {
"default": false,
"description": null
},
"completion_worse.completor.constructor.enabled": { "completion_worse.completor.constructor.enabled": {
"default": true, "default": true,
"description": "Enable or disable the ``constructor`` completor.\n\nCompletion for constructors." "description": "Enable or disable the ``constructor`` completor.\n\nCompletion for constructors."
@ -147,7 +163,7 @@
}, },
"completion_worse.completor.symfony.enabled": { "completion_worse.completor.symfony.enabled": {
"default": true, "default": true,
"description": "Enable\/disable the Symfony completor - depends on Symfony extension being enabled" "description": "Enable/disable the Symfony completor - depends on Symfony extension being enabled"
}, },
"completion_worse.completor.type.enabled": { "completion_worse.completor.type.enabled": {
"default": true, "default": true,
@ -161,19 +177,28 @@
"default": true, "default": true,
"description": "Enable or disable the ``worse_parameter`` completor.\n\nCompletion for method or function parameters." "description": "Enable or disable the ``worse_parameter`` completor.\n\nCompletion for method or function parameters."
}, },
"completion_worse.debug": { "default": false, "description": "Include debug info in completion results" }, "completion_worse.debug": {
"completion_worse.experimantal": { "default": false, "description": "Enable experimental functionality" }, "default": false,
"description": "Include debug info in completion results"
},
"completion_worse.experimantal": {
"default": false,
"description": "Enable experimental functionality"
},
"completion_worse.name_completion_priority": { "completion_worse.name_completion_priority": {
"default": "proximity", "default": "proximity",
"description": "Strategy to use when ordering completion results for classes and functions:\n\n- `proximity`: Classes and functions will be ordered by their proximity to the text document being edited.\n- `none`: No ordering will be applied." "description": "Strategy to use when ordering completion results for classes and functions:\n\n- `proximity`: Classes and functions will be ordered by their proximity to the text document being edited.\n- `none`: No ordering will be applied."
}, },
"completion_worse.snippets": { "default": true, "description": "Enable or disable completion snippets" }, "completion_worse.snippets": {
"default": true,
"description": "Enable or disable completion snippets"
},
"composer.autoload_deregister": { "composer.autoload_deregister": {
"default": true, "default": true,
"description": "Immediately de-register the autoloader once it has been included (prevent conflicts with Phpactor's autoloader). Some platforms may require this to be disabled" "description": "Immediately de-register the autoloader once it has been included (prevent conflicts with Phpactor's autoloader). Some platforms may require this to be disabled"
}, },
"composer.autoloader_path": { "composer.autoloader_path": {
"default": "%project_root%\/vendor\/autoload.php", "default": "%project_root%/vendor/autoload.php",
"description": "Path to project's autoloader, can be an array" "description": "Path to project's autoloader, can be an array"
}, },
"composer.class_maps_only": { "composer.class_maps_only": {
@ -186,9 +211,23 @@
}, },
"console.decorated": { "console.decorated": {
"description": "Whether to decorate messages (null for auto-guessing)", "description": "Whether to decorate messages (null for auto-guessing)",
"enum": [true, false, null] "enum": [
true,
false,
null
]
},
"console.verbosity": {
"default": 32,
"description": "Verbosity level",
"enum": [
16,
32,
64,
128,
256
]
}, },
"console.verbosity": { "default": 32, "description": "Verbosity level", "enum": [16, 32, 64, 128, 256] },
"console_dumper_default": { "console_dumper_default": {
"default": "indented", "default": "indented",
"description": "Name of the \"dumper\" (renderer) to use for some CLI commands" "description": "Name of the \"dumper\" (renderer) to use for some CLI commands"
@ -197,75 +236,131 @@
"default": 1610612736, "default": 1610612736,
"description": "Ensure that PHP has a memory_limit of at least this amount in bytes" "description": "Ensure that PHP has a memory_limit of at least this amount in bytes"
}, },
"file_path_resolver.app_name": { "default": "phpactor", "description": null }, "file_path_resolver.app_name": {
"file_path_resolver.application_root": { "description": null }, "default": "phpactor",
"file_path_resolver.enable_cache": { "default": true, "description": null }, "description": null
"file_path_resolver.enable_logging": { "default": true, "description": null }, },
"file_path_resolver.project_root": { "default": "\/opt\/phpactor", "description": null }, "file_path_resolver.application_root": {
"description": null
},
"file_path_resolver.enable_cache": {
"default": true,
"description": null
},
"file_path_resolver.enable_logging": {
"default": true,
"description": null
},
"file_path_resolver.project_root": {
"default": "/opt/phpactor",
"description": null
},
"indexer.buffer_time": { "indexer.buffer_time": {
"default": 500, "default": 500,
"description": "For real-time indexers only: the time, in milliseconds, to buffer the results", "description": "For real-time indexers only: the time, in milliseconds, to buffer the results",
"type": ["integer"] "type": [
"integer"
]
}, },
"indexer.enabled_watchers": { "indexer.enabled_watchers": {
"default": ["inotify", "watchman", "find", "php"], "default": [
"find",
"inotify",
"php",
"watchman"
],
"description": "List of allowed watchers. The first watcher that supports the current system will be used", "description": "List of allowed watchers. The first watcher that supports the current system will be used",
"type": ["object"] "type": [
"object"
]
}, },
"indexer.exclude_patterns": { "indexer.exclude_patterns": {
"default": ["\/vendor\/**\/Tests\/**\/*", "\/vendor\/**\/tests\/**\/*", "\/vendor\/composer\/**\/*"], "default": [
"/vendor/**/tests/**/*",
"/vendor/**/Tests/**/*",
"/vendor/composer/**/*"
],
"description": "Glob patterns to exclude while indexing", "description": "Glob patterns to exclude while indexing",
"type": ["object"] "type": [
"object"
]
}, },
"indexer.follow_symlinks": { "indexer.follow_symlinks": {
"default": false, "default": false,
"description": "To allow indexer to follow symlinks", "description": "To allow indexer to follow symlinks",
"type": ["boolean"] "type": [
"boolean"
]
}, },
"indexer.implementation_finder.deep": { "indexer.implementation_finder.deep": {
"default": true, "default": true,
"description": "Recurse over class implementations to resolve all class implementations (not just the classes directly implementing the subject)", "description": "Recurse over class implementations to resolve all class implementations (not just the classes directly implementing the subject)",
"type": ["boolean"] "type": [
"boolean"
]
}, },
"indexer.include_patterns": { "indexer.include_patterns": {
"default": ["\/**\/*.php", "\/**\/*.phar"], "default": [
"/**/*.phar",
"/**/*.php"
],
"description": "Glob patterns to include while indexing", "description": "Glob patterns to include while indexing",
"type": ["object"] "type": [
"object"
]
}, },
"indexer.index_path": { "indexer.index_path": {
"default": "%cache%\/index\/%project_id%", "default": "%cache%/index/%project_id%",
"description": "Path where the index should be saved", "description": "Path where the index should be saved",
"type": ["string"] "type": [
"string"
]
}, },
"indexer.poll_time": { "indexer.poll_time": {
"default": 5000, "default": 5000,
"description": "For polling indexers only: the time, in milliseconds, between polls (e.g. filesystem scans)", "description": "For polling indexers only: the time, in milliseconds, between polls (e.g. filesystem scans)",
"type": ["integer"] "type": [
"integer"
]
}, },
"indexer.project_root": { "indexer.project_root": {
"default": "%project_root%", "default": "%project_root%",
"description": "The root path to use for scanning the index", "description": "The root path to use for scanning the index",
"type": ["string"] "type": [
"string"
]
}, },
"indexer.reference_finder.deep": { "indexer.reference_finder.deep": {
"default": true, "default": true,
"description": "Recurse over class implementations to resolve all references", "description": "Recurse over class implementations to resolve all references",
"type": ["boolean"] "type": [
"boolean"
]
}, },
"indexer.stub_paths": { "indexer.stub_paths": {
"default": [], "default": [],
"description": "Paths to external folders to index. They will be indexed only once, if you want to take any changes into account you will have to reindex your project manually.", "description": "Paths to external folders to index. They will be indexed only once, if you want to take any changes into account you will have to reindex your project manually.",
"type": ["object"] "type": [
"object"
]
}, },
"indexer.supported_extensions": { "indexer.supported_extensions": {
"default": ["php", "phar"], "default": [
"phar",
"php"
],
"description": "File extensions (e.g. `php`) for files that should be indexed", "description": "File extensions (e.g. `php`) for files that should be indexed",
"type": ["object"] "type": [
"object"
]
},
"language_server.catch_errors": {
"default": true,
"description": null
}, },
"language_server.catch_errors": { "default": true, "description": null },
"language_server.diagnostic_exclude_paths": { "language_server.diagnostic_exclude_paths": {
"default": [], "default": [],
"description": "List of paths to exclude from diagnostics, e.g. `vendor\/**\/*`" "description": "List of paths to exclude from diagnostics, e.g. `vendor/**/*`"
}, },
"language_server.diagnostic_outsource": { "language_server.diagnostic_outsource": {
"default": true, "default": true,
@ -296,19 +391,30 @@
}, },
"language_server.enable_workspace": { "language_server.enable_workspace": {
"default": true, "default": true,
"description": "If workspace management \/ text synchronization should be enabled (this isn't required for some language server implementations, e.g. static analyzers)" "description": "If workspace management / text synchronization should be enabled (this isn't required for some language server implementations, e.g. static analyzers)"
},
"language_server.file_event_globs": {
"default": [
"**/*.php"
],
"description": null
},
"language_server.file_events": {
"default": true,
"description": "Register to receive file events"
}, },
"language_server.file_event_globs": { "default": ["**\/*.php"], "description": null },
"language_server.file_events": { "default": true, "description": "Register to receive file events" },
"language_server.method_alias_map": { "language_server.method_alias_map": {
"default": [], "default": [],
"description": "Allow method names to be re-mapped. Useful for maintaining backwards compatibility" "description": "Allow method names to be re-mapped. Useful for maintaining backwards compatibility"
}, },
"language_server.phpactor_bin": { "language_server.phpactor_bin": {
"default": "\/opt\/phpactor\/lib\/Extension\/LanguageServer\/..\/..\/..\/bin\/phpactor", "default": "/opt/phpactor/lib/Extension/LanguageServer/../../../bin/phpactor",
"description": "Internal use only - name path to Phpactor binary" "description": "Internal use only - name path to Phpactor binary"
}, },
"language_server.profile": { "default": false, "description": "Logs timing information for incoming LSP requests" }, "language_server.profile": {
"default": false,
"description": "Logs timing information for incoming LSP requests"
},
"language_server.self_destruct_timeout": { "language_server.self_destruct_timeout": {
"default": 2500, "default": 2500,
"description": "Wait this amount of time (in milliseconds) after a shutdown request before self-destructing" "description": "Wait this amount of time (in milliseconds) after a shutdown request before self-destructing"
@ -340,22 +446,30 @@
"language_server_configuration.auto_config": { "language_server_configuration.auto_config": {
"default": true, "default": true,
"description": "Prompt to enable extensions which apply to your project on language server start", "description": "Prompt to enable extensions which apply to your project on language server start",
"type": ["boolean"] "type": [
"boolean"
]
}, },
"language_server_indexer.reindex_timeout": { "language_server_indexer.reindex_timeout": {
"default": 300, "default": 300,
"description": "Unconditionally reindex modified files every N seconds" "description": "Unconditionally reindex modified files every N seconds"
}, },
"language_server_indexer.workspace_symbol_search_limit": { "default": 250, "description": null }, "language_server_indexer.workspace_symbol_search_limit": {
"default": 250,
"description": null
},
"language_server_php_cs_fixer.bin": { "language_server_php_cs_fixer.bin": {
"default": "%project_root%\/vendor\/bin\/php-cs-fixer", "default": "%project_root%/vendor/bin/php-cs-fixer",
"description": "Path to the php-cs-fixer executable" "description": "Path to the php-cs-fixer executable"
}, },
"language_server_php_cs_fixer.config": { "language_server_php_cs_fixer.config": {
"description": "Set custom PHP CS config path. Ex., %project_root%\/.php-cs-fixer.php" "description": "Set custom PHP CS config path. Ex., %project_root%/.php-cs-fixer.php"
}, },
"language_server_php_cs_fixer.env": { "language_server_php_cs_fixer.env": {
"default": { "PHP_CS_FIXER_IGNORE_ENV": true, "XDEBUG_MODE": "off" }, "default": {
"PHP_CS_FIXER_IGNORE_ENV": true,
"XDEBUG_MODE": "off"
},
"description": "Environment for PHP CS Fixer (e.g. to set PHP_CS_FIXER_IGNORE_ENV)" "description": "Environment for PHP CS Fixer (e.g. to set PHP_CS_FIXER_IGNORE_ENV)"
}, },
"language_server_php_cs_fixer.show_diagnostics": { "language_server_php_cs_fixer.show_diagnostics": {
@ -363,16 +477,24 @@
"description": "Whether PHP CS Fixer diagnostics are shown" "description": "Whether PHP CS Fixer diagnostics are shown"
}, },
"language_server_phpstan.bin": { "language_server_phpstan.bin": {
"default": "%project_root%\/vendor\/bin\/phpstan", "default": "%project_root%/vendor/bin/phpstan",
"description": "Path to the PHPStan executable" "description": "Path to the PHPStan executable"
}, },
"language_server_phpstan.config": { "description": "Override the PHPStan configuration file" }, "language_server_phpstan.config": {
"language_server_phpstan.level": { "description": "Override the PHPStan level" }, "description": "Override the PHPStan configuration file"
"language_server_phpstan.mem_limit": { "description": "Override the PHPStan memory limit" }, },
"language_server_phpstan.level": {
"description": "Override the PHPStan level"
},
"language_server_phpstan.mem_limit": {
"description": "Override the PHPStan memory limit"
},
"language_server_psalm.bin": { "language_server_psalm.bin": {
"default": "%project_root%\/vendor\/bin\/psalm", "default": "%project_root%/vendor/bin/psalm",
"description": "Path to psalm if different from vendor\/bin\/psalm", "description": "Path to psalm if different from vendor/bin/psalm",
"type": ["string"] "type": [
"string"
]
}, },
"language_server_psalm.error_level": { "language_server_psalm.error_level": {
"description": "Override level at which Psalm should report errors (lower => more errors)" "description": "Override level at which Psalm should report errors (lower => more errors)"
@ -380,28 +502,39 @@
"language_server_psalm.show_info": { "language_server_psalm.show_info": {
"default": true, "default": true,
"description": "If infos from psalm should be displayed", "description": "If infos from psalm should be displayed",
"type": ["boolean"] "type": [
"boolean"
]
}, },
"language_server_psalm.threads": { "language_server_psalm.threads": {
"default": 1, "default": 1,
"description": "Set the number of threads Psalm should use. Warning: NULL will use as many as possible and may crash your computer", "description": "Set the number of threads Psalm should use. Warning: NULL will use as many as possible and may crash your computer",
"type": ["integer"] "type": [
"integer"
]
}, },
"language_server_psalm.timeout": { "language_server_psalm.timeout": {
"default": 15, "default": 15,
"description": "Kill the psalm process after this number of seconds", "description": "Kill the psalm process after this number of seconds",
"type": ["integer"] "type": [
"integer"
]
}, },
"language_server_psalm.use_cache": { "language_server_psalm.use_cache": {
"default": true, "default": true,
"description": "If the Psalm cache should be used (see the `--no-cache` option)", "description": "If the Psalm cache should be used (see the `--no-cache` option)",
"type": ["boolean"] "type": [
"boolean"
]
}, },
"language_server_reference_reference_finder.reference_timeout": { "language_server_reference_reference_finder.reference_timeout": {
"default": 60, "default": 60,
"description": "Stop searching for references after this time (in seconds) has expired" "description": "Stop searching for references after this time (in seconds) has expired"
}, },
"language_server_worse_reflection.diagnostics.enable": { "default": true, "description": "Enable diagnostics" }, "language_server_worse_reflection.diagnostics.enable": {
"default": true,
"description": "Enable diagnostics"
},
"language_server_worse_reflection.inlay_hints.enable": { "language_server_worse_reflection.inlay_hints.enable": {
"default": false, "default": false,
"description": "Enable inlay hints (experimental)" "description": "Enable inlay hints (experimental)"
@ -418,34 +551,87 @@
"default": 100, "default": 100,
"description": "Minimum interval to update the workspace index as documents are updated (in milliseconds)" "description": "Minimum interval to update the workspace index as documents are updated (in milliseconds)"
}, },
"logger.name": { "default": "logger", "description": null, "type": ["string"] }, "logger.name": {
"logging.enabled": { "default": false, "description": null, "type": ["boolean"] }, "default": "logger",
"logging.fingers_crossed": { "default": false, "description": null, "type": ["boolean"] }, "description": null,
"logging.formatter": { "description": null }, "type": [
"string"
]
},
"logging.enabled": {
"default": false,
"description": null,
"type": [
"boolean"
]
},
"logging.fingers_crossed": {
"default": false,
"description": null,
"type": [
"boolean"
]
},
"logging.formatter": {
"description": null
},
"logging.level": { "logging.level": {
"default": "warning", "default": "warning",
"description": null, "description": null,
"enum": ["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"], "enum": [
"type": ["string"] "alert",
"critical",
"debug",
"emergency",
"error",
"info",
"notice",
"warning"
],
"type": [
"string"
]
},
"logging.path": {
"default": "application.log",
"description": null,
"type": [
"string"
]
},
"navigator.autocreate": {
"default": [],
"description": null
},
"navigator.destinations": {
"default": [],
"description": null
}, },
"logging.path": { "default": "application.log", "description": null, "type": ["string"] },
"navigator.autocreate": { "default": [], "description": null },
"navigator.destinations": { "default": [], "description": null },
"object_renderer.template_paths.markdown": { "object_renderer.template_paths.markdown": {
"default": ["%project_config%\/templates\/markdown", "%config%\/templates\/markdown"], "default": [
"%config%/templates/markdown",
"%project_config%/templates/markdown"
],
"description": "Paths in which to look for templates for hover information." "description": "Paths in which to look for templates for hover information."
}, },
"php.version": { "php.version": {
"description": "Consider this value to be the project\\'s version of PHP (e.g. `7.4`). If omitted\nit will check `composer.json` (by the configured platform then the PHP requirement) before\nfalling back to the PHP version of the current process." "description": "Consider this value to be the project\\'s version of PHP (e.g. `7.4`). If omitted\nit will check `composer.json` (by the configured platform then the PHP requirement) before\nfalling back to the PHP version of the current process."
}, },
"php_code_sniffer.args": { "default": [], "description": "Additional arguments to pass to the PHPCS process" }, "php_code_sniffer.args": {
"default": [],
"description": "Additional arguments to pass to the PHPCS process"
},
"php_code_sniffer.bin": { "php_code_sniffer.bin": {
"default": "%project_root%\/vendor\/bin\/phpcs", "default": "%project_root%/vendor/bin/phpcs",
"description": "Path to the phpcs executable" "description": "Path to the phpcs executable"
}, },
"php_code_sniffer.cwd": { "description": "Working directory for PHPCS" }, "php_code_sniffer.cwd": {
"description": "Working directory for PHPCS"
},
"php_code_sniffer.env": { "php_code_sniffer.env": {
"default": { "XDEBUG_MODE": "off" }, "default": {
"XDEBUG_MODE": "off"
},
"description": "Environment for PHP_CodeSniffer (e.g. to set XDEBUG_MODE)" "description": "Environment for PHP_CodeSniffer (e.g. to set XDEBUG_MODE)"
}, },
"php_code_sniffer.show_diagnostics": { "php_code_sniffer.show_diagnostics": {
@ -456,15 +642,24 @@
"default": false, "default": false,
"description": "Only consider public services when providing analysis for the service locator" "description": "Only consider public services when providing analysis for the service locator"
}, },
"rpc.replay_path": { "default": "%cache%\/replay.json", "description": "Path where the replays should be stored" }, "rpc.replay_path": {
"rpc.store_replay": { "default": false, "description": "Should replays be stored?" }, "default": "%cache%/replay.json",
"source_code_filesystem.project_root": { "default": "%project_root%", "description": null }, "description": "Path where the replays should be stored"
},
"rpc.store_replay": {
"default": false,
"description": "Should replays be stored?"
},
"source_code_filesystem.project_root": {
"default": "%project_root%",
"description": null
},
"symfony.xml_path": { "symfony.xml_path": {
"default": "%project_root%\/var\/cache\/dev\/App_KernelDevDebugContainer.xml", "default": "%project_root%/var/cache/dev/App_KernelDevDebugContainer.xml",
"description": "Path to the Symfony container XML dump file" "description": "Path to the Symfony container XML dump file"
}, },
"worse_reflection.cache_dir": { "worse_reflection.cache_dir": {
"default": "%cache%\/worse-reflection", "default": "%cache%/worse-reflection",
"description": "Cache directory for stubs" "description": "Cache directory for stubs"
}, },
"worse_reflection.cache_lifetime": { "worse_reflection.cache_lifetime": {
@ -474,18 +669,26 @@
"worse_reflection.diagnostics.undefined_variable.suggestion_levenshtein_disatance": { "worse_reflection.diagnostics.undefined_variable.suggestion_levenshtein_disatance": {
"default": 4, "default": 4,
"description": "Levenshtein distance to use when suggesting corrections for variable names", "description": "Levenshtein distance to use when suggesting corrections for variable names",
"type": ["integer"] "type": [
"integer"
]
},
"worse_reflection.enable_cache": {
"default": true,
"description": "If reflection caching should be enabled"
}, },
"worse_reflection.enable_cache": { "default": true, "description": "If reflection caching should be enabled" },
"worse_reflection.enable_context_location": { "worse_reflection.enable_context_location": {
"default": true, "default": true,
"description": "If source code is passed to a ``Reflector`` then temporarily make it available as a\nsource location. Note this should NOT be enabled if the source code can be\nlocated in another (e.g. when running a Language Server)" "description": "If source code is passed to a ``Reflector`` then temporarily make it available as a\nsource location. Note this should NOT be enabled if the source code can be\nlocated in another (e.g. when running a Language Server)"
}, },
"worse_reflection.stub_dir": { "worse_reflection.stub_dir": {
"default": "%application_root%\/vendor\/jetbrains\/phpstorm-stubs", "default": "%application_root%/vendor/jetbrains/phpstorm-stubs",
"description": "Location of the core PHP stubs - these will be scanned and cached on the first request" "description": "Location of the core PHP stubs - these will be scanned and cached on the first request"
}, },
"xdebug_disable": { "default": true, "description": "If XDebug should be automatically disabled" } "xdebug_disable": {
"default": true,
"description": "If XDebug should be automatically disabled"
}
}, },
"title": "Phpactor Configuration Schema", "title": "Phpactor Configuration Schema",
"type": "object" "type": "object"

View file

@ -1,17 +1,18 @@
import { $ } from "bun"; import { $ } from "bun";
import { Array, Console, Effect, Layer, ManagedRuntime, Option, Order, pipe, Schema, ServiceMap } from "effect"; import type { Option } from "effect";
import { UnknownError } from "effect/Cause"; import { Array as FxArray, Console, Context, Effect, Layer, ManagedRuntime, Order, pipe, Schema } from "effect";
import type { UnknownError } from "effect/Cause";
import { readdir } from "node:fs/promises"; import { readdir } from "node:fs/promises";
class PodmanError extends Schema.TaggedErrorClass<PodmanError>()("PodmanError", { class PodmanError extends Schema.TaggedErrorClass<PodmanError>()("PodmanError", {
cause: Schema.Error, cause: Schema.Error,
}) {} }) {}
class FileSystemError extends Schema.TaggedErrorClass<FileSystemError>()("FileSystemError", { class FSError extends Schema.TaggedErrorClass<FSError>()("FSError", {
cause: Schema.Error, cause: Schema.Error,
}) {} }) {}
class Podman extends ServiceMap.Service< class Podman extends Context.Service<
Podman, Podman,
{ {
launchContainers(): Effect.Effect<string, PodmanError>; launchContainers(): Effect.Effect<string, PodmanError>;
@ -21,21 +22,21 @@ class Podman extends ServiceMap.Service<
static readonly layer = Layer.effect( static readonly layer = Layer.effect(
Podman, Podman,
// oxlint-disable-next-line require-yield // oxlint-disable-next-line require-yield
Effect.gen(function* () { Effect.gen(function*() {
const launchContainers = Effect.fn("launchContainers")(function* () { const launchContainers = Effect.fn("launchContainers")(function*() {
return yield* pipe( return yield* pipe(
Effect.tryPromise(() => $`podman compose up -d &> /dev/null`), Effect.tryPromise(async () => $`podman compose up -d &> /dev/null`),
Effect.map((shell: $.ShellOutput) => shell.text()), Effect.map((shell: $.ShellOutput) => shell.text()),
Effect.mapError((error: UnknownError) => new PodmanError({ cause: error })), Effect.mapError((error: UnknownError) => new PodmanError({ cause: error })),
); );
}); });
const importLatestDbInWordPressContainer = Effect.fn("importLatestDbInWordPressContainer")(function* ( const importLatestDbInWordPressContainer = Effect.fn("importLatestDbInWordPressContainer")(function*(
exportPath: string, exportPath: string,
) { ) {
return yield* pipe( return yield* pipe(
Effect.tryPromise( Effect.tryPromise(
() => async () =>
$`podman exec -it haikuatelier.fr-wordpress fish -c "cd web && wp --allow-root db import ${exportPath} > /dev/null"`, $`podman exec -it haikuatelier.fr-wordpress fish -c "cd web && wp --allow-root db import ${exportPath} > /dev/null"`,
), ),
Effect.map((shell: $.ShellOutput) => shell.text()), Effect.map((shell: $.ShellOutput) => shell.text()),
@ -51,47 +52,44 @@ class Podman extends ServiceMap.Service<
); );
} }
class FileSystem extends ServiceMap.Service< class FS extends Context.Service<
FileSystem, FS,
{ {
getLatestDbExport(): Effect.Effect<string, FileSystemError>; getLatestDbExport(): Effect.Effect<string, FSError>;
} }
>()("haikuatelier.fr/scripts/importe-dernier-export-bdd/FileSystem") { >()("haikuatelier.fr/scripts/importe-dernier-export-bdd/FS") {
static readonly layer = Layer.effect( static readonly layer = Layer.effect(
FileSystem, FS,
// oxlint-disable-next-line require-yield // oxlint-disable-next-line require-yield
Effect.gen(function* () { Effect.gen(function*() {
const getLatestDbExport = Effect.fn("getLatestDbExport")(function* () { const getLatestDbExport = Effect.fn("getLatestDbExport")(function*() {
return yield* pipe( return yield* pipe(
Effect.tryPromise(() => readdir(`./db`)), Effect.tryPromise(async () => readdir(`./db`)),
Effect.map((paths: ReadonlyArray<string>) => Array.sort(paths, Order.String)), Effect.map((paths: ReadonlyArray<string>) => FxArray.sort(paths, Order.String)),
Effect.map((sortedPaths: ReadonlyArray<string>) => Array.last(sortedPaths)), Effect.map((sortedPaths: ReadonlyArray<string>) => FxArray.last(sortedPaths)),
Effect.flatMap((path: Option.Option<string>) => Effect.fromOption(path)), Effect.flatMap((path: Option.Option<string>) => Effect.fromOption(path)),
Effect.mapError((_) => new FileSystemError({ cause: new Error("Aucun export de BDD n'est disponible.") })), Effect.mapError(_ => new FSError({ cause: new Error("Aucun export de BDD n'est disponible.") })),
); );
}); });
return FileSystem.of({ return FS.of({
getLatestDbExport, getLatestDbExport,
}); });
}), }),
); );
} }
const mainLayer = Layer.mergeAll(Podman.layer, FileSystem.layer); const mainLayer = Layer.mergeAll(Podman.layer, FS.layer);
const runtime = ManagedRuntime.make(mainLayer); const runtime = ManagedRuntime.make(mainLayer);
const program = Effect.fn("program")(function* () { const program = Effect.fn("program")(function*() {
yield* Podman.use((podman) => podman.launchContainers()); yield* Podman.use(podman => podman.launchContainers());
yield* Console.log("Containers are launched."); yield* Console.log("Containers are launched.");
const latestExportPath: string = pipe( const latestExportPath: string = pipe(yield* FS.use(fs => fs.getLatestDbExport()), path => `../db/${path}`);
yield* FileSystem.use((fs) => fs.getLatestDbExport()),
(path) => `../db/${path}`,
);
yield* Console.log(latestExportPath); yield* Console.log(latestExportPath);
yield* Podman.use((podman) => podman.importLatestDbInWordPressContainer(latestExportPath)); yield* Podman.use(podman => podman.importLatestDbInWordPressContainer(latestExportPath));
yield* Console.log("Import done."); yield* Console.log("Import done.");
}); });

View file

@ -1,5 +1,5 @@
import { YAML } from "bun"; import { YAML } from "bun";
import { Console, Data, Effect, Array as EffectArray, pipe, Record, Schema, SchemaIssue } from "effect"; import { Array as EffectArray, Console, Data, Effect, pipe, Record, Schema, SchemaIssue } from "effect";
import { SchemaError } from "effect/Schema"; import { SchemaError } from "effect/Schema";
const COMPOSE_PATH = "compose.yaml"; const COMPOSE_PATH = "compose.yaml";
@ -21,7 +21,7 @@ class ScriptError extends Data.TaggedError("ScriptError")<{ cause: unknown }> {}
* @param compose Le fichier _Compose_ sous forme d'objet. * @param compose Le fichier _Compose_ sous forme d'objet.
* @returns Les noms des Services sous forme de tableau. * @returns Les noms des Services sous forme de tableau.
*/ */
const getServicesFromComposeYaml: (compose: Compose) => ReadonlyArray<string> = (compose) => const getServicesFromComposeYaml: (compose: Compose) => ReadonlyArray<string> = compose =>
Record.keys(compose.services); Record.keys(compose.services);
/** /**
@ -31,7 +31,7 @@ const getServicesFromComposeYaml: (compose: Compose) => ReadonlyArray<string> =
* @returns Le contenu textuel du fichier sous forme de chaîne de caractères. * @returns Le contenu textuel du fichier sous forme de chaîne de caractères.
*/ */
const getFileContent: (filePath: string) => Effect.Effect<string, ScriptError> = Effect.fn("getFileContent")( const getFileContent: (filePath: string) => Effect.Effect<string, ScriptError> = Effect.fn("getFileContent")(
function* (filePath) { function*(filePath) {
const fileRef: Bun.BunFile = Bun.file(filePath); const fileRef: Bun.BunFile = Bun.file(filePath);
yield* Effect.tryPromise({ yield* Effect.tryPromise({
@ -56,12 +56,12 @@ const getFileContent: (filePath: string) => Effect.Effect<string, ScriptError> =
const getComposeYaml: <ComposeSchema>( const getComposeYaml: <ComposeSchema>(
path: string, path: string,
schema: Schema.Schema<ComposeSchema>, schema: Schema.Schema<ComposeSchema>,
) => Effect.Effect<ComposeSchema, ScriptError, unknown> = Effect.fn("getComposeYaml")(function* (path, schema) { ) => Effect.Effect<ComposeSchema, ScriptError, unknown> = Effect.fn("getComposeYaml")(function*(path, schema) {
return yield* pipe( return yield* pipe(
getFileContent(path), getFileContent(path),
Effect.map((text: string): unknown => YAML.parse(text)), Effect.map((text: string): unknown => YAML.parse(text)),
Effect.flatMap((yaml: unknown) => Effect.flatMap((yaml: unknown) =>
Schema.decodeUnknownEffect(schema)(yaml, { errors: "all", onExcessProperty: "ignore" }), Schema.decodeUnknownEffect(schema)(yaml, { errors: "all", onExcessProperty: "ignore" })
), ),
Effect.mapError((error): ScriptError => { Effect.mapError((error): ScriptError => {
if (error instanceof SchemaError) { if (error instanceof SchemaError) {
@ -76,7 +76,7 @@ const getComposeYaml: <ComposeSchema>(
const program: Effect.Effect<ReadonlyArray<string>, ScriptError> = pipe( const program: Effect.Effect<ReadonlyArray<string>, ScriptError> = pipe(
getComposeYaml(COMPOSE_PATH, Compose), getComposeYaml(COMPOSE_PATH, Compose),
Effect.map((compose: Compose) => getServicesFromComposeYaml(compose)), Effect.map((compose: Compose) => getServicesFromComposeYaml(compose)),
Effect.map((keys: ReadonlyArray<string>) => EffectArray.filter(keys, (key) => key !== "wordpress")), Effect.map((keys: ReadonlyArray<string>) => EffectArray.filter(keys, key => key !== "wordpress")),
Effect.orElseSucceed(() => [""]), Effect.orElseSucceed(() => [""]),
Effect.tap((services: ReadonlyArray<string>) => { Effect.tap((services: ReadonlyArray<string>) => {
Bun.spawn({ cmd: ["podman", "compose", "pull", ...services], timeout: DEFAULT_CMD_TIMEOUT }); Bun.spawn({ cmd: ["podman", "compose", "pull", ...services], timeout: DEFAULT_CMD_TIMEOUT });

View file

@ -14,32 +14,32 @@ global $wpdb;
$wp_postmeta = "{$wpdb->prefix}postmeta"; $wp_postmeta = "{$wpdb->prefix}postmeta";
try { try {
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Error Handling // Error Handling
$sql = "UPDATE {$wp_postmeta} SET meta_value = REPLACE(meta_value,'-scaled.jpg','.jpg') WHERE meta_key='_wp_attached_file' AND meta_value LIKE '%-scaled.jpg%'"; $sql = "UPDATE {$wp_postmeta} SET meta_value = REPLACE(meta_value,'-scaled.jpg','.jpg') WHERE meta_key='_wp_attached_file' AND meta_value LIKE '%-scaled.jpg%'";
$result = $pdo->exec($sql); $result = $pdo->exec($sql);
print_r($result); print_r($result);
} catch (PDOException $e) { } catch (PDOException $e) {
print_r($e->getMessage()); print_r($e->getMessage());
} }
// replace _wp_attachment_metadata meta_key. // replace _wp_attachment_metadata meta_key.
$image_metas = []; $image_metas = [];
try { try {
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Error Handling // Error Handling
$sql = "SELECT * FROM {$wp_postmeta} WHERE meta_value LIKE '%-scaled.jpg%' AND meta_key='_wp_attachment_metadata'"; $sql = "SELECT * FROM {$wp_postmeta} WHERE meta_value LIKE '%-scaled.jpg%' AND meta_key='_wp_attachment_metadata'";
$statement = $pdo->query($sql); $statement = $pdo->query($sql);
$image_metas = $statement->fetchAll(); $image_metas = $statement->fetchAll();
foreach ($image_metas as $meta) { foreach ($image_metas as $meta) {
$meta_value = unserialize($meta['meta_value']); $meta_value = unserialize($meta['meta_value']);
$file = $meta_value['file']; $file = $meta_value['file'];
$meta_value['file'] = str_replace('-scaled.jpg', '.jpg', $file); $meta_value['file'] = str_replace('-scaled.jpg', '.jpg', $file);
update_post_meta($meta['post_id'], $meta['meta_key'], $meta_value); update_post_meta($meta['post_id'], $meta['meta_key'], $meta_value);
$result = get_post_meta($meta['post_id'], $meta['meta_key']); $result = get_post_meta($meta['post_id'], $meta['meta_key']);
print_r($result); print_r($result);
} }
} catch (PDOException $e) { } catch (PDOException $e) {
print_r($e->getMessage()); print_r($e->getMessage());
} }

View file

@ -37,7 +37,7 @@ Array.from<TestPage>([
}, },
]).forEach(({ pageName, url }) => { ]).forEach(({ pageName, url }) => {
test.skip(pageName, async ({ page }, testInfo) => { test.skip(pageName, async ({ page }, testInfo) => {
await page.goto(url); await page["goto"](url);
const projectName = testInfo.project.name; const projectName = testInfo.project.name;
const timestamp: string = genTimestamp(); const timestamp: string = genTimestamp();

View file

@ -1,11 +1,13 @@
import { test as base, expect, Response } from "@playwright/test"; import type { Response } from "@playwright/test";
import { import { expect, test as base } from "@playwright/test";
import { pipe } from "effect";
import { not } from "effect/Boolean";
import type {
WCV3Product, WCV3Product,
WCV3Products, WCV3Products,
} from "../../web/app/themes/haiku-atelier-2024/src/scripts/lib/types/api/v3/products"; } from "../../web/app/themes/haiku-atelier-2024/src/scripts/lib/types/api/v3/products";
import { BackendHeaders, getBackendHeadersFromHtml } from "./utils.ts"; import type { BackendHeaders } from "./utils.ts";
import { pipe } from "effect"; import { getBackendHeadersFromHtml } from "./utils.ts";
import { not } from "effect/Boolean";
/* /*
* Faire un premier test simple l'on clic sur la première carte du shop * Faire un premier test simple l'on clic sur la première carte du shop
@ -30,7 +32,7 @@ type ProductsKinds = {
export const test = base.extend<ProductsFixture>({ export const test = base.extend<ProductsFixture>({
products: async ({ page, request }, use) => { products: async ({ page, request }, use) => {
await page.goto("/shop"); await page["goto"]("/shop");
const backendHeaders: BackendHeaders = await getBackendHeadersFromHtml(page); const backendHeaders: BackendHeaders = await getBackendHeadersFromHtml(page);
const response = await request.get("/wp-json/wc/v3/products?page=1&per_page=100&status=publish", { const response = await request.get("/wp-json/wc/v3/products?page=1&per_page=100&status=publish", {
@ -68,7 +70,7 @@ test("can add a Product without variation with stock to the Cart", async ({ page
} }
// Va à la page du Produit. // Va à la page du Produit.
await page.goto(randomProduct.permalink); await page["goto"](randomProduct.permalink);
// Vérifie le bon état du bouton de l'ajout au Panier. // Vérifie le bon état du bouton de l'ajout au Panier.
const addToCartButton = page.getByRole("button", { disabled: false, name: "Add to cart" }); const addToCartButton = page.getByRole("button", { disabled: false, name: "Add to cart" });
@ -101,7 +103,7 @@ test("can't add a Product without variation without stock to the Cart", async ({
} }
// Va à la page du Produit. // Va à la page du Produit.
await page.goto(randomProduct.permalink); await page["goto"](randomProduct.permalink);
// Vérifie le bon état du bouton de l'ajout au Panier. // Vérifie le bon état du bouton de l'ajout au Panier.
const outOfStockButton = page.getByRole("button", { disabled: true, name: "Out of stock" }); const outOfStockButton = page.getByRole("button", { disabled: true, name: "Out of stock" });

View file

@ -1,6 +1,8 @@
import { APIRequestContext, expect, Locator, Page, Response, test } from "@playwright/test"; import type { APIRequestContext, Locator, Page, Response } from "@playwright/test";
import { WCV3Products } from "../../web/app/themes/haiku-atelier-2024/src/scripts/lib/types/api/v3/products"; import { expect, test } from "@playwright/test";
import { BackendHeaders, getBackendHeadersFromHtml } from "./utils.ts"; import type { WCV3Products } from "../../web/app/themes/haiku-atelier-2024/src/scripts/lib/types/api/v3/products";
import type { BackendHeaders } from "./utils.ts";
import { getBackendHeadersFromHtml } from "./utils.ts";
test.describe.configure({ mode: "parallel", timeout: 60_000 }); test.describe.configure({ mode: "parallel", timeout: 60_000 });
@ -9,13 +11,13 @@ test("can scroll to the end of the grid", async ({ page }): Promise<void> => {
}); });
test.skip("can access all Products' pages", async ({ page, request }): Promise<void> => { test.skip("can access all Products' pages", async ({ page, request }): Promise<void> => {
await page.goto("https://haikuatelier.gcch.local/shop/"); await page["goto"]("https://haikuatelier.gcch.local/shop/");
const links = await getAllProductsLinks(page, request); const links = await getAllProductsLinks(page, request);
for (const link of links) { for (const link of links) {
// Vérifie que le lien de la page retourne OK. // Vérifie que le lien de la page retourne OK.
const req = await request.get(link as string); const req = await request.get(link);
expect(req, "The Product's page is accessible").toBeOK(); await expect(req, "The Product's page is accessible").toBeOK();
} }
}); });
@ -25,11 +27,11 @@ const getAllProductsLinks = async (page: Page, request: APIRequestContext): Prom
headers: { Authorization: `Basic ${backendHeaders.authString}`, Nonce: backendHeaders.nonce }, headers: { Authorization: `Basic ${backendHeaders.authString}`, Nonce: backendHeaders.nonce },
}); });
const json = (await response.json()) as WCV3Products; const json = (await response.json()) as WCV3Products;
return json.map((p) => p.permalink); return json.map(p => p.permalink);
}; };
const scrollToGridsEnd = async (page: Page): Promise<void> => { const scrollToGridsEnd = async (page: Page): Promise<void> => {
await page.goto("https://haikuatelier.gcch.local/shop/"); await page["goto"]("https://haikuatelier.gcch.local/shop/");
let hasMoreProducts = true; let hasMoreProducts = true;
let currentPageNumber = "1"; let currentPageNumber = "1";

View file

@ -1,5 +1,5 @@
import { Option, pipe } from "effect"; import { Option, pipe } from "effect";
import { Page } from "playwright/test"; import type { Page } from "playwright/test";
export type BackendHeaders = { export type BackendHeaders = {
authString: string; authString: string;
@ -12,7 +12,7 @@ export type BackendHeaders = {
export const getBackendHeadersFromHtml = async (page: Page): Promise<BackendHeaders> => { export const getBackendHeadersFromHtml = async (page: Page): Promise<BackendHeaders> => {
const backendHeaders: BackendHeaders | undefined = pipe( const backendHeaders: BackendHeaders | undefined = pipe(
Option.fromNullishOr(await page.locator("#injection-v2").textContent()), Option.fromNullishOr(await page.locator("#injection-v2").textContent()),
Option.andThen((j) => JSON.parse(j) as BackendHeaders), Option.andThen(j => JSON.parse(j) as BackendHeaders),
Option.getOrUndefined, Option.getOrUndefined,
); );

View file

@ -12,7 +12,12 @@
"exactOptionalPropertyTypes": true, "exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"isolatedModules": true, "isolatedModules": true,
"lib": ["DOM", "DOM.Iterable", "DOM.AsyncIterable", "ESNext"], "lib": [
"DOM",
"DOM.AsyncIterable",
"DOM.Iterable",
"ESNext"
],
"libReplacement": true, "libReplacement": true,
"module": "ESNext", "module": "ESNext",
"moduleDetection": "force", "moduleDetection": "force",
@ -41,10 +46,20 @@
"strictNullChecks": true, "strictNullChecks": true,
"strictPropertyInitialization": true, "strictPropertyInitialization": true,
"target": "ESNext", "target": "ESNext",
"types": ["node", "vite/client"], "types": [
"node",
"vite/client"
],
"useDefineForClassFields": true, "useDefineForClassFields": true,
"useUnknownInCatchVariables": true "useUnknownInCatchVariables": true
}, },
"exclude": ["vendor", "web/app/plugins", "web/wp"], "exclude": [
"include": ["**/*.js", "**/*.ts"] "vendor",
"web/app/plugins",
"web/wp"
],
"include": [
"**/*.js",
"**/*.ts"
]
} }

View file

@ -22,11 +22,12 @@ $templates = ['404.twig'];
* *
* @throws Exception une exception est levée s'il est impossible d'obtenir la date de modification du fichier à charger * @throws Exception une exception est levée s'il est impossible d'obtenir la date de modification du fichier à charger
*/ */
function load_page_resources(): void { function load_page_resources(): void
Resource::enqueue_style_file( {
handle: 'haiku-atelier-2024-styles-page-a-propos', Resource::enqueue_style_file(
path: '/assets/css/pages/page-modele-simple.css', handle: 'haiku-atelier-2024-styles-page-a-propos',
); path: '/assets/css/pages/page-modele-simple.css',
);
} }
add_action('wp_enqueue_scripts', load_page_resources(...)); add_action('wp_enqueue_scripts', load_page_resources(...));

View file

@ -1,4 +1,4 @@
jQuery(document).ready(function ($) { jQuery(document).ready(function($) {
"use strict"; "use strict";
/** /**
@ -9,7 +9,7 @@ jQuery(document).ready(function ($) {
* @link https://github.com/maddisondesigns * @link https://github.com/maddisondesigns
*/ */
$(".customize-control-tinymce-editor").each(function () { $(".customize-control-tinymce-editor").each(function() {
// Get the toolbar strings that were passed from the PHP Class // Get the toolbar strings that were passed from the PHP Class
const tinyMCEToolbar1String = _wpCustomizeSettings.controls[$(this).attr("id")].skyrockettinymcetoolbar1; const tinyMCEToolbar1String = _wpCustomizeSettings.controls[$(this).attr("id")].skyrockettinymcetoolbar1;
const tinyMCEToolbar2String = _wpCustomizeSettings.controls[$(this).attr("id")].skyrockettinymcetoolbar2; const tinyMCEToolbar2String = _wpCustomizeSettings.controls[$(this).attr("id")].skyrockettinymcetoolbar2;
@ -19,14 +19,14 @@ jQuery(document).ready(function ($) {
mediaButtons: tinyMCEMediaButtons, mediaButtons: tinyMCEMediaButtons,
quicktags: true, quicktags: true,
tinymce: { tinymce: {
wpautop: true,
toolbar1: tinyMCEToolbar1String, toolbar1: tinyMCEToolbar1String,
toolbar2: tinyMCEToolbar2String, toolbar2: tinyMCEToolbar2String,
wpautop: true,
}, },
}); });
}); });
$(document).on("tinymce-editor-init", function (event, editor) { $(document).on("tinymce-editor-init", function(event, editor) {
editor.on("change", function (e) { editor.on("change", function(e) {
tinyMCE.triggerSave(); tinyMCE.triggerSave();
$("#" + editor.id).trigger("change"); $("#" + editor.id).trigger("change");
}); });

View file

@ -17,14 +17,14 @@ $context = Timber::context();
$templates = ['accueil.twig']; $templates = ['accueil.twig'];
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: 'haiku-atelier-2024-styles-page-accueil', handle: 'haiku-atelier-2024-styles-page-accueil',
path: '/assets/css/pages/page-accueil.css', path: '/assets/css/pages/page-accueil.css',
); );
Resource::enqueue_script_module_file( Resource::enqueue_script_module_file(
id: 'haiku-atelier-2024-scripts-page-accueil', id: 'haiku-atelier-2024-scripts-page-accueil',
path: '/assets/js/scripts-page-accueil.js', path: '/assets/js/scripts-page-accueil.js',
); );
}); });
Timber::render(data: $context, filenames: $templates); Timber::render(data: $context, filenames: $templates);

View file

@ -24,20 +24,20 @@ $templates = ['a-propos.twig'];
$image_dimensions = getimagesize(filename: get_template_directory() . '/assets/img/about/haikuabout.png'); $image_dimensions = getimagesize(filename: get_template_directory() . '/assets/img/about/haikuabout.png');
if (is_bool($image_dimensions)) { if (is_bool($image_dimensions)) {
throw new Exception("Impossible d'obtenir les dimensions de l'image principale de la page."); throw new Exception("Impossible d'obtenir les dimensions de l'image principale de la page.");
} }
$context['image_dimensions'] = $image_dimensions; $context['image_dimensions'] = $image_dimensions;
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: 'haiku-atelier-2024-styles-page-a-propos', handle: 'haiku-atelier-2024-styles-page-a-propos',
path: '/assets/css/pages/page-a-propos.css', path: '/assets/css/pages/page-a-propos.css',
); );
Resource::enqueue_script_module_file( Resource::enqueue_script_module_file(
id: 'haiku-atelier-2024-scripts-page-a-propos', id: 'haiku-atelier-2024-scripts-page-a-propos',
path: '/assets/js/scripts-page-a-propos.js', path: '/assets/js/scripts-page-a-propos.js',
); );
}); });
Timber::render(data: $context, filenames: $templates); Timber::render(data: $context, filenames: $templates);

View file

@ -22,20 +22,22 @@ use WC_Session_Handler;
header('Content-Type: application/json; charset=utf-8'); header('Content-Type: application/json; charset=utf-8');
// TODO: Appliquer le bon calcul pour les montants vs. percentages // TODO: Appliquer le bon calcul pour les montants vs. percentages
function get_discount_amount(WC_Coupon $coupon) { function get_discount_amount(WC_Coupon $coupon)
if ($coupon->get_discount_type() === 'fixed_cart') { {
return $coupon->get_amount() * 100; if ($coupon->get_discount_type() === 'fixed_cart') {
} else { return $coupon->get_amount() * 100;
return $coupon->get_amount(); } else {
} return $coupon->get_amount();
}
} }
function get_discount_duration(WC_Coupon $coupon): string { function get_discount_duration(WC_Coupon $coupon): string
if ($coupon->get_discount_type() === 'fixed_cart') { {
return 'once'; if ($coupon->get_discount_type() === 'fixed_cart') {
} else { return 'once';
return 'forever'; } else {
} return 'forever';
}
} }
// Récupère les informations nécessaires // Récupère les informations nécessaires
@ -44,37 +46,37 @@ $session_wc = WC()->session;
/** @var array<string,string> $urls URLs utilisables pour rediriger l'Utilisateur. */ /** @var array<string,string> $urls URLs utilisables pour rediriger l'Utilisateur. */
$urls = [ $urls = [
'accueil' => get_page_link(get_page_by_path('home')), 'accueil' => get_page_link(get_page_by_path('home')),
'succes_commande' => get_page_link(get_page_by_path('successful-order')), 'succes_commande' => get_page_link(get_page_by_path('successful-order')),
'echec_commande' => get_page_link(get_page_by_path('failed-order')), 'echec_commande' => get_page_link(get_page_by_path('failed-order')),
]; ];
// Redirige à la page d'accueil si le Panier est vide // Redirige à la page d'accueil si le Panier est vide
if (WC()->cart->is_empty()) { if (WC()->cart->is_empty()) {
header('Location: ' . $urls['accueil']); header('Location: ' . $urls['accueil']);
return; return;
} }
// Vérifie que les paramètres d'URLs nécessaires soient présents // Vérifie que les paramètres d'URLs nécessaires soient présents
/** @var string $order_id */ /** @var string $order_id */
$order_id = $_GET['order_id']; $order_id = $_GET['order_id'];
if (!$order_id) { if (!$order_id) {
$reponse = ['succes' => false, 'status' => 'order_key is missing']; $reponse = ['succes' => false, 'status' => 'order_key is missing'];
echo json_encode($reponse); echo json_encode($reponse);
http_response_code(400); http_response_code(400);
return; return;
} }
/** @var string $order_key */ /** @var string $order_key */
$order_key = $_GET['order_key']; $order_key = $_GET['order_key'];
if (!$order_key) { if (!$order_key) {
$reponse = ['succes' => false, 'status' => 'order_key is missing']; $reponse = ['succes' => false, 'status' => 'order_key is missing'];
echo json_encode($reponse); echo json_encode($reponse);
http_response_code(400); http_response_code(400);
return; return;
} }
// Récupère le Panier et l'Email du Client // Récupère le Panier et l'Email du Client
@ -86,29 +88,29 @@ $email_client = WC()->session->get('customer')['email'];
/** @var list<Product> $articles */ /** @var list<Product> $articles */
$articles = collect($panier->get_cart()) $articles = collect($panier->get_cart())
->map(static function ($article_panier) { ->map(static function ($article_panier) {
$titre_produit = match ('variable' === $article_panier['data']?->get_type()) { $titre_produit = match ('variable' === $article_panier['data']?->get_type()) {
true => $article_panier['data']?->get_title() true => $article_panier['data']?->get_title()
. ' (' . ' ('
. explode(': ', (string) $article_panier['data']?->get_attribute_summary())[1] . explode(': ', (string) $article_panier['data']?->get_attribute_summary())[1]
. ')', . ')',
false => $article_panier['data']?->get_title(), false => $article_panier['data']?->get_title(),
}; };
return [ return [
'price_data' => [ 'price_data' => [
'currency' => 'EUR', 'currency' => 'EUR',
'product_data' => [ 'product_data' => [
'name' => $titre_produit, 'name' => $titre_produit,
'images' => [wp_get_attachment_image_url($article_panier['data']?->get_image_id())], 'images' => [wp_get_attachment_image_url($article_panier['data']?->get_image_id())],
], ],
'unit_amount' => $article_panier['data']?->get_price() * 100, 'unit_amount' => $article_panier['data']?->get_price() * 100,
], ],
'quantity' => $article_panier['quantity'], 'quantity' => $article_panier['quantity'],
]; ];
}) })
->values() ->values()
->toArray(); ->toArray();
// Récupère la Commande et la Méthode de Livraison // Récupère la Commande et la Méthode de Livraison
/** @var WC_Order $commande */ /** @var WC_Order $commande */
@ -118,7 +120,7 @@ $methode_livraison = ['nom' => $commande->get_shipping_method(), 'cout' => $comm
// Le nom de la méthode de livraison ne peut être une chaîne vide. // Le nom de la méthode de livraison ne peut être une chaîne vide.
if (empty($methode_livraison['nom'])) { if (empty($methode_livraison['nom'])) {
$methode_livraison['nom'] = 'Free'; $methode_livraison['nom'] = 'Free';
} }
// Sélectionne la clé API Stripe // Sélectionne la clé API Stripe
@ -127,39 +129,39 @@ Stripe::setApiKey(Config::get('STRIPE_API_SECRET'));
// Met à jour les Codes promos // Met à jour les Codes promos
$coupons_stripe = collect(Coupon::all()->data); $coupons_stripe = collect(Coupon::all()->data);
$coupons_wc = collect(WC()->cart->get_coupons()) $coupons_wc = collect(WC()->cart->get_coupons())
->map(static fn(WC_Coupon $coupon): array => [ ->map(static fn(WC_Coupon $coupon): array => [
'currency' => 'EUR', 'currency' => 'EUR',
'duration' => get_discount_duration($coupon), 'duration' => get_discount_duration($coupon),
'fixed_cart' === $coupon->get_discount_type() ? 'amount_off' : 'percent_off' => get_discount_amount($coupon), 'fixed_cart' === $coupon->get_discount_type() ? 'amount_off' : 'percent_off' => get_discount_amount($coupon),
'id' => $coupon->get_code(), 'id' => $coupon->get_code(),
'name' => $coupon->get_code(), 'name' => $coupon->get_code(),
]) ])
->each(static function (array $item) use ($coupons_stripe): void { ->each(static function (array $item) use ($coupons_stripe): void {
// Si le code promo n'existe pas, le créer // Si le code promo n'existe pas, le créer
if (!$coupons_stripe->contains('name', $item['name'])) { if (!$coupons_stripe->contains('name', $item['name'])) {
Coupon::create($item); Coupon::create($item);
} }
}); });
$reductions_stripe = $coupons_wc $reductions_stripe = $coupons_wc
->map(static fn($coupon): array => ['coupon' => $coupon['name']]) ->map(static fn($coupon): array => ['coupon' => $coupon['name']])
->values() ->values()
->toArray(); ->toArray();
/** @var Session $session_checkout_stripe */ /** @var Session $session_checkout_stripe */
$session_checkout_stripe = Session::create([ $session_checkout_stripe = Session::create([
'cancel_url' => $urls['echec_commande'], 'cancel_url' => $urls['echec_commande'],
'customer_email' => $email_client, 'customer_email' => $email_client,
'discounts' => $reductions_stripe, 'discounts' => $reductions_stripe,
'line_items' => $articles, 'line_items' => $articles,
'mode' => 'payment', 'mode' => 'payment',
'success_url' => $urls['succes_commande'] . '?session_id={CHECKOUT_SESSION_ID}', 'success_url' => $urls['succes_commande'] . '?session_id={CHECKOUT_SESSION_ID}',
'metadata' => ['order_id' => $order_id, 'order_key' => $order_key], 'metadata' => ['order_id' => $order_id, 'order_key' => $order_key],
'shipping_options' => [['shipping_rate_data' => [ 'shipping_options' => [['shipping_rate_data' => [
'display_name' => $methode_livraison['nom'], 'display_name' => $methode_livraison['nom'],
'fixed_amount' => ['amount' => $methode_livraison['cout'], 'currency' => 'EUR'], 'fixed_amount' => ['amount' => $methode_livraison['cout'], 'currency' => 'EUR'],
'tax_behavior' => 'inclusive', 'tax_behavior' => 'inclusive',
'type' => 'fixed_amount', 'type' => 'fixed_amount',
]]], ]]],
], ['idempotency_key' => Uuid::v4()]); ], ['idempotency_key' => Uuid::v4()]);
// echo json_encode($session_checkout_stripe); // echo json_encode($session_checkout_stripe);
header('HTTP/1.1 303 See Other'); header('HTTP/1.1 303 See Other');

View file

@ -17,10 +17,10 @@ $context = Timber::context();
$templates = ['echec-commande.twig']; $templates = ['echec-commande.twig'];
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: 'haiku-atelier-2024-styles-page-modele-simple', handle: 'haiku-atelier-2024-styles-page-modele-simple',
path: '/assets/css/pages/page-modele-simple.css', path: '/assets/css/pages/page-modele-simple.css',
); );
}); });
// Rendu // Rendu

View file

@ -17,10 +17,10 @@ $context = Timber::context();
$templates = ['cgv.twig']; $templates = ['cgv.twig'];
add_action('wp_enqueue_scripts', function (): void { add_action('wp_enqueue_scripts', function (): void {
Resource::enqueue_style_file( Resource::enqueue_style_file(
handle: '/assets/css/pages/page-modele-simple.css', handle: '/assets/css/pages/page-modele-simple.css',
path: '/assets/css/pages/page-modele-simple.css', path: '/assets/css/pages/page-modele-simple.css',
); );
}); });
// Rendu // Rendu

View file

@ -45,6 +45,7 @@ $maximum_price = collect($product->variations)->max('price');
$same_collection_products = Product::get_same_collection_products($product->collection)($product->id) $same_collection_products = Product::get_same_collection_products($product->collection)($product->id)
|> function (/** @var list<WC_Product>|stdClass */ mixed $products): array { |> function (/** @var list<WC_Product>|stdClass */ mixed $products): array {
assert(is_array($products), 'Les Produits de la même collection doivent être un tableau.'); assert(is_array($products), 'Les Produits de la même collection doivent être un tableau.');
return $products; return $products;
} }
|> (static fn(/** @var list<WC_Product> */ array $products): array => Arr::map( |> (static fn(/** @var list<WC_Product> */ array $products): array => Arr::map(

View file

@ -170,6 +170,7 @@ final class StarterSite extends Site {
public function maj_environnement_twig(array $options): array { public function maj_environnement_twig(array $options): array {
return $options; return $options;
} }
// public function charge_traductions_theme(): void { // public function charge_traductions_theme(): void {
// load_theme_textdomain("haiku-atelier-2024", get_template_directory() . "/languages"); // load_theme_textdomain("haiku-atelier-2024", get_template_directory() . "/languages");
// } // }

View file

@ -9,36 +9,39 @@ declare(strict_types=1);
use Carbon_Fields\Container; use Carbon_Fields\Container;
use Carbon_Fields\Field; use Carbon_Fields\Field;
function cree_champs_personnalises_produit(): void { function cree_champs_personnalises_produit(): void
Container::make('post_meta', "Product's Details") {
->where('post_type', '=', 'product') Container::make('post_meta', "Product's Details")
->add_fields([ ->where('post_type', '=', 'product')
// Galerie des photos Produit ->add_fields([
Field::make('media_gallery', 'photos_colonne_gauche', __('Left Column Photos')) // Galerie des photos Produit
->set_type(['image']) Field::make('media_gallery', 'photos_colonne_gauche', __('Left Column Photos'))
->set_duplicates_allowed(false), ->set_type(['image'])
// Galerie des photos portées ->set_duplicates_allowed(false),
Field::make('media_gallery', 'photos_colonne_droite', __('Right Column Photos')) // Galerie des photos portées
->set_type(['image']) Field::make('media_gallery', 'photos_colonne_droite', __('Right Column Photos'))
->set_duplicates_allowed(false), ->set_type(['image'])
// Texte des détails du Produit ->set_duplicates_allowed(false),
Field::make('rich_text', 'haiku_details_produit', __("Product's Details")), // Texte des détails du Produit
Field::make('rich_text', 'haiku_details_produit', __("Product's Details")),
]);
}
function cree_champ_personnalise_commande($order): void
{
woocommerce_wp_text_input([
'id' => 'tracking_number',
'label' => 'Tracking Number:',
'value' => $order->get_meta('tracking_number'),
'wrapper_class' => 'form-field-wide',
]); ]);
} }
function cree_champ_personnalise_commande($order): void { function maj_champ_personnalise_commande($order_id): void
woocommerce_wp_text_input([ {
'id' => 'tracking_number', $order = wc_get_order($order_id);
'label' => 'Tracking Number:', $order->update_meta_data('tracking_number', wc_clean($_POST['tracking_number']));
'value' => $order->get_meta('tracking_number'), $order->save();
'wrapper_class' => 'form-field-wide',
]);
}
function maj_champ_personnalise_commande($order_id): void {
$order = wc_get_order($order_id);
$order->update_meta_data('tracking_number', wc_clean($_POST['tracking_number']));
$order->save();
} }
add_action('carbon_fields_register_fields', 'cree_champs_personnalises_produit'); add_action('carbon_fields_register_fields', 'cree_champs_personnalises_produit');

View file

@ -8,69 +8,74 @@
declare(strict_types=1); declare(strict_types=1);
function enregistre_controle_personnalise_tinymce(): void { function enregistre_controle_personnalise_tinymce(): void
/** {
* TinyMCE Custom Control.
*
* @author Anthony Hortin <http://maddisondesigns.com>
* @license http://www.gnu.org/licenses/gpl-2.0.html
*
* @see https://github.com/maddisondesigns
*/
final class ControlesPersonnalises extends WP_Customize_Control {
/** The type of control being rendered. */
public $type = 'editeur_tinymce';
/** /**
* Enqueue our scripts and styles. * TinyMCE Custom Control.
*
* @author Anthony Hortin <http://maddisondesigns.com>
* @license http://www.gnu.org/licenses/gpl-2.0.html
*
* @see https://github.com/maddisondesigns
*/ */
public function enqueue(): void { final class ControlesPersonnalises extends WP_Customize_Control
wp_enqueue_script( {
handle: 'controle-personnalise-tinymce', /** The type of control being rendered. */
src: get_template_directory_uri() . '/assets/vendor/controle-personnalise-tinymce.js', public $type = 'editeur_tinymce';
deps: ['jquery'],
ver: '1.3',
args: true,
);
wp_enqueue_editor();
}
/** /**
* Render the control in the customizer. * Enqueue our scripts and styles.
*/ */
public function render_content(): void { ?> public function enqueue(): void
{
wp_enqueue_script(
handle: 'controle-personnalise-tinymce',
src: get_template_directory_uri() . '/assets/vendor/controle-personnalise-tinymce.js',
deps: ['jquery'],
ver: '1.3',
args: true,
);
wp_enqueue_editor();
}
/**
* Render the control in the customizer.
*/
public function render_content(): void
{ ?>
<div class="tinymce-control"> <div class="tinymce-control">
<span class="customize-control-title"><?php echo esc_html($this->label); ?></span> <span class="customize-control-title"><?php echo esc_html($this->label); ?></span>
<?php if (!empty($this->description)) { ?> <?php if (!empty($this->description)) { ?>
<span class="customize-control-description"><?php echo esc_html($this->description); ?></span> <span class="customize-control-description"><?php echo esc_html($this->description); ?></span>
<?php } ?> <?php } ?>
<textarea id="<?php echo <textarea id="<?php echo
esc_attr($this->id) esc_attr($this->id)
; ?>" class="customize-control-tinymce-editor" <?php $this->link(); ?>><?php echo ; ?>" class="customize-control-tinymce-editor" <?php $this->link(); ?>><?php echo
esc_html($this->value()) esc_html($this->value())
; ?></textarea> ; ?></textarea>
</div> </div>
<?php } <?php }
/** /**
* Pass our TinyMCE toolbar string to JavaScript. * Pass our TinyMCE toolbar string to JavaScript.
*/ */
public function to_json(): void { public function to_json(): void
parent::to_json(); {
parent::to_json();
$this->json['skyrockettinymcetoolbar1'] = isset($this->input_attrs['toolbar1']) $this->json['skyrockettinymcetoolbar1'] = isset($this->input_attrs['toolbar1'])
? esc_attr($this->input_attrs['toolbar1']) ? esc_attr($this->input_attrs['toolbar1'])
: 'bold italic bullist numlist alignleft aligncenter alignright link'; : 'bold italic bullist numlist alignleft aligncenter alignright link';
$this->json['skyrockettinymcetoolbar2'] = isset($this->input_attrs['toolbar2']) $this->json['skyrockettinymcetoolbar2'] = isset($this->input_attrs['toolbar2'])
? esc_attr($this->input_attrs['toolbar2']) ? esc_attr($this->input_attrs['toolbar2'])
: ''; : '';
$this->json['skyrocketmediabuttons'] = isset($this->input_attrs['mediaButtons']) $this->json['skyrocketmediabuttons'] = isset($this->input_attrs['mediaButtons'])
&& $this->input_attrs['mediaButtons'] === true && $this->input_attrs['mediaButtons'] === true
? true ? true
: false; : false;
}
} }
}
} }
add_action('customize_register', 'enregistre_controle_personnalise_tinymce'); add_action('customize_register', 'enregistre_controle_personnalise_tinymce');

View file

@ -11,112 +11,116 @@ use function is_float;
use function is_int; use function is_int;
use function is_string; use function is_string;
final readonly class Cart { final readonly class Cart
public function __construct() {} {
public function __construct() {}
/** La valeur par défaut d'une donnée invalide du Panier. */ /** La valeur par défaut d'une donnée invalide du Panier. */
private const string DEFAULT_VALUE = '0.00'; private const string DEFAULT_VALUE = '0.00';
/** /**
* Retourne la liste des pays acceptés pour la livraison. * Retourne la liste des pays acceptés pour la livraison.
* *
* @return array<int,string> * @return array<int,string>
*/ */
public static function get_allowed_countries(): array { public static function get_allowed_countries(): array
return [ {
'AD', return [
'AL', 'AD',
'AM', 'AL',
'AR', 'AM',
'AT', 'AR',
'AU', 'AT',
'BA', 'AU',
'BE', 'BA',
'BG', 'BE',
'BR', 'BG',
'CA', 'BR',
'CH', 'CA',
'CL', 'CH',
'CR', 'CL',
'CU', 'CR',
'CY', 'CU',
'CZ', 'CY',
'DE', 'CZ',
'DK', 'DE',
'DZ', 'DK',
'EE', 'DZ',
'EG', 'EE',
'ES', 'EG',
'FI', 'ES',
'FR', 'FI',
'GF', 'FR',
'GP', 'GF',
'GR', 'GP',
'HR', 'GR',
'HU', 'HR',
'IE', 'HU',
'IS', 'IE',
'IT', 'IS',
'JP', 'IT',
'KR', 'JP',
'LB', 'KR',
'LI', 'LB',
'LT', 'LI',
'LU', 'LT',
'LV', 'LU',
'MA', 'LV',
'MD', 'MA',
'ME', 'MD',
'MF', 'ME',
'MQ', 'MF',
'MT', 'MQ',
'MX', 'MT',
'NC', 'MX',
'NL', 'NC',
'NO', 'NL',
'NZ', 'NO',
'PF', 'NZ',
'PL', 'PF',
'PM', 'PL',
'PS', 'PM',
'PT', 'PS',
'RE', 'PT',
'RO', 'RE',
'SE', 'RO',
'SI', 'SE',
'SK', 'SI',
'SM', 'SK',
'TN', 'SM',
'TR', 'TN',
'TW', 'TR',
'US', 'TW',
'YT', 'US',
'ZA', 'YT',
]; 'ZA',
} ];
public static function parse_cart_value(int|float|string|bool $cart_value): string {
if (is_int($cart_value) || is_float($cart_value)) {
return self::format_number($cart_value);
} }
if (is_string($cart_value)) { public static function parse_cart_value(int|float|string|bool $cart_value): string
$number = Number::parseInt($cart_value); {
$number = is_bool($number) ? 0 : $number; if (is_int($cart_value) || is_float($cart_value)) {
return self::format_number($cart_value);
}
return self::format_number($number); if (is_string($cart_value)) {
$number = Number::parseInt($cart_value);
$number = is_bool($number) ? 0 : $number;
return self::format_number($number);
}
return '0.00';
} }
return '0.00'; private static function format_number(int|float $number): string
} {
$formatted_number = Number::format(
private static function format_number(int|float $number): string { number: $number,
$formatted_number = Number::format( // precision et max_precision sont mutuellement exclusifs.
number: $number, precision: 2,
// precision et max_precision sont mutuellement exclusifs. locale: 'fr',
precision: 2, );
locale: 'fr', return is_bool($formatted_number) ? self::DEFAULT_VALUE : $formatted_number;
); }
return is_bool($formatted_number) ? self::DEFAULT_VALUE : $formatted_number;
}
} }

View file

@ -6,32 +6,34 @@ namespace HaikuAtelier\Data;
use WC_Product; use WC_Product;
final readonly class ProductVariation { final readonly class ProductVariation
/** {
* @param int $id L'ID de la Variation /**
* @param string $price Le prix de la Variation * @param int $id L'ID de la Variation
* @param list<ProductVariationAttribute> $attributes Les attributs appliqués à la Variation * @param string $price Le prix de la Variation
*/ * @param list<ProductVariationAttribute> $attributes Les attributs appliqués à la Variation
private function __construct( */
public int $id, private function __construct(
public string $price, public int $id,
public array $attributes, public string $price,
) {} public array $attributes,
) {}
/** /**
* Créé une nouvelle instance de `ProductVariation` à partir d'un `WC_Product`. * Créé une nouvelle instance de `ProductVariation` à partir d'un `WC_Product`.
*/ */
public static function new(WC_Product $product): self { public static function new(WC_Product $product): self
$id = $product->get_id(); {
$price = $product->get_price(); $id = $product->get_id();
/** @var list<ProductVariationAttribute> */ $price = $product->get_price();
$attributes = array_map( /** @var list<ProductVariationAttribute> */
/** @phpstan-ignore argument.type (Impossible à satisfaire) */ $attributes = array_map(
static fn(string $key, string $value) => new ProductVariationAttribute($key, $value), /** @phpstan-ignore argument.type (Impossible à satisfaire) */
array_keys($product->get_attributes()), static fn(string $key, string $value) => new ProductVariationAttribute($key, $value),
array_values($product->get_attributes()), array_keys($product->get_attributes()),
); array_values($product->get_attributes()),
);
return new self($id, $price, $attributes); return new self($id, $price, $attributes);
} }
} }

View file

@ -4,13 +4,14 @@ declare(strict_types=1);
namespace HaikuAtelier\Data; namespace HaikuAtelier\Data;
final readonly class ProductVariationAttribute { final readonly class ProductVariationAttribute
/** {
* @param string $attribute Le slug de l'Attribut /**
* @param string $value Le slug de la valeur de l'Attribut * @param string $attribute Le slug de l'Attribut
*/ * @param string $value Le slug de la valeur de l'Attribut
public function __construct( */
public string $attribute, public function __construct(
public string $value, public string $attribute,
) {} public string $value,
) {}
} }

View file

@ -9,8 +9,9 @@ declare(strict_types=1);
namespace HaikuAtelier; namespace HaikuAtelier;
// Désactive divers transformations du contenu par WordPress // Désactive divers transformations du contenu par WordPress
function desactive_wpautop(): void { function desactive_wpautop(): void
remove_filter('the_content', 'wpautop'); {
remove_filter('the_content', 'wpautop');
} }
/** /**
@ -20,16 +21,17 @@ function desactive_wpautop(): void {
* *
* @return array<string, bool> le même tableau avec des configurations en plus * @return array<string, bool> le même tableau avec des configurations en plus
*/ */
function desactive_transformation_contenu_tinymce(array $configuration): array { function desactive_transformation_contenu_tinymce(array $configuration): array
// Ne supprime pas les retours à la ligne {
$configuration['remove_linebreaks'] = false; // Ne supprime pas les retours à la ligne
// Convertis les caractères de retours à la ligne en <br> $configuration['remove_linebreaks'] = false;
$configuration['convert_newlines_to_brs'] = true; // Convertis les caractères de retours à la ligne en <br>
// Supprime les <br> redondants $configuration['convert_newlines_to_brs'] = true;
$configuration['remove_redundant_brs'] = false; // Supprime les <br> redondants
$configuration['remove_redundant_brs'] = false;
// Retourne $configuration à WordPress // Retourne $configuration à WordPress
return $configuration; return $configuration;
} }
/** /**
@ -39,19 +41,22 @@ function desactive_transformation_contenu_tinymce(array $configuration): array {
* *
* @return array<string, string> le même tableau avec SVG en plus * @return array<string, string> le même tableau avec SVG en plus
*/ */
function autorise_import_svg_mediatheque(array $file_types): array { function autorise_import_svg_mediatheque(array $file_types): array
$new_filetypes = []; {
$new_filetypes['svg'] = 'image/svg+xml'; $new_filetypes = [];
$new_filetypes['svg'] = 'image/svg+xml';
return [...$file_types, ...$new_filetypes]; return [...$file_types, ...$new_filetypes];
} }
function retire_motifs_blocs_gutenberg(): void { function retire_motifs_blocs_gutenberg(): void
remove_theme_support('core-block-patterns'); {
remove_theme_support('core-block-patterns');
} }
function retire_styles_core_block(): void { function retire_styles_core_block(): void
wp_dequeue_style('core-block-supports'); {
wp_dequeue_style('core-block-supports');
} }
// Désactive les appels à l'API de la mise à jour des traductions // Désactive les appels à l'API de la mise à jour des traductions

View file

@ -14,32 +14,33 @@ use function register_taxonomy;
/** /**
* Enregistre la Taxonomie « Collection ». * Enregistre la Taxonomie « Collection ».
*/ */
function enregistre_taxonomie_collection(): void { function enregistre_taxonomie_collection(): void
$labels = [ {
'add_new_item' => __('Add New Collection'), $labels = [
'all_items' => __('All Collections'), 'add_new_item' => __('Add New Collection'),
'edit_item' => __('Edit Collection'), 'all_items' => __('All Collections'),
'menu_name' => __('Collections'), 'edit_item' => __('Edit Collection'),
'name' => __('Collections'), 'menu_name' => __('Collections'),
'new_item_name' => __('New Collection Name'), 'name' => __('Collections'),
'search_items' => __('Search Collections'), 'new_item_name' => __('New Collection Name'),
'singular_name' => __('Collection'), 'search_items' => __('Search Collections'),
'update_item' => __('Update Collection'), 'singular_name' => __('Collection'),
]; 'update_item' => __('Update Collection'),
$args = [ ];
'description' => __('An ensemble of pieces thematically or chronologically grouped together.'), $args = [
'hierarchical' => false, 'description' => __('An ensemble of pieces thematically or chronologically grouped together.'),
'labels' => $labels, 'hierarchical' => false,
'publicly_queryable' => false, 'labels' => $labels,
'query_var' => true, 'publicly_queryable' => false,
'rewrite' => ['slug' => 'collection'], 'query_var' => true,
'show_admin_column' => true, 'rewrite' => ['slug' => 'collection'],
'show_in_menu' => true, 'show_admin_column' => true,
'show_in_quick_edit' => true, 'show_in_menu' => true,
'show_ui' => true, 'show_in_quick_edit' => true,
]; 'show_ui' => true,
];
register_taxonomy('collection', ['product'], $args); register_taxonomy('collection', ['product'], $args);
} }
add_action('init', enregistre_taxonomie_collection(...)); add_action('init', enregistre_taxonomie_collection(...));

View file

@ -14,46 +14,50 @@ use function is_array;
use function Psl\Option\none; use function Psl\Option\none;
use function Psl\Option\some; use function Psl\Option\some;
final readonly class Post { final readonly class Post
/** {
* @return Option\Option<mixed> /**
*/ * @return Option\Option<mixed>
public static function get_post_meta(int $post_id, string $key): Option\Option { */
/** @var false|mixed|string */ public static function get_post_meta(int $post_id, string $key): Option\Option
$value = get_post_meta($post_id, $key, true); {
/** @var false|mixed|string */
$value = get_post_meta($post_id, $key, true);
if ($value === false) { if ($value === false) {
return none(); return none();
}
return some($value);
} }
return some($value); /**
} * @return Option\Option<array<mixed>>
*/
public static function get_post_meta_array(int $post_id, string $key): Option\Option
{
/** @var array<mixed>|false */
$value = get_post_meta($post_id, $key, false);
/** if (is_array($value)) {
* @return Option\Option<array<mixed>> return some($value);
*/ }
public static function get_post_meta_array(int $post_id, string $key): Option\Option {
/** @var array<mixed>|false */
$value = get_post_meta($post_id, $key, false);
if (is_array($value)) { return none();
return some($value);
} }
return none(); /**
} * @return Option\Option<array<mixed>>
*/
public static function get_terms(int $post_id, string $taxonomy_name): Option\Option
{
/** @var false|list<WP_Term>|WP_Error */
$terms = get_the_terms($post_id, $taxonomy_name);
/** if (is_array($terms)) {
* @return Option\Option<array<mixed>> return some($terms);
*/ }
public static function get_terms(int $post_id, string $taxonomy_name): Option\Option {
/** @var false|list<WP_Term>|WP_Error */
$terms = get_the_terms($post_id, $taxonomy_name);
if (is_array($terms)) { return none();
return some($terms);
} }
return none();
}
} }

View file

@ -7,13 +7,11 @@ import { getOptionOrThrowWithError } from "./utils.ts";
type ParentElement = Document | Element; type ParentElement = Document | Element;
const getFirstSelectorFromParent = const getFirstSelectorFromParent =
(parent: ParentElement) => (parent: ParentElement) => <E extends Element = Element>(selector: string): Option.Option<NonNullable<E>> =>
<E extends Element = Element>(selector: string): Option.Option<NonNullable<E>> =>
Option.fromNullishOr(parent.querySelector<E>(selector)); Option.fromNullishOr(parent.querySelector<E>(selector));
const getFirstSelectorFromParentOrThrow = const getFirstSelectorFromParentOrThrow =
(parent: ParentElement) => (parent: ParentElement) => <E extends Element = Element>(selector: string): NonNullable<E> =>
<E extends Element = Element>(selector: string): NonNullable<E> =>
pipe( pipe(
getFirstSelectorFromParent(parent)<E>(selector), getFirstSelectorFromParent(parent)<E>(selector),
getOptionOrThrowWithError(`Il n'y a pas d'Élément dans le parent avec le sélecteur suivant : ${selector}.`), getOptionOrThrowWithError(`Il n'y a pas d'Élément dans le parent avec le sélecteur suivant : ${selector}.`),
@ -29,8 +27,7 @@ const getFirstSelectorFromDocumentOrThrow = <E extends Element = Element>(select
); );
const getAllSelectorFromParent = const getAllSelectorFromParent =
(parent: ParentElement) => (parent: ParentElement) => <E extends Element = Element>(selector: string): Option.Option<NonEmptyReadonlyArray<E>> =>
<E extends Element = Element>(selector: string): Option.Option<NonEmptyReadonlyArray<E>> =>
pipe( pipe(
parent.querySelectorAll<E>(selector), parent.querySelectorAll<E>(selector),
// Convertis NodeListOf en Array. // Convertis NodeListOf en Array.

View file

@ -1,9 +1,7 @@
import { Option, pipe } from "effect"; import { Option, pipe } from "effect";
export const getOptionOrThrowWithError = export const getOptionOrThrowWithError = (message: string) => <T>(option: Option.Option<T>): T =>
(message: string) => pipe(
<T>(option: Option.Option<T>): T => option,
pipe( Option.getOrThrowWith(() => new Error(message)),
option, );
Option.getOrThrowWith(() => new Error(message)),
);

View file

@ -1,18 +1,12 @@
export const forEach = export const forEach = <T>(fn: (_1: T) => void) => (xs: Array<T>): void => {
<T>(fn: (_1: T) => void) => xs.forEach(fn);
(xs: Array<T>): void => { };
xs.forEach(fn);
};
export const forEachWithIndex = export const forEachWithIndex = <T>(fn: (_1: T, _2: number) => void) => (xs: Array<T>): void => {
<T>(fn: (_1: T, _2: number) => void) => xs.forEach(fn);
(xs: Array<T>): void => { };
xs.forEach(fn);
};
export const map = export const map = <T>(fn: (_1: T) => void) => (xs: Array<T>): Array<T> => {
<T>(fn: (_1: T) => void) => xs.map(fn);
(xs: Array<T>): Array<T> => { return xs;
xs.map(fn); };
return xs;
};

View file

@ -18,26 +18,22 @@ import {
} from "./erreurs"; } from "./erreurs";
export const recupereElementAvecSelecteur = export const recupereElementAvecSelecteur =
(parent: ParentElement) => (parent: ParentElement) => <E extends Element = Element>(selecteur: string): Either<SyntaxError, E> =>
<E extends Element = Element>(selecteur: string): Either<SyntaxError, E> =>
Either Either
// Retourne une SyntaxError dans un Left si le sélecteur est invalide // Retourne une SyntaxError dans un Left si le sélecteur est invalide
.encase(() => parent.querySelector<E>(selecteur)) .encase(() => parent.querySelector<E>(selecteur))
// Transforme le Left en une erreur plus sympathique // Transforme le Left en une erreur plus sympathique
.mapLeft((_) => creeSyntaxError(ERREUR_SYNTAXE_INVALIDE(selecteur))) .mapLeft(_ => creeSyntaxError(ERREUR_SYNTAXE_INVALIDE(selecteur)))
// Retourne une SyntaxError si l'Élément est null // Retourne une SyntaxError si l'Élément est null
.chain((e: E | null) => .chain((e: E | null) => G.isNotNullable(e) ? Right(e) : Left(creeSyntaxError(ERREUR_DOM_INEXISTANT(selecteur))));
G.isNotNullable(e) ? Right(e) : Left(creeSyntaxError(ERREUR_DOM_INEXISTANT(selecteur))),
);
export const getDOMElementsWithSelector = export const getDOMElementsWithSelector =
(parent: ParentElement) => (parent: ParentElement) => <E extends Element = Element>(selecteur: string): Either<SyntaxError, Array<E>> =>
<E extends Element = Element>(selecteur: string): Either<SyntaxError, Array<E>> =>
Either Either
// Retourne une SyntaxError dans un Left si le sélecteur est invalide // Retourne une SyntaxError dans un Left si le sélecteur est invalide
.encase(() => pipe(parent.querySelectorAll<E>(selecteur), Array.from<E>)) .encase(() => pipe(parent.querySelectorAll<E>(selecteur), Array.from<E>))
// Transforme le Left en une erreur plus sympathique // Transforme le Left en une erreur plus sympathique
.mapLeft((_) => creeSyntaxError(ERREUR_SYNTAXE_INVALIDE(selecteur))) .mapLeft(_ => creeSyntaxError(ERREUR_SYNTAXE_INVALIDE(selecteur)))
// Retourne une SyntaxError si le tableau est vide // Retourne une SyntaxError si le tableau est vide
.chain((e: Array<E>) => (A.isEmpty(e) ? Left(creeSyntaxError(ERREUR_DOM_INEXISTANT(selecteur))) : Right(e))); .chain((e: Array<E>) => (A.isEmpty(e) ? Left(creeSyntaxError(ERREUR_DOM_INEXISTANT(selecteur))) : Right(e)));
@ -55,20 +51,18 @@ export const recupereElementsOuLeve = <E extends Element = Element>(
Right: identity, Right: identity,
}); });
export const majElementInnerHtml = export const majElementInnerHtml = <T extends HTMLElement>(element: T) => (innerHtml: string) => {
<T extends HTMLElement>(element: T) => element.innerHTML = innerHtml;
(innerHtml: string) => { return element;
element.innerHTML = innerHtml; };
return element;
};
// Merci facon (https://github.com/terkelg/facon) // Merci facon (https://github.com/terkelg/facon)
export const html = (strings: TemplateStringsArray, ...args: Array<string>) => export const html = (strings: TemplateStringsArray, ...args: Array<string>) =>
pipe( pipe(
document.createElement("template"), document.createElement("template"),
(template) => template =>
majElementInnerHtml(template)(args.reduce((prev, value, i) => prev + value + strings[i + 1], strings[0])), majElementInnerHtml(template)(args.reduce((prev, value, i) => prev + value + strings[i + 1], strings[0])),
(template) => template.content, template => template.content,
); );
/** /**
@ -86,10 +80,8 @@ export const safeJsonParse = (chaine: string): Either<SyntaxError, JSONValue> =>
* *
* @returns Un booléen * @returns Un booléen
*/ */
export const targetMatchesSelector = <E extends HTMLElement = HTMLElement>( export const targetMatchesSelector = (cible: EventTarget | null, selecteur: string): cible is HTMLElement =>
cible: EventTarget | null, (cible as HTMLElement)?.matches(selecteur);
selecteur: string,
): cible is E => cible !== null && (cible as HTMLElement).matches(selecteur);
export const recupereElementsDocumentEither: <E extends Element = Element>( export const recupereElementsDocumentEither: <E extends Element = Element>(
selecteur: string, selecteur: string,
@ -105,13 +97,11 @@ export const recupereElementDocumentEither: <E extends Element = Element>(select
* @throws Une SyntaxError si l'Élément n'est pas trouvé. * @throws Une SyntaxError si l'Élément n'est pas trouvé.
* @returns Un Élément. * @returns Un Élément.
*/ */
export const mustGetEleInDocument = <E extends Element = Element>(selecteur: string): E => export const mustGetEleInDocument = (selecteur: string): Element =>
pipe(recupereElementDocumentEither<E>(selecteur), recupereElementOuLeve); pipe(recupereElementDocumentEither<Element>(selecteur), recupereElementOuLeve);
export const mustGetEleInParent = export const mustGetEleInParent = (parent: ParentElement) => (selector: string) =>
(parent: ParentElement) => pipe(recupereElementAvecSelecteur(parent)<HTMLElement>(selector), recupereElementOuLeve);
<E extends HTMLElement>(selector: string) =>
pipe(recupereElementAvecSelecteur(parent)<E>(selector), recupereElementOuLeve);
/** /**
* Fonction utilitaire pour récupérer des Éléments selon un sélecteur au sein du Document. * Fonction utilitaire pour récupérer des Éléments selon un sélecteur au sein du Document.
@ -138,11 +128,11 @@ export const setButtonLoadingState = (button: HTMLButtonElement, isLoading: bool
}; };
export const estErreurHttp = (erreur: unknown) => export const estErreurHttp = (erreur: unknown) =>
erreur instanceof BadRequestError || erreur instanceof BadRequestError
erreur instanceof ForbiddenError || || erreur instanceof ForbiddenError
erreur instanceof NotFoundError || || erreur instanceof NotFoundError
erreur instanceof ServerError || || erreur instanceof ServerError
erreur instanceof UnauthorizedError; || erreur instanceof UnauthorizedError;
export const estErreurFetch = (erreur: unknown) => export const estErreurFetch = (erreur: unknown) =>
erreur instanceof DOMException || erreur instanceof TypeError || erreur instanceof Error; erreur instanceof DOMException || erreur instanceof TypeError || erreur instanceof Error;

View file

@ -78,7 +78,7 @@ export const Erreur = (message: string): Error => new Error(message);
export const ErreurInconnue = (erreur: unknown): UnknownError => new UnknownError(erreur); export const ErreurInconnue = (erreur: unknown): UnknownError => new UnknownError(erreur);
export const ErreurEntreeInexistante = (message: string): NonExistingKeyError => new NonExistingKeyError(message); export const ErreurEntreeInexistante = (message: string): NonExistingKeyError => new NonExistingKeyError(message);
export const leveErreur = <E extends Error = Error>(erreur: E): never => { export const leveErreur = (erreur: Error): never => {
throw erreur; throw erreur;
}; };
export const leveBadRequestError = (erreur: WCErrorBody): never => { export const leveBadRequestError = (erreur: WCErrorBody): never => {
@ -106,7 +106,7 @@ export const leveNonExistingKeyError = (message: string): never => {
* @param erreur * @param erreur
* @returns L'ID Sentry de l'évènement capturé. * @returns L'ID Sentry de l'évènement capturé.
*/ */
export const reporteErreur = <E extends Error>(erreur: E): string => captureException(erreur); export const reporteErreur = (erreur: Error): string => captureException(erreur);
/** /**
* Reporte une Erreur, sous forme d'erreur console et au service GlitchTip, puis la lève sous forme * Reporte une Erreur, sous forme d'erreur console et au service GlitchTip, puis la lève sous forme
@ -115,12 +115,12 @@ export const reporteErreur = <E extends Error>(erreur: E): string => captureExce
* @param erreur * @param erreur
* @returns never Lève une Erreur et ne retourne donc rien. * @returns never Lève une Erreur et ne retourne donc rien.
*/ */
export const reporteEtLeveErreur = <E extends Error>(erreur: E): never => { export const reporteEtLeveErreur = (erreur: Error): never => {
reporteErreur(erreur); reporteErreur(erreur);
throw erreur; throw erreur;
}; };
export const reporteEtJournaliseErreur = <E extends Error>(erreur: E): void => { export const reporteEtJournaliseErreur = (erreur: Error): void => {
reporteErreur(erreur); reporteErreur(erreur);
console.error(erreur); console.error(erreur);
if (erreur instanceof ValiError) { if (erreur instanceof ValiError) {

View file

@ -7,12 +7,12 @@ export const CODE_PROMO_MAJ_EVENT = new CustomEvent(CODE_PROMO_MAJ, {});
// Interfaces // Interfaces
export type UpdatedShippingRatesEvent = { export type UpdatedShippingRatesEvent = Event & {
detail: { refresh_methods: boolean; shipping_rates: ReadonlyArray<WCStoreShippingRateShippingRate> }; detail: { refresh_methods: boolean; shipping_rates: ReadonlyArray<WCStoreShippingRateShippingRate> };
} & Event; };
export type UpdatedTotalsEvent = { export type UpdatedTotalsEvent = Event & {
detail: { totals: WCStoreCartTotals }; detail: { totals: WCStoreCartTotals };
} & Event; };
// Méthodes // Méthodes

View file

@ -1,9 +1,7 @@
import type { Constructor } from "./types/classes"; import type { Constructor } from "./types/classes";
const estElement = const estElement = <T extends HTMLElement>(typeElement: Constructor<T>) => (element: unknown): element is T =>
<T extends HTMLElement>(typeElement: Constructor<T>) => element instanceof typeElement;
(element: unknown): element is T =>
element instanceof typeElement;
export const estHTMLSelectElement = estElement<HTMLSelectElement>(HTMLSelectElement); export const estHTMLSelectElement = estElement<HTMLSelectElement>(HTMLSelectElement);

View file

@ -55,30 +55,31 @@ export const emetMessageMajContenuPanier = (args: MessageMajContenuPanierDonnees
* @param message Le message émis. * @param message Le message émis.
* @return void * @return void
*/ */
export const emetUniqueMessageBroadcastChannel = <M>(nomCanal: string, message: M): void => export const emetUniqueMessageBroadcastChannel = (nomCanal: string, message: unknown): void => {
pipe( pipe(
new BroadcastChannel(nomCanal), new BroadcastChannel(nomCanal),
(canal) => canalPostMessage(canal, message), canal => canalPostMessage(canal, message),
(canal) => canal.close(), canal => canal.close(),
); );
};
// Validations // Validations
export const valideMessageMajBoutonPanier = ( export const valideMessageMajBoutonPanier = (
evenementMessage: MessageEvent<unknown>, evenementMessage: MessageEvent<unknown>,
): Either<ValiError<typeof MessageMajBoutonPanierSchema>, MessageMajBoutonPanier> => ): Either<ValiError<typeof MessageMajBoutonPanierSchema>, MessageMajBoutonPanier> =>
Either.of<ValiError<typeof MessageMajBoutonPanierSchema>, MessageMajBoutonPanier>( Either.of<ValiError<typeof MessageMajBoutonPanierSchema>>(
parse(MessageMajBoutonPanierSchema, evenementMessage.data), parse(MessageMajBoutonPanierSchema, evenementMessage.data),
).ifLeft((erreur) => reporteErreur(erreur)); ).ifLeft(erreur => reporteErreur(erreur));
export const valideMessageMajContenuPanier = ( export const valideMessageMajContenuPanier = (
evenementMessage: MessageEvent<unknown>, evenementMessage: MessageEvent<unknown>,
): Either<ValiError<typeof MessageMajContenuPanierSchema>, MessageMajContenuPanier> => ): Either<ValiError<typeof MessageMajContenuPanierSchema>, MessageMajContenuPanier> =>
Either.of<ValiError<typeof MessageMajContenuPanierSchema>, MessageMajContenuPanier>( Either.of<ValiError<typeof MessageMajContenuPanierSchema>>(
parse(MessageMajContenuPanierSchema, evenementMessage.data), parse(MessageMajContenuPanierSchema, evenementMessage.data),
).ifLeft((erreur) => reporteErreur(erreur)); ).ifLeft(erreur => reporteErreur(erreur));
// Correspondances // Correspondances
export const reponseEstCodeErreurWC = (reponse: SimplifiedResponse, codeErreurWC: string): boolean => export const reponseEstCodeErreurWC = (reponse: SimplifiedResponse, codeErreurWC: string): boolean =>
safeSchemaParse(reponse, WCErrorSchema) safeSchemaParse(reponse, WCErrorSchema)
.map((v) => v.body.code === codeErreurWC) .map(v => v.body.code === codeErreurWC)
.orDefault(false); .orDefault(false);

View file

@ -5,10 +5,10 @@ export const estEntreDeuxNombres = (nombre: number, min: number, max: number): b
export const diviseParCent = (nombre: number | string): number => Number(nombre) / 100; export const diviseParCent = (nombre: number | string): number => Number(nombre) / 100;
export const arrondisADeuxDecimales = (nombre: number | string) => pipe(Number(nombre), (n) => n.toFixed(2)); export const arrondisADeuxDecimales = (nombre: number | string) => pipe(Number(nombre), n => n.toFixed(2));
export const arrondisAZeroOuDeuxDecimales = (nombre: number | string): string => export const arrondisAZeroOuDeuxDecimales = (nombre: number | string): string =>
pipe(Number(nombre), (n) => (n / Math.round(n) === 1 ? n.toFixed(0) : n.toFixed(2))); pipe(Number(nombre), n => (n / Math.round(n) === 1 ? n.toFixed(0) : n.toFixed(2)));
export const inverseNombre = (nombre: number | string): number => Number(nombre) * -1; export const inverseNombre = (nombre: number | string): number => Number(nombre) * -1;

View file

@ -38,7 +38,7 @@ type ArgumentsPostBackendWC = {
// Fetch // Fetch
export const getBackend = (args: ArgumentsGetBackendWC): Promise<Response> => export const getBackend = async (args: ArgumentsGetBackendWC): Promise<Response> =>
fetch(args.route, { fetch(args.route, {
credentials: "same-origin", credentials: "same-origin",
headers: { headers: {
@ -53,7 +53,7 @@ export const getBackend = (args: ArgumentsGetBackendWC): Promise<Response> =>
signal: AbortSignal.timeout(5000), signal: AbortSignal.timeout(5000),
}); });
export const getBackendAvecParametresUrl = (args: ArgumentsGetBackendWC): Promise<Response> => export const getBackendAvecParametresUrl = async (args: ArgumentsGetBackendWC): Promise<Response> =>
fetch(`${args.route}?${args.searchParams}`, { fetch(`${args.route}?${args.searchParams}`, {
credentials: "same-origin", credentials: "same-origin",
headers: { headers: {
@ -68,7 +68,7 @@ export const getBackendAvecParametresUrl = (args: ArgumentsGetBackendWC): Promis
signal: AbortSignal.timeout(5000), signal: AbortSignal.timeout(5000),
}); });
export const deleteBackend = (args: ArgumentsDeleteBackendWC): Promise<Response> => export const deleteBackend = async (args: ArgumentsDeleteBackendWC): Promise<Response> =>
fetch(args.route, { fetch(args.route, {
credentials: "same-origin", credentials: "same-origin",
headers: { headers: {
@ -83,7 +83,7 @@ export const deleteBackend = (args: ArgumentsDeleteBackendWC): Promise<Response>
signal: AbortSignal.timeout(5000), signal: AbortSignal.timeout(5000),
}); });
export const postBackend = (args: ArgumentsPostBackendWC): Promise<Response> => export const postBackend = async (args: ArgumentsPostBackendWC): Promise<Response> =>
fetch(args.route, { fetch(args.route, {
body: args.corps, body: args.corps,
credentials: "same-origin", credentials: "same-origin",
@ -101,7 +101,7 @@ export const postBackend = (args: ArgumentsPostBackendWC): Promise<Response> =>
export const prefilledPostBackend = export const prefilledPostBackend =
(nonce: string, authString?: string) => (nonce: string, authString?: string) =>
(route: string, body: BodyInit, needsAuthString: boolean): Promise<Response> => async (route: string, body: BodyInit, needsAuthString: boolean): Promise<Response> =>
fetch(route, { fetch(route, {
body: body, body: body,
credentials: "same-origin", credentials: "same-origin",
@ -127,9 +127,9 @@ export const newPartialResponse = async (reponse: Response): Promise<SimplifiedR
export const traiteErreursBackendWooCommerce = (rs: SimplifiedResponse): HttpCodeErrors => export const traiteErreursBackendWooCommerce = (rs: SimplifiedResponse): HttpCodeErrors =>
match(rs) match(rs)
.with({ status: 400 }, () => new BadRequestError()) ["with"]({ status: 400 }, () => new BadRequestError())
.with({ status: 401 }, () => new UnauthorizedError()) ["with"]({ status: 401 }, () => new UnauthorizedError())
.with({ status: 403 }, () => new ForbiddenError()) ["with"]({ status: 403 }, () => new ForbiddenError())
.with({ status: 404 }, () => new NotFoundError()) ["with"]({ status: 404 }, () => new NotFoundError())
.with({ status: 500 }, () => new ServerError()) ["with"]({ status: 500 }, () => new ServerError())
.otherwise((rs) => new Error(String(rs.status))); .otherwise(rs => new Error(String(rs.status)));

View file

@ -7,7 +7,5 @@ import { Maybe } from "purify-ts";
*/ */
export const first = <T>(xs: Array<T>): Maybe<T> => Maybe.fromNullable(xs.at(0)); export const first = <T>(xs: Array<T>): Maybe<T> => Maybe.fromNullable(xs.at(0));
export const find = export const find = <T>(predicateFn: (_1: T) => boolean) => (xs: Array<T>): Maybe<T> =>
<T>(predicateFn: (_1: T) => boolean) => Maybe.fromNullable(xs.find(predicateFn));
(xs: Array<T>): Maybe<T> =>
Maybe.fromNullable(xs.find(predicateFn));

View file

@ -20,24 +20,24 @@ export const WCStoreCartItemTotalsSchema = v.object({
}); });
export const WCStoreCartItemSchema = v.object({ export const WCStoreCartItemSchema = v.object({
backorders_allowed: v.boolean(), backorders_allowed: v["boolean"](),
catalog_visibility: v.enum(CATALOG_VISIBILITIES), catalog_visibility: v["enum"](CATALOG_VISIBILITIES),
description: v.string(), description: v.string(),
extensions: v.unknown(), extensions: v.unknown(),
id: v.number(), id: v.number(),
images: v.array(v.unknown()), images: v.array(v.unknown()),
item_data: v.array(v.unknown()), item_data: v.array(v.unknown()),
key: v.string(), key: v.string(),
low_stock_remaining: v.union([v.number(), v.null()]), low_stock_remaining: v.union([v.number(), v["null"]()]),
name: v.string(), name: v.string(),
permalink: v.pipe(v.string(), v.url()), permalink: v.pipe(v.string(), v.url()),
prices: v.unknown(), prices: v.unknown(),
quantity: v.number(), quantity: v.number(),
quantity_limits: v.unknown(), quantity_limits: v.unknown(),
short_description: v.string(), short_description: v.string(),
show_backorder_badge: v.boolean(), show_backorder_badge: v["boolean"](),
sku: v.string(), sku: v.string(),
sold_individually: v.boolean(), sold_individually: v["boolean"](),
totals: WCStoreCartItemTotalsSchema, totals: WCStoreCartItemTotalsSchema,
type: v.string(), type: v.string(),
variation: v.array(v.unknown()), variation: v.array(v.unknown()),
@ -60,10 +60,10 @@ export const WCStoreCartTotalsSchema = v.object({
total_items_tax: v.string(), total_items_tax: v.string(),
total_price: v.pipe(v.union([v.string(), v.number()]), v.transform(Number)), total_price: v.pipe(v.union([v.string(), v.number()]), v.transform(Number)),
total_shipping: v.pipe( total_shipping: v.pipe(
v.union([v.string(), v.number(), v.null()]), v.union([v.string(), v.number(), v["null"]()]),
v.transform((n) => (n ? Number(n) : 0)), v.transform(n => (n ? Number(n) : 0)),
), ),
total_shipping_tax: v.union([v.string(), v.null()]), total_shipping_tax: v.union([v.string(), v["null"]()]),
total_tax: v.string(), total_tax: v.string(),
}); });
@ -75,12 +75,12 @@ export const WCStoreCartSchema = v.object({
errors: v.unknown(), errors: v.unknown(),
extensions: v.unknown(), extensions: v.unknown(),
fees: v.unknown(), fees: v.unknown(),
has_calculated_shipping: v.boolean(), has_calculated_shipping: v["boolean"](),
items: v.array(WCStoreCartItemSchema), items: v.array(WCStoreCartItemSchema),
items_count: v.pipe(v.number(), v.integer()), items_count: v.pipe(v.number(), v.integer()),
items_weight: v.pipe(v.number(), v.integer()), items_weight: v.pipe(v.number(), v.integer()),
needs_payment: v.boolean(), needs_payment: v["boolean"](),
needs_shipping: v.boolean(), needs_shipping: v["boolean"](),
payment_methods: v.unknown(), payment_methods: v.unknown(),
payment_requirements: v.unknown(), payment_requirements: v.unknown(),
shipping_address: WCStoreShippingAddressSchema, shipping_address: WCStoreShippingAddressSchema,

View file

@ -26,7 +26,7 @@ export const WCStoreShippingRateShippingRateSchema = v.object({
name: v.string(), name: v.string(),
price: v.pipe(v.union([v.string(), v.number()]), v.transform(Number)), price: v.pipe(v.union([v.string(), v.number()]), v.transform(Number)),
rate_id: v.string(), rate_id: v.string(),
selected: v.boolean(), selected: v["boolean"](),
taxes: v.string(), taxes: v.string(),
}); });

View file

@ -24,14 +24,14 @@ export const WCAddressErrorSchema = v.object({
billing: v.optional( billing: v.optional(
v.object({ v.object({
code: v.string(), code: v.string(),
data: v.union([v.null(), v.string()]), data: v.union([v["null"](), v.string()]),
message: v.string(), message: v.string(),
}), }),
), ),
shipping: v.optional( shipping: v.optional(
v.object({ v.object({
code: v.string(), code: v.string(),
data: v.union([v.null(), v.string()]), data: v.union([v["null"](), v.string()]),
message: v.string(), message: v.string(),
}), }),
), ),

View file

@ -17,36 +17,36 @@ import {
export const WCProductsArgsSchema = v.object({ export const WCProductsArgsSchema = v.object({
// Date ISO8601 // Date ISO8601
after: v.optional(v.optional(v.string())), after: v.optional(v.optional(v.string())),
attribute_relation: v.optional(v.enum(ATTRIBUTES_RELATIONS)), attribute_relation: v.optional(v["enum"](ATTRIBUTES_RELATIONS)),
attributes: v.optional(v.array(v.unknown())), attributes: v.optional(v.array(v.unknown())),
// Date ISO8601 // Date ISO8601
before: v.optional(v.string()), before: v.optional(v.string()),
catalog_visibility: v.optional(v.enum(CATALOG_VISIBILITIES)), catalog_visibility: v.optional(v["enum"](CATALOG_VISIBILITIES)),
category: v.optional(v.string()), category: v.optional(v.string()),
category_operator: v.optional(v.enum(CATEGORY_OPERATORS)), category_operator: v.optional(v["enum"](CATEGORY_OPERATORS)),
context: v.optional(v.enum(PRODUCTS_CONTEXTES)), context: v.optional(v["enum"](PRODUCTS_CONTEXTES)),
date_column: v.optional(v.enum(DATE_COLUMN_VALUES)), date_column: v.optional(v["enum"](DATE_COLUMN_VALUES)),
exclude: v.optional(v.array(v.pipe(v.number(), v.integer()))), exclude: v.optional(v.array(v.pipe(v.number(), v.integer()))),
featured: v.optional(v.boolean()), featured: v.optional(v["boolean"]()),
include: v.optional(v.array(v.pipe(v.number(), v.integer()))), include: v.optional(v.array(v.pipe(v.number(), v.integer()))),
max_price: v.optional(v.string()), max_price: v.optional(v.string()),
min_price: v.optional(v.string()), min_price: v.optional(v.string()),
offset: v.optional(v.number()), offset: v.optional(v.number()),
on_sale: v.optional(v.boolean()), on_sale: v.optional(v["boolean"]()),
order: v.optional(v.enum(ORDER_VALUES)), order: v.optional(v["enum"](ORDER_VALUES)),
orderby: v.optional(v.enum(ORDERBY_VALUES)), orderby: v.optional(v["enum"](ORDERBY_VALUES)),
page: v.optional(v.pipe(v.number(), v.minValue(1))), page: v.optional(v.pipe(v.number(), v.minValue(1))),
parent: v.optional(v.array(v.pipe(v.number(), v.integer()))), parent: v.optional(v.array(v.pipe(v.number(), v.integer()))),
parent_exclude: v.optional(v.array(v.pipe(v.number(), v.integer()))), parent_exclude: v.optional(v.array(v.pipe(v.number(), v.integer()))),
per_page: v.optional(v.pipe(v.number(), v.minValue(0), v.maxValue(100))), per_page: v.optional(v.pipe(v.number(), v.minValue(0), v.maxValue(100))),
rating: v.optional(v.array(v.enum(RATINGS))), rating: v.optional(v.array(v["enum"](RATINGS))),
search: v.optional(v.string()), search: v.optional(v.string()),
sku: v.optional(v.string()), sku: v.optional(v.string()),
slug: v.optional(v.string()), slug: v.optional(v.string()),
stock_status: v.optional(v.array(v.enum(STOCK_STATUSES))), stock_status: v.optional(v.array(v["enum"](STOCK_STATUSES))),
tag: v.optional(v.string()), tag: v.optional(v.string()),
tag_operator: v.optional(v.enum(TAG_OPERATORS)), tag_operator: v.optional(v["enum"](TAG_OPERATORS)),
type: v.optional(v.enum(PRODUCT_TYPES)), type: v.optional(v["enum"](PRODUCT_TYPES)),
}); });
export const WCProductSchema = v.object({ export const WCProductSchema = v.object({
@ -70,7 +70,7 @@ export const WCProductSchema = v.object({
), ),
description: v.string(), description: v.string(),
extensions: v.unknown(), extensions: v.unknown(),
has_options: v.boolean(), has_options: v["boolean"](),
id: v.number(), id: v.number(),
images: v.array( images: v.array(
v.object({ v.object({
@ -83,12 +83,12 @@ export const WCProductSchema = v.object({
thumbnail: v.string(), thumbnail: v.string(),
}), }),
), ),
is_in_stock: v.boolean(), is_in_stock: v["boolean"](),
is_on_backorder: v.boolean(), is_on_backorder: v["boolean"](),
is_purchasable: v.boolean(), is_purchasable: v["boolean"](),
low_stock_remaining: v.union([v.number(), v.null()]), low_stock_remaining: v.union([v.number(), v["null"]()]),
name: v.string(), name: v.string(),
on_sale: v.boolean(), on_sale: v["boolean"](),
parent: v.number(), parent: v.number(),
permalink: v.string(), permalink: v.string(),
price_html: v.string(), price_html: v.string(),
@ -109,7 +109,7 @@ export const WCProductSchema = v.object({
short_description: v.string(), short_description: v.string(),
sku: v.string(), sku: v.string(),
slug: v.string(), slug: v.string(),
sold_individually: v.boolean(), sold_individually: v["boolean"](),
tags: v.array(v.string()), tags: v.array(v.string()),
type: v.string(), type: v.string(),
variation: v.unknown(), variation: v.unknown(),

View file

@ -14,7 +14,7 @@ export const WCV3OrdersCouponLineSchema = v.object({
discount: v.string(), discount: v.string(),
discount_tax: v.string(), discount_tax: v.string(),
discount_type: v.string(), discount_type: v.string(),
free_shipping: v.boolean(), free_shipping: v["boolean"](),
id: v.pipe(v.number(), v.integer()), id: v.pipe(v.number(), v.integer()),
meta_data: v.array(WCV3OrdersCouponLineMetaDataSchema), meta_data: v.array(WCV3OrdersCouponLineMetaDataSchema),
nominal_amount: v.number(), nominal_amount: v.number(),
@ -37,7 +37,7 @@ export const WCV3OrdersFeeLineSchema = v.object({
meta_data: v.array(WCV3OrdersFeeLineMetaDataSchema), meta_data: v.array(WCV3OrdersFeeLineMetaDataSchema),
name: v.string(), name: v.string(),
tax_class: v.string(), tax_class: v.string(),
tax_status: v.enum(TAX_STATUSES), tax_status: v["enum"](TAX_STATUSES),
taxes: v.array(WCV3OrdersFeeLineTaxSchema), taxes: v.array(WCV3OrdersFeeLineTaxSchema),
total: v.string(), total: v.string(),
total_tax: v.string(), total_tax: v.string(),
@ -88,7 +88,7 @@ export const WCV3OrdersLineItemSchema = v.object({
image: v.optional(WCV3OrdersLineItemImageSchema), image: v.optional(WCV3OrdersLineItemImageSchema),
meta_data: v.optional(v.array(WCV3OrdersLineItemMetaDataSchema)), meta_data: v.optional(v.array(WCV3OrdersLineItemMetaDataSchema)),
name: v.optional(v.string()), name: v.optional(v.string()),
parent_name: v.optional(v.union([v.string(), v.null()])), parent_name: v.optional(v.union([v.string(), v["null"]()])),
price: v.optional(v.number()), price: v.optional(v.number()),
product_id: v.optional(v.pipe(v.number(), v.integer())), product_id: v.optional(v.pipe(v.number(), v.integer())),
quantity: v.optional(v.pipe(v.number(), v.integer())), quantity: v.optional(v.pipe(v.number(), v.integer())),
@ -116,14 +116,14 @@ export const WCV3OrdersArgsSchema = v.object({
customer_note: v.optional(v.string()), customer_note: v.optional(v.string()),
fee_lines: v.optional(v.array(WCV3OrdersFeeLineSchema)), fee_lines: v.optional(v.array(WCV3OrdersFeeLineSchema)),
line_items: v.optional(v.array(WCV3OrdersLineItemSchema)), line_items: v.optional(v.array(WCV3OrdersLineItemSchema)),
manual_update: v.optional(v.boolean()), manual_update: v.optional(v["boolean"]()),
parent_id: v.optional(v.pipe(v.number(), v.integer())), parent_id: v.optional(v.pipe(v.number(), v.integer())),
payment_method: v.optional(v.string()), payment_method: v.optional(v.string()),
payment_method_title: v.optional(v.string()), payment_method_title: v.optional(v.string()),
set_paid: v.optional(v.boolean()), set_paid: v.optional(v["boolean"]()),
shipping: v.optional(WCStoreShippingAddressSchema), shipping: v.optional(WCStoreShippingAddressSchema),
shipping_lines: v.optional(v.array(WCV3OrdersShippingLineSchema)), shipping_lines: v.optional(v.array(WCV3OrdersShippingLineSchema)),
status: v.optional(v.enum(ORDER_STATUSES)), status: v.optional(v["enum"](ORDER_STATUSES)),
transaction_id: v.optional(v.string()), transaction_id: v.optional(v.string()),
}); });
@ -139,37 +139,37 @@ export const WCV3OrderSchema = v.object({
customer_ip_address: v.string(), customer_ip_address: v.string(),
customer_note: v.string(), customer_note: v.string(),
customer_user_agent: v.string(), customer_user_agent: v.string(),
date_completed: v.union([v.string(), v.null()]), date_completed: v.union([v.string(), v["null"]()]),
date_completed_gmt: v.union([v.string(), v.null()]), date_completed_gmt: v.union([v.string(), v["null"]()]),
// Date // Date
date_created: v.string(), date_created: v.string(),
date_created_gmt: v.string(), date_created_gmt: v.string(),
date_modified: v.string(), date_modified: v.string(),
date_modified_gmt: v.string(), date_modified_gmt: v.string(),
date_paid: v.union([v.string(), v.null()]), date_paid: v.union([v.string(), v["null"]()]),
date_paid_gmt: v.union([v.string(), v.null()]), date_paid_gmt: v.union([v.string(), v["null"]()]),
discount_tax: v.string(), discount_tax: v.string(),
discount_total: v.string(), discount_total: v.string(),
fee_lines: v.array(WCV3OrdersFeeLineSchema), fee_lines: v.array(WCV3OrdersFeeLineSchema),
id: v.pipe(v.number(), v.integer()), id: v.pipe(v.number(), v.integer()),
is_editable: v.boolean(), is_editable: v["boolean"](),
line_items: v.array(WCV3OrdersLineItemSchema), line_items: v.array(WCV3OrdersLineItemSchema),
meta_data: v.unknown(), meta_data: v.unknown(),
needs_payment: v.boolean(), needs_payment: v["boolean"](),
needs_processing: v.boolean(), needs_processing: v["boolean"](),
number: v.string(), number: v.string(),
order_key: v.string(), order_key: v.string(),
parent_id: v.pipe(v.number(), v.integer()), parent_id: v.pipe(v.number(), v.integer()),
payment_method: v.string(), payment_method: v.string(),
payment_method_title: v.string(), payment_method_title: v.string(),
payment_url: v.string(), payment_url: v.string(),
prices_include_tax: v.boolean(), prices_include_tax: v["boolean"](),
refunds: v.array(v.unknown()), refunds: v.array(v.unknown()),
shipping: WCStoreShippingAddressSchema, shipping: WCStoreShippingAddressSchema,
shipping_lines: v.array(WCV3OrdersShippingLineSchema), shipping_lines: v.array(WCV3OrdersShippingLineSchema),
shipping_tax: v.string(), shipping_tax: v.string(),
shipping_total: v.string(), shipping_total: v.string(),
status: v.enum(ORDER_STATUSES), status: v["enum"](ORDER_STATUSES),
tax_lines: v.array(v.unknown()), tax_lines: v.array(v.unknown()),
total: v.string(), total: v.string(),
total_tax: v.string(), total_tax: v.string(),

View file

@ -21,20 +21,20 @@ export const WCV3ProductsArgsSchema = v.object({
// Date ISO8601 // Date ISO8601
after: v.optional(v.string()), after: v.optional(v.string()),
attribute: v.optional(v.string()), attribute: v.optional(v.string()),
attribute_relation: v.optional(v.enum(ATTRIBUTES_RELATIONS)), attribute_relation: v.optional(v["enum"](ATTRIBUTES_RELATIONS)),
attribute_term: v.optional(v.string()), attribute_term: v.optional(v.string()),
attributes: v.optional(v.array(v.unknown())), attributes: v.optional(v.array(v.unknown())),
// Date ISO8601 // Date ISO8601
before: v.optional(v.string()), before: v.optional(v.string()),
catalog_visibility: v.optional(v.enum(CATALOG_VISIBILITIES)), catalog_visibility: v.optional(v["enum"](CATALOG_VISIBILITIES)),
category: v.optional(v.string()), category: v.optional(v.string()),
category_operator: v.optional(v.enum(CATEGORY_OPERATORS)), category_operator: v.optional(v["enum"](CATEGORY_OPERATORS)),
context: v.optional(v.enum(PRODUCTS_CONTEXTES)), context: v.optional(v["enum"](PRODUCTS_CONTEXTES)),
date_column: v.optional(v.enum(DATE_COLUMN_VALUES)), date_column: v.optional(v["enum"](DATE_COLUMN_VALUES)),
dates_are_gmt: v.optional(v.boolean()), dates_are_gmt: v.optional(v["boolean"]()),
exclude: v.optional(v.array(v.pipe(v.number(), v.integer()))), exclude: v.optional(v.array(v.pipe(v.number(), v.integer()))),
exclude_meta: v.optional(v.array(v.string())), exclude_meta: v.optional(v.array(v.string())),
featured: v.optional(v.boolean()), featured: v.optional(v["boolean"]()),
include: v.optional(v.array(v.pipe(v.number(), v.integer()))), include: v.optional(v.array(v.pipe(v.number(), v.integer()))),
include_meta: v.optional(v.array(v.string())), include_meta: v.optional(v.array(v.string())),
max_price: v.optional(v.string()), max_price: v.optional(v.string()),
@ -44,24 +44,24 @@ export const WCV3ProductsArgsSchema = v.object({
// Date ISO8601 // Date ISO8601
modified_before: v.optional(v.string()), modified_before: v.optional(v.string()),
offset: v.optional(v.pipe(v.number(), v.integer())), offset: v.optional(v.pipe(v.number(), v.integer())),
on_sale: v.optional(v.boolean()), on_sale: v.optional(v["boolean"]()),
order: v.optional(v.enum(ORDER_VALUES)), order: v.optional(v["enum"](ORDER_VALUES)),
orderby: v.optional(v.enum(ORDERBY_VALUES)), orderby: v.optional(v["enum"](ORDERBY_VALUES)),
page: v.optional(v.pipe(v.number(), v.minValue(1))), page: v.optional(v.pipe(v.number(), v.minValue(1))),
parent: v.optional(v.array(v.pipe(v.number(), v.integer()))), parent: v.optional(v.array(v.pipe(v.number(), v.integer()))),
parent_exclude: v.optional(v.array(v.pipe(v.number(), v.integer()))), parent_exclude: v.optional(v.array(v.pipe(v.number(), v.integer()))),
per_page: v.optional(v.pipe(v.number(), v.minValue(0), v.maxValue(100))), per_page: v.optional(v.pipe(v.number(), v.minValue(0), v.maxValue(100))),
rating: v.optional(v.array(v.enum(RATINGS))), rating: v.optional(v.array(v["enum"](RATINGS))),
search: v.optional(v.string()), search: v.optional(v.string()),
search_sku: v.optional(v.string()), search_sku: v.optional(v.string()),
shipping_class: v.optional(v.string()), shipping_class: v.optional(v.string()),
sku: v.optional(v.string()), sku: v.optional(v.string()),
slug: v.optional(v.string()), slug: v.optional(v.string()),
status: v.optional(v.enum(PRODUCT_STATUTES)), status: v.optional(v["enum"](PRODUCT_STATUTES)),
stock_status: v.optional(v.array(v.enum(STOCK_STATUSES))), stock_status: v.optional(v.array(v["enum"](STOCK_STATUSES))),
tag: v.optional(v.string()), tag: v.optional(v.string()),
tag_operator: v.optional(v.enum(TAG_OPERATORS)), tag_operator: v.optional(v["enum"](TAG_OPERATORS)),
type: v.optional(v.enum(PRODUCT_TYPES)), type: v.optional(v["enum"](PRODUCT_TYPES)),
}); });
export const WCV3ProductDownloadsSchema = v.object({ export const WCV3ProductDownloadsSchema = v.object({
@ -99,8 +99,8 @@ export const WCV3ProductAttributeSchema = v.object({
name: v.string(), name: v.string(),
options: v.array(v.string()), options: v.array(v.string()),
position: v.pipe(v.number(), v.integer()), position: v.pipe(v.number(), v.integer()),
variation: v.boolean(), variation: v["boolean"](),
visible: v.boolean(), visible: v["boolean"](),
}); });
export const WCV3ProductDefaultAttributeSchema = v.object({ export const WCV3ProductDefaultAttributeSchema = v.object({
id: v.pipe(v.number(), v.integer()), id: v.pipe(v.number(), v.integer()),
@ -116,46 +116,46 @@ export const WCV3ProductMetaDataSchema = v.object({
export const WCV3ProductSchema = v.object({ export const WCV3ProductSchema = v.object({
attributes: v.array(WCV3ProductAttributeSchema), attributes: v.array(WCV3ProductAttributeSchema),
average_rating: v.string(), average_rating: v.string(),
backordered: v.boolean(), backordered: v["boolean"](),
backorders: v.enum(BACKORDERS_SETTINGS), backorders: v["enum"](BACKORDERS_SETTINGS),
backorders_allowed: v.boolean(), backorders_allowed: v["boolean"](),
button_text: v.string(), button_text: v.string(),
catalog_visibility: v.enum(CATALOG_VISIBILITIES), catalog_visibility: v["enum"](CATALOG_VISIBILITIES),
categories: v.array(WCV3ProductCategorySchema), categories: v.array(WCV3ProductCategorySchema),
cross_sell_ids: v.array(v.pipe(v.number(), v.integer())), cross_sell_ids: v.array(v.pipe(v.number(), v.integer())),
date_created: v.string(), date_created: v.string(),
date_created_gmt: v.string(), date_created_gmt: v.string(),
date_modified: v.string(), date_modified: v.string(),
date_modified_gmt: v.string(), date_modified_gmt: v.string(),
date_on_sale_from: v.union([v.string(), v.null()]), date_on_sale_from: v.union([v.string(), v["null"]()]),
date_on_sale_from_gmt: v.union([v.string(), v.null()]), date_on_sale_from_gmt: v.union([v.string(), v["null"]()]),
date_on_sale_to: v.union([v.string(), v.null()]), date_on_sale_to: v.union([v.string(), v["null"]()]),
date_on_sale_to_gmt: v.union([v.string(), v.null()]), date_on_sale_to_gmt: v.union([v.string(), v["null"]()]),
default_attributes: v.array(WCV3ProductDefaultAttributeSchema), default_attributes: v.array(WCV3ProductDefaultAttributeSchema),
description: v.string(), description: v.string(),
dimensions: WCV3ProductDimensionsSchema, dimensions: WCV3ProductDimensionsSchema,
download_expiry: v.number(), download_expiry: v.number(),
download_limit: v.number(), download_limit: v.number(),
downloadable: v.boolean(), downloadable: v["boolean"](),
downloads: v.array(WCV3ProductDownloadsSchema), downloads: v.array(WCV3ProductDownloadsSchema),
external_url: v.string(), external_url: v.string(),
featured: v.boolean(), featured: v["boolean"](),
generated_slug: v.optional(v.string()), generated_slug: v.optional(v.string()),
global_unique_id: v.string(), global_unique_id: v.string(),
grouped_products: v.array(v.pipe(v.number(), v.integer())), grouped_products: v.array(v.pipe(v.number(), v.integer())),
has_options: v.boolean(), has_options: v["boolean"](),
id: v.pipe(v.number(), v.integer()), id: v.pipe(v.number(), v.integer()),
// NOTE: Ajouté par mes soins // NOTE: Ajouté par mes soins
image_repos: v.union([v.string(), v.null()]), image_repos: v.union([v.string(), v["null"]()]),
// NOTE: Ajouté par mes soins // NOTE: Ajouté par mes soins
image_survol: v.union([v.string(), v.null()]), image_survol: v.union([v.string(), v["null"]()]),
images: v.array(WCV3ProductImageSchema), images: v.array(WCV3ProductImageSchema),
low_stock_amount: v.union([v.number(), v.null()]), low_stock_amount: v.union([v.number(), v["null"]()]),
manage_stock: v.boolean(), manage_stock: v["boolean"](),
menu_order: v.pipe(v.number(), v.integer()), menu_order: v.pipe(v.number(), v.integer()),
meta_data: v.array(WCV3ProductMetaDataSchema), meta_data: v.array(WCV3ProductMetaDataSchema),
name: v.string(), name: v.string(),
on_sale: v.boolean(), on_sale: v["boolean"](),
parent_id: v.pipe(v.number(), v.integer()), parent_id: v.pipe(v.number(), v.integer()),
permalink: v.pipe(v.string(), v.url()), permalink: v.pipe(v.string(), v.url()),
permalink_template: v.optional(v.string()), permalink_template: v.optional(v.string()),
@ -163,32 +163,32 @@ export const WCV3ProductSchema = v.object({
price: v.string(), price: v.string(),
price_html: v.string(), price_html: v.string(),
prix_maximal: v.string(), prix_maximal: v.string(),
purchasable: v.boolean(), purchasable: v["boolean"](),
purchase_note: v.string(), purchase_note: v.string(),
rating_count: v.pipe(v.number(), v.integer()), rating_count: v.pipe(v.number(), v.integer()),
regular_price: v.string(), regular_price: v.string(),
related_ids: v.array(v.pipe(v.number(), v.integer())), related_ids: v.array(v.pipe(v.number(), v.integer())),
reviews_allowed: v.boolean(), reviews_allowed: v["boolean"](),
sale_price: v.string(), sale_price: v.string(),
shipping_class: v.string(), shipping_class: v.string(),
shipping_class_id: v.pipe(v.number(), v.integer()), shipping_class_id: v.pipe(v.number(), v.integer()),
shipping_required: v.boolean(), shipping_required: v["boolean"](),
shipping_taxable: v.boolean(), shipping_taxable: v["boolean"](),
short_description: v.string(), short_description: v.string(),
sku: v.string(), sku: v.string(),
slug: v.string(), slug: v.string(),
sold_individually: v.boolean(), sold_individually: v["boolean"](),
status: v.enum(PRODUCT_STATUTES), status: v["enum"](PRODUCT_STATUTES),
stock_quantity: v.union([v.number(), v.null()]), stock_quantity: v.union([v.number(), v["null"]()]),
stock_status: v.enum(STOCK_STATUSES), stock_status: v["enum"](STOCK_STATUSES),
tags: v.array(WCV3ProductTagSchema), tags: v.array(WCV3ProductTagSchema),
tax_class: v.string(), tax_class: v.string(),
tax_status: v.enum(TAX_STATUTES), tax_status: v["enum"](TAX_STATUTES),
total_sales: v.pipe(v.number(), v.integer()), total_sales: v.pipe(v.number(), v.integer()),
type: v.enum(PRODUCT_TYPES), type: v["enum"](PRODUCT_TYPES),
upsell_ids: v.array(v.pipe(v.number(), v.integer())), upsell_ids: v.array(v.pipe(v.number(), v.integer())),
variations: v.array(v.pipe(v.number(), v.integer())), variations: v.array(v.pipe(v.number(), v.integer())),
virtual: v.boolean(), virtual: v["boolean"](),
weight: v.string(), weight: v.string(),
}); });

View file

@ -5,7 +5,7 @@ import * as v from "valibot";
import { TYPES_MESSAGES } from "../../constantes/messages.ts"; import { TYPES_MESSAGES } from "../../constantes/messages.ts";
import { WCStoreCartItemSchema } from "./api/cart.ts"; import { WCStoreCartItemSchema } from "./api/cart.ts";
export const TypesMessagesSchema = v.enum(TYPES_MESSAGES); export const TypesMessagesSchema = v["enum"](TYPES_MESSAGES);
export const MessageMajBoutonPanierDonneesSchema = v.object({ export const MessageMajBoutonPanierDonneesSchema = v.object({
quantiteProduits: v.number(), quantiteProduits: v.number(),

View file

@ -35,4 +35,4 @@ export const getSessionStorageByKey = <S extends GenericSchema>(key: string, sch
export const setSessionStorageByKey = export const setSessionStorageByKey =
<S extends GenericSchema>(key: string, schema: S) => <S extends GenericSchema>(key: string, schema: S) =>
(value: unknown): Either<DOMException | ValiError<S>, InferOutput<S>> => (value: unknown): Either<DOMException | ValiError<S>, InferOutput<S>> =>
safeSchemaParse(value, schema).chain((v) => eitherSetSessionStorage(key, v)); safeSchemaParse(value, schema).chain(v => eitherSetSessionStorage(key, v));

View file

@ -1 +1 @@
export type Constructor<T> = new (...args: Array<unknown>) => T; export type Constructor<T> = new(...args: Array<unknown>) => T;

View file

@ -7,9 +7,7 @@ import { CleNonTrouveError } from "./erreurs";
/** /**
* TODO * TODO
*/ */
export const propEither = export const propEither = <T, K extends keyof T>(cle: K) => (donnees: T): Either<CleNonTrouveError, T[K]> =>
<T, K extends keyof T>(cle: K) => Maybe.fromNullable(D.getUnsafe(donnees, cle)).toEither(
(donnees: T): Either<CleNonTrouveError, T[K]> => new CleNonTrouveError(`La clé « ${String(cle)} » n'a pas été trouvé dans l'objet.`),
Maybe.fromNullable(D.getUnsafe(donnees, cle)).toEither( );
new CleNonTrouveError(`La clé « ${String(cle)} » n'a pas été trouvé dans l'objet.`),
);

View file

@ -12,6 +12,5 @@ export const safeSchemaParse = <Schema extends GenericSchema>(
): Either<ValiError<Schema>, InferOutput<Schema>> => Either.encase(() => parse(schema, valeur)); ): Either<ValiError<Schema>, InferOutput<Schema>> => Either.encase(() => parse(schema, valeur));
export const safeSchemaParseCurried = export const safeSchemaParseCurried =
<S extends GenericSchema>(schema: S) => <S extends GenericSchema>(schema: S) => (valeur: unknown): Either<ValiError<S>, InferOutput<S>> =>
(valeur: unknown): Either<ValiError<S>, InferOutput<S>> =>
Either.encase(() => parse(schema, valeur)); Either.encase(() => parse(schema, valeur));

View file

@ -8,15 +8,16 @@ import { ValiError } from "valibot";
import type { AnySchema } from "valibot"; import type { AnySchema } from "valibot";
import type { WCStoreBillingAddress, WCStoreShippingAddress } from "../lib/types/api/adresses.ts"; import type { WCStoreBillingAddress, WCStoreShippingAddress } from "../lib/types/api/adresses.ts";
import type { WCStoreCart, WCStoreShippingRate, WCStoreShippingRateShippingRate } from "../lib/types/api/cart.ts";
import type { WCStoreCartUpdateCustomerArgs } from "../lib/types/api/cart-update-customer.ts"; import type { WCStoreCartUpdateCustomerArgs } from "../lib/types/api/cart-update-customer.ts";
import type { WCStoreCart, WCStoreShippingRate, WCStoreShippingRateShippingRate } from "../lib/types/api/cart.ts";
import type { WCV3Order, WCV3OrdersArgs } from "../lib/types/api/v3/orders.ts"; import type { WCV3Order, WCV3OrdersArgs } from "../lib/types/api/v3/orders.ts";
import type { GenericPageState } from "../lib/types/pages.ts"; import type { GenericPageState } from "../lib/types/pages.ts";
import type { FetchErrors, HttpCodeErrors } from "../lib/types/reseau.ts"; import type { FetchErrors, HttpCodeErrors } from "../lib/types/reseau.ts";
import { Console, Effect, Stream } from "effect";
import { ReadonlyRecord } from "effect/Record";
import { ROUTE_API_MAJ_CLIENT, ROUTE_API_NOUVELLE_COMMANDES } from "../constantes/api.ts"; import { ROUTE_API_MAJ_CLIENT, ROUTE_API_NOUVELLE_COMMANDES } from "../constantes/api.ts";
import { ATTRIBUT_CHARGEMENT, ATTRIBUT_LIVRAISON_VALIDEE } from "../constantes/dom.ts"; import { ATTRIBUT_CHARGEMENT, ATTRIBUT_LIVRAISON_VALIDEE } from "../constantes/dom.ts";
import { NOM_CANAL_REVALIDATION_LIVRAISON } from "../constantes/messages.ts";
import { import {
ERREUR_ADRESSE_GENERIQUE, ERREUR_ADRESSE_GENERIQUE,
ERREUR_ADRESSE_MAUVAIS_CODE_POSTAL, ERREUR_ADRESSE_MAUVAIS_CODE_POSTAL,
@ -24,6 +25,7 @@ import {
ERREUR_GENERIQUE_RESEAU, ERREUR_GENERIQUE_RESEAU,
ERREUR_GENERIQUE_SOUMISSION_ADRESSES, ERREUR_GENERIQUE_SOUMISSION_ADRESSES,
} from "../constantes/messages-utilisateur.ts"; } from "../constantes/messages-utilisateur.ts";
import { NOM_CANAL_REVALIDATION_LIVRAISON } from "../constantes/messages.ts";
import { estErreurFetch, estErreurHttp, setButtonLoadingState } from "../lib/dom.ts"; import { estErreurFetch, estErreurHttp, setButtonLoadingState } from "../lib/dom.ts";
import { reporteEtJournaliseErreur } from "../lib/erreurs.ts"; import { reporteEtJournaliseErreur } from "../lib/erreurs.ts";
import { ErreurAdresseInvalide } from "../lib/erreurs/adresses.ts"; import { ErreurAdresseInvalide } from "../lib/erreurs/adresses.ts";
@ -36,15 +38,13 @@ import { emetUniqueMessageBroadcastChannel } from "../lib/messages.ts";
import { diviseParCent } from "../lib/nombres.ts"; import { diviseParCent } from "../lib/nombres.ts";
import { newPartialResponse, prefilledPostBackend, safeFetch, traiteErreursBackendWooCommerce } from "../lib/reseau.ts"; import { newPartialResponse, prefilledPostBackend, safeFetch, traiteErreursBackendWooCommerce } from "../lib/reseau.ts";
import { find, first } from "../lib/safe-arrays.ts"; import { find, first } from "../lib/safe-arrays.ts";
import { WCStoreCartSchema } from "../lib/schemas/api/cart.ts";
import { WCStoreCartUpdateCustomerArgsSchema } from "../lib/schemas/api/cart-update-customer.ts"; import { WCStoreCartUpdateCustomerArgsSchema } from "../lib/schemas/api/cart-update-customer.ts";
import { WCStoreCartSchema } from "../lib/schemas/api/cart.ts";
import { estWCAddressError } from "../lib/schemas/api/erreurs.ts"; import { estWCAddressError } from "../lib/schemas/api/erreurs.ts";
import { WCV3OrdersArgsSchema, WCV3OrderSchema } from "../lib/schemas/api/v3/orders.ts"; import { WCV3OrdersArgsSchema, WCV3OrderSchema } from "../lib/schemas/api/v3/orders.ts";
import { safeSchemaParse } from "../lib/validation.ts"; import { safeSchemaParse } from "../lib/validation.ts";
import { E } from "./scripts-page-panier-elements.ts"; import { E } from "./scripts-page-panier-elements.ts";
import { getShippingRatesLS } from "./scripts-page-panier-local-storage.ts"; import { getShippingRatesLS } from "./scripts-page-panier-local-storage.ts";
import { ReadonlyRecord } from "effect/Record";
import { Console, Effect, Stream } from "effect";
type Addresses = { type Addresses = {
billing_address: WCStoreBillingAddress; billing_address: WCStoreBillingAddress;
@ -60,7 +60,7 @@ const postBackend = prefilledPostBackend(ETATS_PAGE.nonce, ETATS_PAGE.authString
* *
* @returns Un `Effect` ne retournant rien et ne pouvant échouer. * @returns Un `Effect` ne retournant rien et ne pouvant échouer.
*/ */
export const initCartFormEventEmitters = Effect.fn("initCartFormEventEmitters")(function* () { export const initCartFormEventEmitters = Effect.fn("initCartFormEventEmitters")(function*() {
return yield* pipe( return yield* pipe(
Stream.fromEventListener(E.FORMULAIRE_PANIER, "change"), Stream.fromEventListener(E.FORMULAIRE_PANIER, "change"),
Stream.tap((event: Event) => { Stream.tap((event: Event) => {
@ -125,7 +125,7 @@ export const initShippingCalculationButton = (): void => {
.fromFalsy(E.FORMULAIRE_PANIER.checkValidity()) .fromFalsy(E.FORMULAIRE_PANIER.checkValidity())
// Ne fais rien si la livraison a déjà été validée // Ne fais rien si la livraison a déjà été validée
.chainNullable((): boolean | undefined => .chainNullable((): boolean | undefined =>
E.BOUTON_ACTIONS_FORMULAIRE.hasAttribute(ATTRIBUT_LIVRAISON_VALIDEE) ? undefined : true, E.BOUTON_ACTIONS_FORMULAIRE.hasAttribute(ATTRIBUT_LIVRAISON_VALIDEE) ? undefined : true
) )
.ifJust((): void => { .ifJust((): void => {
event.preventDefault(); event.preventDefault();
@ -133,8 +133,8 @@ export const initShippingCalculationButton = (): void => {
/** Les données du Formulaire transformées pour la requête vers le Backend. */ /** Les données du Formulaire transformées pour la requête vers le Backend. */
const formArgs: WCStoreCartUpdateCustomerArgs = pipe( const formArgs: WCStoreCartUpdateCustomerArgs = pipe(
Object.fromEntries(new FormData(E.FORMULAIRE_PANIER)) as Record<string, string>, Object.fromEntries(new FormData(E.FORMULAIRE_PANIER)) as Record<string, string>,
(fields) => dictMap(fields, stringTrim), fields => dictMap(fields, stringTrim),
(fields) => getAddressesFromForm(fields, E.BOUTON_SEPARATION_ADRESSES.checked), fields => getAddressesFromForm(fields, E.BOUTON_SEPARATION_ADRESSES.checked),
); );
// Réalise la requête et traite sa réponse // Réalise la requête et traite sa réponse
@ -142,7 +142,7 @@ export const initShippingCalculationButton = (): void => {
// Désactive le Bouton pour empêcher des requêtes concurrentes // Désactive le Bouton pour empêcher des requêtes concurrentes
.ifRight((): void => setButtonLoadingState(E.BOUTON_ACTIONS_FORMULAIRE, true)) .ifRight((): void => setButtonLoadingState(E.BOUTON_ACTIONS_FORMULAIRE, true))
.chain((args: WCStoreCartUpdateCustomerArgs) => .chain((args: WCStoreCartUpdateCustomerArgs) =>
safeFetch(postBackend(ROUTE_API_MAJ_CLIENT, JSON.stringify(args), false)), safeFetch(postBackend(ROUTE_API_MAJ_CLIENT, JSON.stringify(args), false))
) )
.chain((rs: Response) => .chain((rs: Response) =>
EitherAsync<ErreurAdresseInvalide | HttpCodeErrors, unknown>( EitherAsync<ErreurAdresseInvalide | HttpCodeErrors, unknown>(
@ -151,18 +151,18 @@ export const initShippingCalculationButton = (): void => {
.with({ status: 200 }, (rs): unknown => rs.body) .with({ status: 200 }, (rs): unknown => rs.body)
.with( .with(
{ {
body: P.when((body) => estWCAddressError(body)), body: P.when(body => estWCAddressError(body)),
status: 400, status: 400,
}, },
(rs): never => throwE(new ErreurAdresseInvalide(rs.body.data.params)), (rs): never => throwE(new ErreurAdresseInvalide(rs.body.data.params)),
) )
.otherwise((rs): never => throwE(traiteErreursBackendWooCommerce(rs))), .otherwise((rs): never => throwE(traiteErreursBackendWooCommerce(rs))),
), )
) )
.chain((b: unknown) => EitherAsync.liftEither(safeSchemaParse(b, WCStoreCartSchema))) .chain((b: unknown) => EitherAsync.liftEither(safeSchemaParse(b, WCStoreCartSchema)))
.ifRight((cart: WCStoreCart): void => { .ifRight((cart: WCStoreCart): void => {
/** La méthode de livraison sélectionnée dans le SessionStorage */ /** La méthode de livraison sélectionnée dans le SessionStorage */
const oldSelectedRateLS = getShippingRatesLS().chain(find((sr) => sr.selected)); const oldSelectedRateLS = getShippingRatesLS().chain(find(sr => sr.selected));
/* Les méthodes de livraison mises à jour avec le nouveau choix de l'Utilisateur. */ /* Les méthodes de livraison mises à jour avec le nouveau choix de l'Utilisateur. */
const updatedRates = first(cart.shipping_rates) const updatedRates = first(cart.shipping_rates)
@ -171,7 +171,7 @@ export const initShippingCalculationButton = (): void => {
srs.map((sr: WCStoreShippingRateShippingRate, index: number) => { srs.map((sr: WCStoreShippingRateShippingRate, index: number) => {
// Sélectionne la nouvelle méthode demandée OU la première si le SessionStorage n'a pas été défini // Sélectionne la nouvelle méthode demandée OU la première si le SessionStorage n'a pas été défini
oldSelectedRateLS.caseOf({ oldSelectedRateLS.caseOf({
Just: (sm) => { Just: sm => {
sr.selected = sr.method_id === sm.method_id; sr.selected = sr.method_id === sm.method_id;
}, },
Nothing: () => { Nothing: () => {
@ -183,7 +183,7 @@ export const initShippingCalculationButton = (): void => {
sr.price = diviseParCent(sr.price); sr.price = diviseParCent(sr.price);
return sr; return sr;
}), })
) )
.orDefault([]); .orDefault([]);
@ -191,13 +191,14 @@ export const initShippingCalculationButton = (): void => {
window.dispatchEvent(createUpdatedShippingRatesEvent(updatedRates, true)); window.dispatchEvent(createUpdatedShippingRatesEvent(updatedRates, true));
// Met à jour les Totaux // Met à jour les Totaux
const newShippingPrice = updatedRates.find((m) => m.selected)?.price ?? 0; const newShippingPrice = updatedRates.find(m => m.selected)?.price ?? 0;
const newTotals = { const newTotals = {
...cart.totals, ...cart.totals,
total_discount: diviseParCent(cart.totals.total_discount), total_discount: diviseParCent(cart.totals.total_discount),
total_items: diviseParCent(cart.totals.total_items), total_items: diviseParCent(cart.totals.total_items),
total_price: total_price: diviseParCent(cart.totals.total_items)
diviseParCent(cart.totals.total_items) - diviseParCent(cart.totals.total_discount) + newShippingPrice, - diviseParCent(cart.totals.total_discount)
+ newShippingPrice,
total_shipping: newShippingPrice, total_shipping: newShippingPrice,
}; };
@ -222,10 +223,10 @@ export const initShippingCalculationButton = (): void => {
match(e.problemes) match(e.problemes)
.when( .when(
// TODO: Créer une fonction utilitaire // TODO: Créer une fonction utilitaire
(p) => p =>
pipe( pipe(
dictValues(p), dictValues(p),
arrayFind((c) => c === "The provided postcode is not valid"), arrayFind(c => c === "The provided postcode is not valid"),
), ),
// TODO: Créer une fonction utilitaire pour fixer le texte d'un message // TODO: Créer une fonction utilitaire pour fixer le texte d'un message
(): void => { (): void => {
@ -315,14 +316,14 @@ export const initOrderCreationButton = (): void => {
}; };
// Retire toute méthode de livraison invalide. // Retire toute méthode de livraison invalide.
formArgs.shipping_lines = formArgs.shipping_lines.filter((line) => line.method_id !== undefined); formArgs.shipping_lines = formArgs.shipping_lines.filter(line => line.method_id !== undefined);
// Réalise la requête et traite sa réponse // Réalise la requête et traite sa réponse
void EitherAsync.liftEither(safeSchemaParse(formArgs, WCV3OrdersArgsSchema)) void EitherAsync.liftEither(safeSchemaParse(formArgs, WCV3OrdersArgsSchema))
// Désactive le Bouton pour empêcher des requêtes concurrentes // Désactive le Bouton pour empêcher des requêtes concurrentes
.ifRight((): void => setButtonLoadingState(E.BOUTON_ACTIONS_FORMULAIRE, true)) .ifRight((): void => setButtonLoadingState(E.BOUTON_ACTIONS_FORMULAIRE, true))
.chain((args: WCV3OrdersArgs) => .chain((args: WCV3OrdersArgs) =>
safeFetch(postBackend(ROUTE_API_NOUVELLE_COMMANDES, JSON.stringify(args), true)), safeFetch(postBackend(ROUTE_API_NOUVELLE_COMMANDES, JSON.stringify(args), true))
) )
.chain((rs: Response) => .chain((rs: Response) =>
EitherAsync<HttpCodeErrors, unknown>( EitherAsync<HttpCodeErrors, unknown>(
@ -330,7 +331,7 @@ export const initOrderCreationButton = (): void => {
match(await newPartialResponse(rs)) match(await newPartialResponse(rs))
.with({ status: 201 }, (rs): unknown => rs.body) .with({ status: 201 }, (rs): unknown => rs.body)
.otherwise((rs): never => throwE(traiteErreursBackendWooCommerce(rs))), .otherwise((rs): never => throwE(traiteErreursBackendWooCommerce(rs))),
), )
) )
.chain((b: unknown) => EitherAsync.liftEither(safeSchemaParse(b, WCV3OrderSchema))) .chain((b: unknown) => EitherAsync.liftEither(safeSchemaParse(b, WCV3OrderSchema)))
.ifRight((order: WCV3Order): void => { .ifRight((order: WCV3Order): void => {
@ -342,9 +343,9 @@ export const initOrderCreationButton = (): void => {
// Redirige vers Stripe // Redirige vers Stripe
Maybe.fromNullable(new URL(`https://${window.location.host}/checkout`)) Maybe.fromNullable(new URL(`https://${window.location.host}/checkout`))
.ifJust((url) => url.searchParams.append("order_key", order.order_key)) .ifJust(url => url.searchParams.append("order_key", order.order_key))
.ifJust((url) => url.searchParams.append("order_id", String(order.id))) .ifJust(url => url.searchParams.append("order_id", String(order.id)))
.ifJust((url) => location.assign(url)); .ifJust(url => location.assign(url));
}) })
.ifLeft((err: FetchErrors | HttpCodeErrors | ValiError<AnySchema>): void => { .ifLeft((err: FetchErrors | HttpCodeErrors | ValiError<AnySchema>): void => {
match(err) match(err)

View file

@ -54,193 +54,34 @@ export const initialiseElementsCodePromo = (): void => {
codePromoPresent: recuperePresenceCodePromo(), codePromoPresent: recuperePresenceCodePromo(),
valeurCodePromo: recupereValeurCodePromo(), valeurCodePromo: recupereValeurCodePromo(),
}) })
// Un code promo doit être ajouté [
// Aucun code promo n'est déjà présent et une valeur acceptable existe // Un code promo doit être ajouté
.with( // Aucun code promo n'est déjà présent et une valeur acceptable existe
"with"
](
{ {
cible: P.when((cible: EventTarget | null) => cible: P.when((cible: EventTarget | null) =>
targetMatchesSelector<HTMLButtonElement>(cible, DOM_BOUTON_CODE_PROMO), targetMatchesSelector<HTMLButtonElement>(cible, DOM_BOUTON_CODE_PROMO)
), ),
codePromoPresent: false, codePromoPresent: false,
valeurCodePromo: P.string, valeurCodePromo: P.string,
}, },
({ valeurCodePromo }) => ({ valeurCodePromo }) => undefined,
void EitherAsync
// Vérifie le Schéma des arguments
.liftEither(safeSchemaParse({ code: valeurCodePromo }, WCStoreCartApplyCouponArgsSchema))
.ifRight(() => {
// Désactive le Bouton pour empêcher des requêtes concurrentes
E.BOUTON_CODE_PROMO.setAttribute(ATTRIBUT_DESACTIVE, "");
E.BOUTON_CODE_PROMO.setAttribute(ATTRIBUT_CHARGEMENT, "");
// Réinitialise le Message à l'Utilisateur
E.MESSAGE_CODE_PROMO.textContent = "";
// Lance un cycle d'animation sur le texte de chargement
lanceAnimationCycleLoading(E.BOUTON_CODE_PROMO, 500);
})
// Réalise la requête auprès du backend
.map((args: WCStoreCartApplyCouponArgs) =>
postBackend({
corps: JSON.stringify(args),
nonce: ETATS_PAGE.nonce,
route: ROUTE_API_APPLIQUE_COUPON,
}),
)
// Traite les cas d'Erreur
.chain((reponse: Response) =>
EitherAsync<ErreurCodePromoInvalide | ServerError, unknown>(async ({ throwE }) => {
const reponseSimplifiee: SimplifiedResponse = {
body: await reponse.json(),
status: reponse.status,
};
return match(reponseSimplifiee)
.with({ status: 500 }, () => throwE(new ServerError("500 Server Error")))
.with(
{
body: P.when(() => reponseEstCodeErreurWC(reponseSimplifiee, ERREUR_CODE_PROMO_INVALIDE)),
status: 400,
},
() => throwE(new ErreurCodePromoInvalide(recupereValeurCodePromo() ?? "")),
)
.with({ status: 200 }, () => reponseSimplifiee.body)
.run();
}),
)
// Vérifie le Schéma de la Réponse du backend
.chain((corpsReponse: unknown) => EitherAsync.liftEither(safeSchemaParse(corpsReponse, WCStoreCartSchema)))
// Déclenche les mises à jour du DOM avec les données du nouveau Panier
.ifRight((panier: WCStoreCart) => {
E.ENSEMBLE_CODE_PROMO.toggleAttribute(ATTRIBUT_CODE_PROMO_PRESENT);
E.CHAMP_CODE_PROMO.toggleAttribute(ATTRIBUT_DESACTIVE);
E.CHAMP_CODE_PROMO.value = panier.coupons[0]?.code ?? "";
E.BOUTON_CODE_PROMO.textContent = "Remove";
E.TOTAL_PANIER.textContent = pipe(
diviseParCent(panier.totals.total_price),
arrondisADeuxDecimales,
formateEnEuros,
);
E.TOTAL_REDUCTION_LIGNE.toggleAttribute(ATTRIBUT_HIDDEN);
E.TOTAL_REDUCTION_VALEUR.textContent = pipe(
diviseParCent(panier.totals.total_discount),
inverseNombre,
arrondisADeuxDecimales,
formateEnEuros,
);
window.dispatchEvent(CODE_PROMO_MAJ_EVENT);
// EmetUniqueMessageBroadcastChannel(NOM_CANAL_REVALIDATION_LIVRAISON, true);
})
.ifLeft((erreur) => {
// Rétablis le texte d'origine
E.BOUTON_CODE_PROMO.textContent = "Apply";
// Traite les Erreurs et affiche un Message à l'Utilisateur
match(erreur)
.with(P.instanceOf(ValiError), (e) => {
reporteErreur(e);
console.error("ValiError", e.issues);
})
.with(P.instanceOf(ErreurCodePromoInvalide), (e) => {
E.MESSAGE_CODE_PROMO.textContent = "This promo code does not exist.";
reporteErreur(e);
console.error(e);
})
.with(P.instanceOf(ServerError), (e) => {
E.MESSAGE_CODE_PROMO.textContent =
"Sorry, something went wrong! Please refresh the page and try again.";
reporteErreur(e);
console.error(e);
})
.with(P.instanceOf(TypeError), (e) => {
E.MESSAGE_CODE_PROMO.textContent =
"Sorry, something went wrong! Please refresh the page and try again.";
reporteErreur(e);
console.error(e);
})
.exhaustive();
})
.finally(() => {
// Désactive l'animation de chargement et rend le Bouton de nouveau cliquable
// TODO: Créer un type d'Événement ?
E.BOUTON_CODE_PROMO.removeAttribute(ATTRIBUT_CHARGEMENT);
E.BOUTON_CODE_PROMO.removeAttribute(ATTRIBUT_DESACTIVE);
})
.run(),
) )
// Un code promo doit être retiré [
// Un code promo est présent sous forme de chaîne // Un code promo doit être retiré
.with( // Un code promo est présent sous forme de chaîne
"with"
](
{ {
cible: P.when((cible) => targetMatchesSelector<HTMLButtonElement>(cible, DOM_BOUTON_CODE_PROMO)), cible: P.when(cible => targetMatchesSelector<HTMLButtonElement>(cible, DOM_BOUTON_CODE_PROMO)),
codePromoPresent: true, codePromoPresent: true,
valeurCodePromo: P.string, valeurCodePromo: P.string,
}, },
({ valeurCodePromo }) => ({ valeurCodePromo }) => undefined,
void EitherAsync.liftEither(safeSchemaParse({ code: valeurCodePromo }, WCStoreCartRemoveCouponArgsSchema))
.ifRight(() => {
E.BOUTON_CODE_PROMO.setAttribute(ATTRIBUT_DESACTIVE, "");
E.BOUTON_CODE_PROMO.setAttribute(ATTRIBUT_CHARGEMENT, "");
lanceAnimationCycleLoading(E.BOUTON_CODE_PROMO, 500);
})
.map((args: WCStoreCartRemoveCouponArgs) =>
postBackend({
corps: JSON.stringify(args),
nonce: ETATS_PAGE.nonce,
route: ROUTE_API_RETIRE_COUPON,
}),
)
.chain((reponse: Response) =>
EitherAsync<ServerError, unknown>(async ({ throwE }) => {
if (estReponse500(reponse)) {
throwE(new ServerError("500 server Error"));
}
return await reponse.json();
}),
)
.chain((corpsReponse: unknown) => EitherAsync.liftEither(safeSchemaParse(corpsReponse, WCStoreCartSchema)))
.ifRight((panier: WCStoreCart) => {
E.ENSEMBLE_CODE_PROMO.toggleAttribute(ATTRIBUT_CODE_PROMO_PRESENT);
E.ENSEMBLE_CODE_PROMO.reset();
E.CHAMP_CODE_PROMO.toggleAttribute(ATTRIBUT_DESACTIVE);
E.CHAMP_CODE_PROMO.textContent = "";
E.BOUTON_CODE_PROMO.textContent = "Apply";
E.TOTAL_PANIER.textContent = pipe(
diviseParCent(panier.totals.total_price),
arrondisADeuxDecimales,
formateEnEuros,
);
E.TOTAL_REDUCTION_LIGNE.toggleAttribute(ATTRIBUT_HIDDEN);
E.TOTAL_REDUCTION_VALEUR.textContent = "-0€";
emetUniqueMessageBroadcastChannel(NOM_CANAL_REVALIDATION_LIVRAISON, true);
})
.ifLeft((erreur) =>
match(erreur)
.with(P.instanceOf(ValiError), (e) => {
reporteErreur(e);
console.error("retour ajout code promo", e.issues);
})
.with(P.instanceOf(ServerError), (e) => {
reporteErreur(e);
console.error("retour ajout code promo", e);
})
.with(P.instanceOf(TypeError), (e) => {
reporteErreur(e);
console.error("retour ajout code promo", e);
})
.exhaustive(),
)
.finally(() => {
E.BOUTON_CODE_PROMO.removeAttribute(ATTRIBUT_CHARGEMENT);
E.BOUTON_CODE_PROMO.removeAttribute(ATTRIBUT_DESACTIVE);
})
.run(),
) )
// Ne rien faire en dehors de ces deux situations [
.with(P._, identity), // Ne rien faire en dehors de ces deux situations
); "with"
](P._, identity));
}; };

View file

@ -26,20 +26,20 @@ export const reinitialiseValidationLivraison = (): void => {
* @returns void * @returns void
*/ */
export const souscrisEvenementsPanier = (): void => { export const souscrisEvenementsPanier = (): void => {
window.addEventListener(ADRESSES_MAJ, (): void => { globalThis.addEventListener(ADRESSES_MAJ, (): void => {
reinitialiseValidationLivraison(); reinitialiseValidationLivraison();
}); });
window.addEventListener(CODE_PROMO_MAJ, (): void => { globalThis.addEventListener(CODE_PROMO_MAJ, (): void => {
reinitialiseValidationLivraison(); reinitialiseValidationLivraison();
}); });
window.addEventListener(SHIPPING_RATES_UPDATED, (event: Event): void => { globalThis.addEventListener(SHIPPING_RATES_UPDATED, (event: Event): void => {
Either Either
// La vérification du schéma se fait à l'émission // La vérification du schéma se fait à l'émission
.encase(() => (event as UpdatedShippingRatesEvent).detail) .encase(() => (event as UpdatedShippingRatesEvent).detail)
// Met à jour le DOM // Met à jour le DOM
.ifRight((event) => { .ifRight(event => {
// Met à jour les Méthodes à l'Utilisateur si demandé // Met à jour les Méthodes à l'Utilisateur si demandé
// Il peut y en avoir aucune // Il peut y en avoir aucune
if (event.refresh_methods) { if (event.refresh_methods) {
@ -47,18 +47,18 @@ export const souscrisEvenementsPanier = (): void => {
} }
}) })
// Met à jour le SessionStorage // Met à jour le SessionStorage
.chain((event) => eitherSetSessionStorage("shipping_rates", event.shipping_rates)) .chain(event => eitherSetSessionStorage("shipping_rates", event.shipping_rates))
.ifLeft(reporteEtJournaliseErreur); .ifLeft(reporteEtJournaliseErreur);
}); });
window.addEventListener(TOTALS_UPDATED, (event: Event): void => { globalThis.addEventListener(TOTALS_UPDATED, (event: Event): void => {
Either Either
// La vérification du Schéma se fait à l'émission // La vérification du Schéma se fait à l'émission
.encase(() => (event as UpdatedTotalsEvent).detail.totals) .encase(() => (event as UpdatedTotalsEvent).detail.totals)
.chain((ts) => eitherSetSessionStorage("totals", ts)) .chain(ts => eitherSetSessionStorage("totals", ts))
.ifLeft(reporteEtJournaliseErreur) .ifLeft(reporteEtJournaliseErreur)
// Met à jour le DOM // Met à jour le DOM
.ifRight((ts) => { .ifRight(ts => {
E.SOUS_TOTAL_LIVRAISON_VALEUR.textContent = formateEnEuros(ts.total_shipping); E.SOUS_TOTAL_LIVRAISON_VALEUR.textContent = formateEnEuros(ts.total_shipping);
E.SOUS_TOTAL_PRODUITS_VALEUR.textContent = formateEnEuros(ts.total_items); E.SOUS_TOTAL_PRODUITS_VALEUR.textContent = formateEnEuros(ts.total_items);
E.SOUS_TOTAL_REDUCTION_VALEUR.textContent = formateEnEuros(ts.total_discount * -1); E.SOUS_TOTAL_REDUCTION_VALEUR.textContent = formateEnEuros(ts.total_discount * -1);

View file

@ -19,7 +19,7 @@ import { getShippingRatesLS } from "./scripts-page-panier-local-storage";
export const initShippingRatesChoicesActions = (): void => { export const initShippingRatesChoicesActions = (): void => {
getDOMElementsWithSelector(E.CONTENEUR_METHODES_LIVRAISON)<HTMLInputElement>("input").ifRight( getDOMElementsWithSelector(E.CONTENEUR_METHODES_LIVRAISON)<HTMLInputElement>("input").ifRight(
forEach((el: HTMLInputElement): void => forEach((el: HTMLInputElement): void => {
el.addEventListener("click", (event: MouseEvent): void => { el.addEventListener("click", (event: MouseEvent): void => {
// Récupère les méthodes du SessionStorage et les met à jour avec le nouveau choix // Récupère les méthodes du SessionStorage et les met à jour avec le nouveau choix
getShippingRatesLS() getShippingRatesLS()
@ -32,10 +32,10 @@ export const initShippingRatesChoicesActions = (): void => {
) )
// Met à jour les Méthodes de livraison dans le SessionStorage et le DOM // Met à jour les Méthodes de livraison dans le SessionStorage et le DOM
.ifJust((srs: WCStoreShippingRateShippingRates): void => { .ifJust((srs: WCStoreShippingRateShippingRates): void => {
window.dispatchEvent(createUpdatedShippingRatesEvent(srs, false)); globalThis.dispatchEvent(createUpdatedShippingRatesEvent(srs, false));
}) })
// Met à jour les totaux dans le SessionStorage et le DOM // Met à jour les totaux dans le SessionStorage et le DOM
.chain(find((sr) => sr.selected)) .chain(find(sr => sr.selected))
.ifJust((sr: WCStoreShippingRateShippingRate): void => { .ifJust((sr: WCStoreShippingRateShippingRate): void => {
getSessionStorageByKey("totals", WCStoreCartTotalsSchema) getSessionStorageByKey("totals", WCStoreCartTotalsSchema)
.ifLeft(reporteEtJournaliseErreur) .ifLeft(reporteEtJournaliseErreur)
@ -45,11 +45,11 @@ export const initShippingRatesChoicesActions = (): void => {
return ts; return ts;
}) })
.ifRight((ts: WCStoreCartTotals): void => { .ifRight((ts: WCStoreCartTotals): void => {
window.dispatchEvent(createUpdatedTotalsEvent(ts)); globalThis.dispatchEvent(createUpdatedTotalsEvent(ts));
}); });
}); });
}), });
), }),
); );
}; };
@ -64,12 +64,17 @@ export const generateShippingRatesHTML = (
} }
// Retire les méthodes de livraison initiales // Retire les méthodes de livraison initiales
getDOMElementsWithSelector(container)("div[data-methode-initiale]").ifRight(arrayForEach((div) => div.remove())); getDOMElementsWithSelector(container)("div[data-methode-initiale]").ifRight(
arrayForEach(div => {
div.remove();
}),
);
const selectedShippingRate: string = shippingRates.find((sr) => sr.selected)?.method_id ?? ""; const selectedShippingRate: string = shippingRates.find(sr => sr.selected)?.method_id ?? "";
const shippingRatesHTML: ReadonlyArray<TemplateResult> = arrayMap( const shippingRatesHTML: ReadonlyArray<TemplateResult> = arrayMap(
shippingRates, shippingRates,
(methode) => html` <div> methode =>
html` <div>
<input <input
id="methode-livraison-${methode.method_id}" id="methode-livraison-${methode.method_id}"
name="choix-methode-livraison" name="choix-methode-livraison"

View file

@ -7,12 +7,13 @@ import { match, P } from "ts-pattern";
import { ValiError } from "valibot"; import { ValiError } from "valibot";
import type { AnySchema } from "valibot"; import type { AnySchema } from "valibot";
import type { WCStoreCart } from "../lib/types/api/cart.ts";
import type { WCStoreCartRemoveItemArgs } from "../lib/types/api/cart-remove-item.ts"; import type { WCStoreCartRemoveItemArgs } from "../lib/types/api/cart-remove-item.ts";
import type { WCStoreCartUpdateItemArgs } from "../lib/types/api/cart-update-item.ts"; import type { WCStoreCartUpdateItemArgs } from "../lib/types/api/cart-update-item.ts";
import type { WCStoreCart } from "../lib/types/api/cart.ts";
import type { GenericPageState } from "../lib/types/pages.ts"; import type { GenericPageState } from "../lib/types/pages.ts";
import type { FetchErrors, HttpCodeErrors } from "../lib/types/reseau.ts"; import type { FetchErrors, HttpCodeErrors } from "../lib/types/reseau.ts";
import { getFirstSelectorFromParentOrThrow } from "../../scripts-effect/lib/dom.ts";
import { ROUTE_API_MAJ_ARTICLE_PANIER, ROUTE_API_RETIRE_ARTICLE_PANIER } from "../constantes/api.ts"; import { ROUTE_API_MAJ_ARTICLE_PANIER, ROUTE_API_RETIRE_ARTICLE_PANIER } from "../constantes/api.ts";
import { import {
ATTRIBUT_CLE_PANIER, ATTRIBUT_CLE_PANIER,
@ -31,12 +32,11 @@ import {
} from "../lib/messages.ts"; } from "../lib/messages.ts";
import { diviseParCent } from "../lib/nombres.ts"; import { diviseParCent } from "../lib/nombres.ts";
import { newPartialResponse, postBackend, safeFetch, traiteErreursBackendWooCommerce } from "../lib/reseau.ts"; import { newPartialResponse, postBackend, safeFetch, traiteErreursBackendWooCommerce } from "../lib/reseau.ts";
import { WCStoreCartSchema } from "../lib/schemas/api/cart.ts";
import { WCStoreCartRemoveItemArgsSchema } from "../lib/schemas/api/cart-remove-item.ts"; import { WCStoreCartRemoveItemArgsSchema } from "../lib/schemas/api/cart-remove-item.ts";
import { WCStoreCartUpdateItemArgsSchema } from "../lib/schemas/api/cart-update-item.ts"; import { WCStoreCartUpdateItemArgsSchema } from "../lib/schemas/api/cart-update-item.ts";
import { WCStoreCartSchema } from "../lib/schemas/api/cart.ts";
import { safeSchemaParse } from "../lib/validation.ts"; import { safeSchemaParse } from "../lib/validation.ts";
import { E } from "./scripts-page-panier-elements.ts"; import { E } from "./scripts-page-panier-elements.ts";
import { getFirstSelectorFromParentOrThrow } from "../../scripts-effect/lib/dom.ts";
// @ts-expect-error -- États injectés par le modèle PHP // @ts-expect-error -- États injectés par le modèle PHP
const PAGE_STATE: GenericPageState = _etats; const PAGE_STATE: GenericPageState = _etats;
@ -65,8 +65,7 @@ const getCartEntryInteractiveEles = (entry: HTMLElement): CartEntryInteractiveEl
* @returns Rien. * @returns Rien.
*/ */
const toggleCartEntryButtons = const toggleCartEntryButtons =
(activated: boolean) => (activated: boolean) => (cartEntries: ReadonlyArray<CartEntryInteractiveElements>): void => {
(cartEntries: ReadonlyArray<CartEntryInteractiveElements>): void => {
arrayForEach(cartEntries, (e: CartEntryInteractiveElements): void => { arrayForEach(cartEntries, (e: CartEntryInteractiveElements): void => {
if (activated) { if (activated) {
// Active les Boutons // Active les Boutons
@ -121,10 +120,10 @@ const initActionsOnCartEntries = (): void => {
.fromNullable(entryButtons.quantityInput.valueAsNumber) .fromNullable(entryButtons.quantityInput.valueAsNumber)
.toEither(new Error("Quantité manquante pour cette ligne du Panier !")), .toEither(new Error("Quantité manquante pour cette ligne du Panier !")),
) )
.chain((q) => .chain(q =>
EitherAsync.liftEither( EitherAsync.liftEither(
safeSchemaParse({ key: entryKey, quantity: q + 1 }, WCStoreCartUpdateItemArgsSchema), safeSchemaParse({ key: entryKey, quantity: q + 1 }, WCStoreCartUpdateItemArgsSchema),
), )
) )
.ifRight(() => { .ifRight(() => {
pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(false)); pipe(cartEntries, arrayMap(getCartEntryInteractiveEles), toggleCartEntryButtons(false));
@ -136,14 +135,14 @@ const initActionsOnCartEntries = (): void => {
nonce: PAGE_STATE.nonce, nonce: PAGE_STATE.nonce,
route: ROUTE_API_MAJ_ARTICLE_PANIER, route: ROUTE_API_MAJ_ARTICLE_PANIER,
}), }),
), )
) )
.chain((r: Response) => .chain((r: Response) =>
EitherAsync<ServerError, unknown>(async ({ throwE }) => EitherAsync<ServerError, unknown>(async ({ throwE }) =>
match(await newPartialResponse(r)) match(await newPartialResponse(r))
["with"]({ status: 200 }, (r) => r.body) ["with"]({ status: 200 }, r => r.body)
.otherwise((rs): never => throwE(traiteErreursBackendWooCommerce(rs))), .otherwise((rs): never => throwE(traiteErreursBackendWooCommerce(rs)))
), )
) )
.chain((b: unknown) => EitherAsync.liftEither(safeSchemaParse(b, WCStoreCartSchema))) .chain((b: unknown) => EitherAsync.liftEither(safeSchemaParse(b, WCStoreCartSchema)))
.ifRight((c: WCStoreCart): void => { .ifRight((c: WCStoreCart): void => {
@ -161,17 +160,17 @@ const initActionsOnCartEntries = (): void => {
}) })
.ifLeft((err: FetchErrors | HttpCodeErrors | ValiError<AnySchema>): void => { .ifLeft((err: FetchErrors | HttpCodeErrors | ValiError<AnySchema>): void => {
match(err) match(err)
["with"](P.instanceOf(ValiError), (e) => { ["with"](P.instanceOf(ValiError), e => {
reporteErreur(e); reporteErreur(e);
console.error(e.issues); console.error(e.issues);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
}) })
["with"](P.instanceOf(ServerError), P.instanceOf(BadRequestError), (e) => { ["with"](P.instanceOf(ServerError), P.instanceOf(BadRequestError), e => {
reporteErreur(e); reporteErreur(e);
console.error(e); console.error(e);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
}) })
["with"](P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), (e) => { ["with"](P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), e => {
reporteErreur(e); reporteErreur(e);
console.error(e); console.error(e);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU;
@ -191,7 +190,7 @@ const initActionsOnCartEntries = (): void => {
Maybe Maybe
// Nécessaire pour que l'on ait une valeur à incrémenter // Nécessaire pour que l'on ait une valeur à incrémenter
.fromNullable(entryButtons.quantityInput.valueAsNumber) .fromNullable(entryButtons.quantityInput.valueAsNumber)
.filter((valeur) => valeur > 1) .filter(valeur => valeur > 1)
.ifJust((valeur: number) => { .ifJust((valeur: number) => {
// Réalise la requête et traite sa réponse // Réalise la requête et traite sa réponse
void EitherAsync void EitherAsync
@ -211,7 +210,7 @@ const initActionsOnCartEntries = (): void => {
nonce: PAGE_STATE.nonce, nonce: PAGE_STATE.nonce,
route: ROUTE_API_MAJ_ARTICLE_PANIER, route: ROUTE_API_MAJ_ARTICLE_PANIER,
}), }),
), )
) )
// 4. Traite les cas d'Erreurs et récupère le Corps de la Réponse // 4. Traite les cas d'Erreurs et récupère le Corps de la Réponse
.chain((reponse: Response) => .chain((reponse: Response) =>
@ -220,9 +219,9 @@ const initActionsOnCartEntries = (): void => {
match(await newPartialResponse(reponse)) match(await newPartialResponse(reponse))
["with"]({ status: 500 }, () => throwE(new ServerError("500 Server Error"))) ["with"]({ status: 500 }, () => throwE(new ServerError("500 Server Error")))
["with"]({ status: 400 }, () => throwE(new BadRequestError("400 Bad Request Error"))) ["with"]({ status: 400 }, () => throwE(new BadRequestError("400 Bad Request Error")))
["with"]({ status: 200 }, (r) => r.body) ["with"]({ status: 200 }, r => r.body)
.otherwise((erreur) => throwE(new Error(`Erreur inconnue ${String(erreur.status)}`))), .otherwise(erreur => throwE(new Error(`Erreur inconnue ${String(erreur.status)}`)))
), )
) )
// 5. Vérifie le Schéma de la Réponse // 5. Vérifie le Schéma de la Réponse
.chain((corps: unknown) => EitherAsync.liftEither(safeSchemaParse(corps, WCStoreCartSchema))) .chain((corps: unknown) => EitherAsync.liftEither(safeSchemaParse(corps, WCStoreCartSchema)))
@ -243,17 +242,17 @@ const initActionsOnCartEntries = (): void => {
// 7. Traite les Erreurs et affiche un message à l'Utilisateur // 7. Traite les Erreurs et affiche un message à l'Utilisateur
.ifLeft((erreur: BadRequestError | FetchErrors | ServerError | ValiError<AnySchema>): void => { .ifLeft((erreur: BadRequestError | FetchErrors | ServerError | ValiError<AnySchema>): void => {
match(erreur) match(erreur)
["with"](P.instanceOf(ValiError), (e) => { ["with"](P.instanceOf(ValiError), e => {
reporteErreur(e); reporteErreur(e);
console.error(e.issues); console.error(e.issues);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
}) })
["with"](P.instanceOf(ServerError), P.instanceOf(BadRequestError), (e) => { ["with"](P.instanceOf(ServerError), P.instanceOf(BadRequestError), e => {
reporteErreur(e); reporteErreur(e);
console.error(e); console.error(e);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
}) })
["with"](P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), (e) => { ["with"](P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), e => {
reporteErreur(e); reporteErreur(e);
console.error(e); console.error(e);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU;
@ -292,7 +291,7 @@ const initActionsOnCartEntries = (): void => {
nonce: PAGE_STATE.nonce, nonce: PAGE_STATE.nonce,
route: ROUTE_API_RETIRE_ARTICLE_PANIER, route: ROUTE_API_RETIRE_ARTICLE_PANIER,
}), }),
), )
) )
// 4. Traite les cas d'Erreurs et récupère le Corps de la Réponse // 4. Traite les cas d'Erreurs et récupère le Corps de la Réponse
.chain((reponse: Response) => .chain((reponse: Response) =>
@ -301,9 +300,9 @@ const initActionsOnCartEntries = (): void => {
match(await newPartialResponse(reponse)) match(await newPartialResponse(reponse))
["with"]({ status: 500 }, () => throwE(new ServerError("500 Server Error"))) ["with"]({ status: 500 }, () => throwE(new ServerError("500 Server Error")))
["with"]({ status: 400 }, () => throwE(new BadRequestError("400 Bad Request Error"))) ["with"]({ status: 400 }, () => throwE(new BadRequestError("400 Bad Request Error")))
["with"]({ status: 200 }, (r) => r.body) ["with"]({ status: 200 }, r => r.body)
.otherwise((erreur) => throwE(new Error(`Erreur inconnue ${String(erreur.status)}`))), .otherwise(erreur => throwE(new Error(`Erreur inconnue ${String(erreur.status)}`)))
), )
) )
// 5. Vérifie le Schéma de la Réponse // 5. Vérifie le Schéma de la Réponse
.chain((corps: unknown) => EitherAsync.liftEither(safeSchemaParse(corps, WCStoreCartSchema))) .chain((corps: unknown) => EitherAsync.liftEither(safeSchemaParse(corps, WCStoreCartSchema)))
@ -327,17 +326,17 @@ const initActionsOnCartEntries = (): void => {
// 7. Traite les Erreurs et affiche un message à l'Utilisateur // 7. Traite les Erreurs et affiche un message à l'Utilisateur
.ifLeft((erreur: BadRequestError | FetchErrors | ServerError | ValiError<AnySchema>): void => { .ifLeft((erreur: BadRequestError | FetchErrors | ServerError | ValiError<AnySchema>): void => {
match(erreur) match(erreur)
["with"](P.instanceOf(ValiError), (e) => { ["with"](P.instanceOf(ValiError), e => {
reporteErreur(e); reporteErreur(e);
console.error(e.issues); console.error(e.issues);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
}) })
["with"](P.instanceOf(ServerError), P.instanceOf(BadRequestError), (e) => { ["with"](P.instanceOf(ServerError), P.instanceOf(BadRequestError), e => {
reporteErreur(e); reporteErreur(e);
console.error(e); console.error(e);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
}) })
["with"](P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), (e) => { ["with"](P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), e => {
reporteErreur(e); reporteErreur(e);
console.error(e); console.error(e);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU;
@ -352,10 +351,10 @@ const initActionsOnCartEntries = (): void => {
}); });
}, },
) )
.otherwise((_) => {}); .otherwise(_ => {});
}); });
}); });
}); });
}; };
export { toggleCartEntryButtons, initActionsOnCartEntries as initialiseActionsEntreesPanier }; export { initActionsOnCartEntries as initialiseActionsEntreesPanier, toggleCartEntryButtons };

View file

@ -68,9 +68,9 @@ const initialiseObservationFenetre = (): void => {
} }
etapePlanifiee = true; etapePlanifiee = true;
requestAnimationFrame((): void => requestAnimationFrame((): void => {
majVisibiliteBouton(defilementY > window.innerHeight * RATIO_MINIMUM_PAGE_PAR_FENETRE), majVisibiliteBouton(defilementY > window.innerHeight * RATIO_MINIMUM_PAGE_PAR_FENETRE);
); });
}); });
new ResizeObserver((entrees: Array<ResizeObserverEntry>): void => { new ResizeObserver((entrees: Array<ResizeObserverEntry>): void => {

View file

@ -2,13 +2,14 @@
import { Array as EffectArray, Match, Predicate } from "effect"; import { Array as EffectArray, Match, Predicate } from "effect";
import { DOM_ENTREES_MENU_CATEGORIES_PRODUITS, DOM_MENU_CATEGORIES_PRODUITS } from "./constantes/dom.ts";
import { getAllSelectorFromDocumentOrThrow, getFirstSelectorFromDocumentOrThrow } from "../scripts-effect/lib/dom.ts"; import { getAllSelectorFromDocumentOrThrow, getFirstSelectorFromDocumentOrThrow } from "../scripts-effect/lib/dom.ts";
import { DOM_ENTREES_MENU_CATEGORIES_PRODUITS, DOM_MENU_CATEGORIES_PRODUITS } from "./constantes/dom.ts";
// Initialise les attributs HTML pour l'affichage initiale des flèches de défilement du menu de catégories de Produits. // Initialise les attributs HTML pour l'affichage initiale des flèches de défilement du menu de catégories de Produits.
document.addEventListener("DOMContentLoaded", (): void => { document.addEventListener("DOMContentLoaded", (): void => {
const productsCategoriesMenu: HTMLElement = const productsCategoriesMenu: HTMLElement = getFirstSelectorFromDocumentOrThrow<HTMLElement>(
getFirstSelectorFromDocumentOrThrow<HTMLElement>(DOM_MENU_CATEGORIES_PRODUITS); DOM_MENU_CATEGORIES_PRODUITS,
);
const menuEntries: ReadonlyArray<HTMLAnchorElement> = getAllSelectorFromDocumentOrThrow( const menuEntries: ReadonlyArray<HTMLAnchorElement> = getAllSelectorFromDocumentOrThrow(
DOM_ENTREES_MENU_CATEGORIES_PRODUITS, DOM_ENTREES_MENU_CATEGORIES_PRODUITS,
); );
@ -22,17 +23,25 @@ document.addEventListener("DOMContentLoaded", (): void => {
} }
new IntersectionObserver( new IntersectionObserver(
EffectArray.forEach((intersectionEntry) => { EffectArray.forEach(intersectionEntry => {
// Ne déclenche rien si le scroll n'est pas horizontal // Ne déclenche rien si le scroll n'est pas horizontal
if (intersectionEntry.boundingClientRect.top <= 0) { if (intersectionEntry.boundingClientRect.top <= 0) {
return; return;
} }
Match.value([intersectionEntry.isIntersecting]).pipe( Match.value([intersectionEntry.isIntersecting]).pipe(
Match.when([true, 0], () => productsCategoriesMenu.removeAttribute("data-entrees-presentes-debut")), Match.when([true, 0], () => {
Match.when([true, 1], () => productsCategoriesMenu.removeAttribute("data-entrees-presentes-fin")), productsCategoriesMenu.removeAttribute("data-entrees-presentes-debut");
Match.when([false, 0], () => productsCategoriesMenu.setAttribute("data-entrees-presentes-debut", "")), }),
Match.when([false, 1], () => productsCategoriesMenu.setAttribute("data-entrees-presentes-fin", "")), Match.when([true, 1], () => {
productsCategoriesMenu.removeAttribute("data-entrees-presentes-fin");
}),
Match.when([false, 0], () => {
productsCategoriesMenu.setAttribute("data-entrees-presentes-debut", "");
}),
Match.when([false, 1], () => {
productsCategoriesMenu.setAttribute("data-entrees-presentes-fin", "");
}),
Match.orElse(() => {}), Match.orElse(() => {}),
); );
}), }),

View file

@ -18,19 +18,19 @@ const E = {
const initialiseBoutonMenuMobile = (): void => { const initialiseBoutonMenuMobile = (): void => {
const menuMobile = new A11yDialog(E.MENU_MOBILE); const menuMobile = new A11yDialog(E.MENU_MOBILE);
new ResizeObserver((entrees) => new ResizeObserver(entrees =>
// Cache le Menu mobile pour les grandes tailles d'écrans // Cache le Menu mobile pour les grandes tailles d'écrans
pipe( pipe(
A.head(entrees), A.head(entrees),
O.filter((entree: ResizeObserverEntry) => entree.borderBoxSize[0]!.inlineSize > 1000), O.filter((entree: ResizeObserverEntry) => entree.borderBoxSize[0]!.inlineSize > 1000),
O.tap((_) => menuMobile.hide()), O.tap(_ => menuMobile.hide()),
), )
).observe(E.CORPS_HTML); ).observe(E.CORPS_HTML);
E.BOUTON_MENU_MOBILE.addEventListener("click", (): void => { E.BOUTON_MENU_MOBILE.addEventListener("click", (): void => {
// Renvoie à la Page d'accueil pour les grandes tailles d'écrans // Renvoie à la Page d'accueil pour les grandes tailles d'écrans
if (window.innerWidth > 1000) { if (window.innerWidth > 1000) {
window.location.href = "/"; globalThis.location.href = "/";
return; return;
} }
// Cache le Menu mobile s'il est actif // Cache le Menu mobile s'il est actif

View file

@ -2,7 +2,7 @@
* Scripts pour les fonctionnalités de la Page À Propos (« About »). * Scripts pour les fonctionnalités de la Page À Propos (« About »).
*/ */
import { A, pipe as beltPipe, O } from "@mobily/ts-belt"; import { A, O, pipe as beltPipe } from "@mobily/ts-belt";
import { import {
ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF, ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF,
@ -48,7 +48,11 @@ document.addEventListener("DOMContentLoaded", (): void => {
O.tap((id: string) => { O.tap((id: string) => {
beltPipe( beltPipe(
O.fromNullable(ENSEMBLES_EPINGLES_BOITES_TEXTE.get(id)), O.fromNullable(ENSEMBLES_EPINGLES_BOITES_TEXTE.get(id)),
O.tap(A.forEach((element) => element.removeAttribute(ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF))), O.tap(
A.forEach(element => {
element.removeAttribute(ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF);
}),
),
); );
}), }),
); );
@ -64,7 +68,11 @@ document.addEventListener("DOMContentLoaded", (): void => {
if (cible.hasAttribute(ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF)) { if (cible.hasAttribute(ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF)) {
beltPipe( beltPipe(
O.fromNullable(ENSEMBLES_EPINGLES_BOITES_TEXTE.get(id)), O.fromNullable(ENSEMBLES_EPINGLES_BOITES_TEXTE.get(id)),
O.tap(A.forEach((element) => element.removeAttribute(ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF))), O.tap(
A.forEach(element => {
element.removeAttribute(ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF);
}),
),
); );
return; return;
} }
@ -73,12 +81,14 @@ document.addEventListener("DOMContentLoaded", (): void => {
beltPipe( beltPipe(
Array.from(ENSEMBLES_EPINGLES_BOITES_TEXTE.values()), Array.from(ENSEMBLES_EPINGLES_BOITES_TEXTE.values()),
A.flat, A.flat,
A.forEach((element) => element.removeAttribute(ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF)), A.forEach(element => {
element.removeAttribute(ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF);
}),
); );
// Active l'Attribut sur l'Ensemble // Active l'Attribut sur l'Ensemble
beltPipe( beltPipe(
O.fromNullable(ENSEMBLES_EPINGLES_BOITES_TEXTE.get(id)), O.fromNullable(ENSEMBLES_EPINGLES_BOITES_TEXTE.get(id)),
O.tap(A.forEach((element) => element.toggleAttribute(ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF))), O.tap(A.forEach(element => element.toggleAttribute(ATTRIBUT_ENSEMBLE_EPINGLE_BOITE_ACTIF))),
); );
}), }),
); );

View file

@ -94,23 +94,25 @@ const initDefilementStorytelling = (): void => {
}).observe(E.STORYTELLING); }).observe(E.STORYTELLING);
// Initialise la mise à jour des images au défilement sur le Conteneur. // Initialise la mise à jour des images au défilement sur le Conteneur.
E.STORYTELLING.addEventListener("scroll", (): void => majVisibilitéImagesStorytelling()); E.STORYTELLING.addEventListener("scroll", (): void => {
majVisibilitéImagesStorytelling();
});
}; };
const initGestionAnimation = (): void => { const initGestionAnimation = (): void => {
pipe( pipe(
A.at(E.IMAGES_STORYTELLING, 0), A.at(E.IMAGES_STORYTELLING, 0),
O.tap((img) => { O.tap(img => {
const options: IntersectionObserverInit = { const options: IntersectionObserverInit = {
root: undefined, root: undefined,
rootMargin: "0px", rootMargin: "0px",
threshold: 0, threshold: 0,
}; };
const callback = (entries: Array<IntersectionObserverEntry>) => { const callback = (entries: Array<IntersectionObserverEntry>) => {
A.forEach(entries, (e) => { A.forEach(entries, e => {
e.intersectionRatio >= 0.9 e.intersectionRatio >= 0.9 ?
? E.CONTENEUR_ANIMATION.removeAttribute(ATTRIBUT_HIDDEN) E.CONTENEUR_ANIMATION.removeAttribute(ATTRIBUT_HIDDEN) :
: E.CONTENEUR_ANIMATION.setAttribute(ATTRIBUT_HIDDEN, ""); E.CONTENEUR_ANIMATION.setAttribute(ATTRIBUT_HIDDEN, "");
}); });
}; };

View file

@ -13,6 +13,7 @@ import type { WCV3Products, WCV3ProductsArgs } from "./lib/types/api/v3/products
import type { GenericPageState } from "./lib/types/pages"; import type { GenericPageState } from "./lib/types/pages";
import { ROUTE_API_NOUVELLE_PRODUCTS } from "./constantes/api.ts"; import { ROUTE_API_NOUVELLE_PRODUCTS } from "./constantes/api.ts";
import { PRODUCT_STATUTES } from "./constantes/api/products.ts";
import { import {
ATTRIBUT_CHARGEMENT, ATTRIBUT_CHARGEMENT,
ATTRIBUT_DESACTIVE, ATTRIBUT_DESACTIVE,
@ -28,7 +29,6 @@ import { BadRequestError, reporteErreur, ServerError } from "./lib/erreurs.ts";
import { getBackendAvecParametresUrl, newPartialResponse } from "./lib/reseau.ts"; import { getBackendAvecParametresUrl, newPartialResponse } from "./lib/reseau.ts";
import { WCV3ProductsArgsSchema, WCV3ProductsSchema } from "./lib/schemas/api/v3/products.ts"; import { WCV3ProductsArgsSchema, WCV3ProductsSchema } from "./lib/schemas/api/v3/products.ts";
import { safeSchemaParse } from "./lib/validation.ts"; import { safeSchemaParse } from "./lib/validation.ts";
import { PRODUCT_STATUTES } from "./constantes/api/products.ts";
type APIProductsErrors = type APIProductsErrors =
| APIFetchErrors | APIFetchErrors
@ -67,109 +67,7 @@ const initialisePageBoutique = (): void => {
...(idCategorieProduits && { category: idCategorieProduits }), ...(idCategorieProduits && { category: idCategorieProduits }),
}; };
void EitherAsync undefined;
// 1. Valide les Arguments de la Requête
.liftEither(safeSchemaParse(args, WCV3ProductsArgsSchema))
// 2. Exécute un Effet pour empêcher les requêtes concurrentes et lancer une animation de chargement
.ifRight((): void => {
// Désactive le Bouton pour empêcher des requêtes concurrentes
E.BOUTON_PLUS_DE_PRODUITS.setAttribute(ATTRIBUT_DESACTIVE, "");
E.BOUTON_PLUS_DE_PRODUITS.setAttribute(ATTRIBUT_CHARGEMENT, "");
// Lance un cycle d'animation sur le texte de chargement
lanceAnimationCycleLoading(E.BOUTON_PLUS_DE_PRODUITS, 500);
})
// 3. Exécute la requête via fetch sous forme d'EitherAsync
.chain((args: WCV3ProductsArgs) =>
EitherAsync<DOMException | Error, Response>(() =>
getBackendAvecParametresUrl({
authString: ETATS_PAGE.authString,
nonce: ETATS_PAGE.nonce,
route: ROUTE_API_NOUVELLE_PRODUCTS,
searchParams: new URLSearchParams(args).toString(),
}),
),
)
// 4. Traite les cas d'Erreurs et récupère le Corps de la Réponse
.chain((reponse: Response) =>
EitherAsync<APIFetchErrors, unknown>(async ({ throwE }) =>
match(await newPartialResponse(reponse))
.with({ status: 500 }, () => throwE(new ServerError("500 Server Error")))
.with({ status: 400 }, () => throwE(new BadRequestError("400 Server Error")))
.with({ status: 200 }, (r) => r.body)
.run(),
),
)
// 5. Vérifie le Schéma de la Réponse
.chain((corpsReponse: unknown) => EitherAsync.liftEither(safeSchemaParse(corpsReponse, WCV3ProductsSchema)))
// 6. Exécute un Effet pour la mise à jour du DOM avec les Résultats
.ifRight((donnees: WCV3Products) => {
// Cache le bouton s'il y a moins de PRODUCTS_PER_PAGE Produits disponibles (que l'on est à la dernière page)
if (donnees.length < PRODUCTS_PER_PAGE) {
E.BOUTON_PLUS_DE_PRODUITS.toggleAttribute(ATTRIBUT_HIDDEN);
}
// Créé un DocumentFragment qui recevra tous les nouveaux Produits
const fragment: DocumentFragment = document.createDocumentFragment();
// Créé les Éléments <article> à insérer
for (const produit of donnees.slice(0, PRODUCTS_PER_PAGE)) {
pipe(
html`
<article class="produit">
<figure>
<a href="/product/${produit.slug}">
<picture class="produit__illustration produit__illustration__principale">
${produit.image_repos ?? ""}
</picture>
<picture class="produit__illustration produit__illustration__survol">
${produit.image_survol ?? ""}
</picture>
</a>
<figcaption class="produit__textuel">
<h3 class="produit__textuel__titre">
<a href="${produit.permalink}">${produit.name}</a>
</h3>
<p class="produit__textuel__prix">
${produit.prix_maximal}
</p>
</figcaption>
</figure>
</article>
`,
tap((article) => fragment.append(article)),
);
}
// Ajoute les nouveaux Produits dans le DOM
E.GRILLE_PRODUITS.append(fragment);
E.GRILLE_PRODUITS.setAttribute(ATTRIBUT_PAGE, String(nouveauNumeroPage));
E.BOUTON_PLUS_DE_PRODUITS.textContent = "Show more";
})
// 7. Traite les Erreurs et affiche un Message à l'Utilisateur
.ifLeft((erreur: APIProductsErrors) => {
match(erreur)
.with(P.instanceOf(ValiError), (e) => {
reporteErreur(e);
console.error("ValiError", e.issues);
})
.otherwise((e) => {
reporteErreur(e);
console.error("Erreur", e);
});
E.BOUTON_PLUS_DE_PRODUITS.textContent = "Error, try again?";
})
// 8. Quel que soit le résultat, réactiver le Bouton et arrêter l'animation
.finally(() => {
// Désactive l'animation de chargement et rend le Bouton de nouveau cliquable
E.BOUTON_PLUS_DE_PRODUITS.removeAttribute(ATTRIBUT_CHARGEMENT);
E.BOUTON_PLUS_DE_PRODUITS.removeAttribute(ATTRIBUT_DESACTIVE);
})
.run();
}); });
}; };

View file

@ -8,6 +8,8 @@ import type { MessageMajContenuPanierSchema } from "./lib/schemas/messages.ts";
import type { WCStoreCartItem } from "./lib/types/api/cart"; import type { WCStoreCartItem } from "./lib/types/api/cart";
import type { MessageMajBoutonPanierDonnees, MessageMajContenuPanierDonnees } from "./lib/types/messages"; import type { MessageMajBoutonPanierDonnees, MessageMajContenuPanierDonnees } from "./lib/types/messages";
import { Effect } from "effect";
import { Effect } from "effect";
import { import {
ATTRIBUT_CLE_PANIER, ATTRIBUT_CLE_PANIER,
ATTRIBUT_CONTIENT_ARTICLES, ATTRIBUT_CONTIENT_ARTICLES,
@ -36,7 +38,6 @@ import { E } from "./page-panier/scripts-page-panier-elements.ts";
import { souscrisEvenementsPanier } from "./page-panier/scripts-page-panier-evenement.ts"; import { souscrisEvenementsPanier } from "./page-panier/scripts-page-panier-evenement.ts";
import { initShippingRatesChoicesActions } from "./page-panier/scripts-page-panier-methodes-livraison.ts"; import { initShippingRatesChoicesActions } from "./page-panier/scripts-page-panier-methodes-livraison.ts";
import { initialiseActionsEntreesPanier } from "./page-panier/scripts-page-panier-panneau-produits.ts"; import { initialiseActionsEntreesPanier } from "./page-panier/scripts-page-panier-panneau-produits.ts";
import { Effect } from "effect";
type ElementsEntreePanier = { type ElementsEntreePanier = {
boutonAddition: HTMLButtonElement; boutonAddition: HTMLButtonElement;
@ -54,7 +55,6 @@ type EtatsPage = {
// @ts-expect-error -- États injectés par le modèle PHP // @ts-expect-error -- États injectés par le modèle PHP
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- États injectés par le modèle PHP // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- États injectés par le modèle PHP
const ETATS_PAGE: EtatsPage = _etats;
/** /**
* Fonction utilitaire pour récupérer un Élément dans une ligne (entrée) du Panier, en levant une * Fonction utilitaire pour récupérer un Élément dans une ligne (entrée) du Panier, en levant une
@ -64,13 +64,11 @@ const ETATS_PAGE: EtatsPage = _etats;
* @returns L'Élément demandé. * @returns L'Élément demandé.
* @throws Une SyntaxError si l'Élément n'est pas trouvé. * @throws Une SyntaxError si l'Élément n'est pas trouvé.
*/ */
const recupereElementDansEntreePanierOuLeve = const recupereElementDansEntreePanierOuLeve = (entree: HTMLElement) => (selecteur: string) =>
(entree: HTMLElement) => pipe(recupereElementAvecSelecteur(entree)<Element>(selecteur), recupereElementOuLeve);
<E extends Element = Element>(selecteur: string) =>
pipe(recupereElementAvecSelecteur(entree)<E>(selecteur), recupereElementOuLeve);
// NOTE: Nécessaire pour éviter une condition de course entre la réussite de la requête et l'émission effective du Message // NOTE: Nécessaire pour éviter une condition de course entre la réussite de la requête et l'émission effective du Message
const majEtatsActivationBoutons = (entrees: Array<HTMLElement>): void => const majEtatsActivationBoutons = (entrees: Array<HTMLElement>): void => {
entrees.forEach((entree: HTMLElement) => { entrees.forEach((entree: HTMLElement) => {
// Fonction utilitaire // Fonction utilitaire
const recupereElementDansEntree = recupereElementDansEntreePanierOuLeve(entree); const recupereElementDansEntree = recupereElementDansEntreePanierOuLeve(entree);
@ -82,13 +80,14 @@ const majEtatsActivationBoutons = (entrees: Array<HTMLElement>): void =>
champQuantite: recupereElementDansEntree<HTMLInputElement>(DOM_CHAMP_QUANTITE_LIGNE_PANIER), champQuantite: recupereElementDansEntree<HTMLInputElement>(DOM_CHAMP_QUANTITE_LIGNE_PANIER),
}; };
Number(elements.champQuantite?.value) === 1 Number(elements.champQuantite?.value) === 1 ?
? elements.boutonSoustraction.setAttribute(ATTRIBUT_DESACTIVE, "") elements.boutonSoustraction.setAttribute(ATTRIBUT_DESACTIVE, "") :
: elements.boutonSoustraction.removeAttribute(ATTRIBUT_DESACTIVE); elements.boutonSoustraction.removeAttribute(ATTRIBUT_DESACTIVE);
elements.boutonAddition.removeAttribute(ATTRIBUT_DESACTIVE); elements.boutonAddition.removeAttribute(ATTRIBUT_DESACTIVE);
elements.boutonSuppression.removeAttribute(ATTRIBUT_DESACTIVE); elements.boutonSuppression.removeAttribute(ATTRIBUT_DESACTIVE);
elements.boutonSuppression.textContent = "Remove"; elements.boutonSuppression.textContent = "Remove";
}); });
};
const initialiseMajConteneurPanier = (): void => { const initialiseMajConteneurPanier = (): void => {
new BroadcastChannel(NOM_CANAL_BOUTON_PANIER).onmessage = (evenementMessage: MessageEvent<unknown>): void => { new BroadcastChannel(NOM_CANAL_BOUTON_PANIER).onmessage = (evenementMessage: MessageEvent<unknown>): void => {
@ -111,7 +110,7 @@ const initialiseMajContenuPanier = (): void => {
donnees.produits.forEach((ligne: WCStoreCartItem) => { donnees.produits.forEach((ligne: WCStoreCartItem) => {
// Met à jour les entrées du Panier // Met à jour les entrées du Panier
E.ENTREES_PANIER.ifRight((entrees: Array<HTMLElement>) => { E.ENTREES_PANIER.ifRight((entrees: Array<HTMLElement>) => {
Maybe.fromNullable(entrees.find((entree) => entree.getAttribute(ATTRIBUT_CLE_PANIER) === ligne.key)).ifJust( Maybe.fromNullable(entrees.find(entree => entree.getAttribute(ATTRIBUT_CLE_PANIER) === ligne.key)).ifJust(
(entree: HTMLElement) => { (entree: HTMLElement) => {
// Fonction utilitaire // Fonction utilitaire
const recupereElementDansEntree = recupereElementDansEntreePanierOuLeve(entree); const recupereElementDansEntree = recupereElementDansEntreePanierOuLeve(entree);
@ -144,7 +143,9 @@ const initialiseMajContenuPanier = (): void => {
// Reporte tout Erreur et réactive les Boutons // Reporte tout Erreur et réactive les Boutons
.ifLeft((erreur: CleNonTrouveError | ValiError<typeof MessageMajContenuPanierSchema>) => { .ifLeft((erreur: CleNonTrouveError | ValiError<typeof MessageMajContenuPanierSchema>) => {
reporteErreur(erreur); reporteErreur(erreur);
E.ENTREES_PANIER.ifRight((entrees) => majEtatsActivationBoutons(entrees)); E.ENTREES_PANIER.ifRight(entrees => {
majEtatsActivationBoutons(entrees);
});
}); });
}; };
}; };
@ -157,7 +158,9 @@ const initialiseMajFormulairesPanier = (): void => {
// Rend visible le formulaire de facturation. // Rend visible le formulaire de facturation.
E.FORMULAIRE_FACTURATION.removeAttribute(ATTRIBUT_HIDDEN); E.FORMULAIRE_FACTURATION.removeAttribute(ATTRIBUT_HIDDEN);
getDOMElementsWithSelector(E.FORMULAIRE_FACTURATION)("input, select").ifRight( getDOMElementsWithSelector(E.FORMULAIRE_FACTURATION)("input, select").ifRight(
arrayForEach((champ) => champ.removeAttribute(ATTRIBUT_DESACTIVE)), arrayForEach(champ => {
champ.removeAttribute(ATTRIBUT_DESACTIVE);
}),
); );
}) })
// Les Adresses sont combinées. // Les Adresses sont combinées.
@ -167,7 +170,7 @@ const initialiseMajFormulairesPanier = (): void => {
getDOMElementsWithSelector(E.FORMULAIRE_FACTURATION)<HTMLInputElement | HTMLSelectElement>( getDOMElementsWithSelector(E.FORMULAIRE_FACTURATION)<HTMLInputElement | HTMLSelectElement>(
"input, select", "input, select",
).ifRight( ).ifRight(
arrayForEach((champ) => { arrayForEach(champ => {
champ.setAttribute(ATTRIBUT_DESACTIVE, ""); champ.setAttribute(ATTRIBUT_DESACTIVE, "");
champ.value = ""; champ.value = "";
}), }),

View file

@ -0,0 +1,132 @@
import { Array as FxArray, Console, Context, Effect, HashMap, Layer, ManagedRuntime, Option, pipe } from "effect";
import type { NonEmptyReadonlyArray } from "effect/Array";
import type { NoSuchElementError } from "effect/Cause";
import { getAllSelectorFromDocument, getFirstSelectorFromDocument } from "../scripts-effect/lib/dom.ts";
import {
ATTRIBUT_ARIA_CONTROLS,
ATTRIBUT_ARIA_EXPANDED,
ATTRIBUT_HIDDEN,
DOM_BOUTON_AJOUT_PANIER,
DOM_BOUTONS_ACCORDEON,
DOM_CONTENUS_ACCORDEON,
DOM_PRIX_PRODUIT,
} from "./constantes/dom.ts";
import type { WCStoreCartAddItemArgsItems } from "./lib/types/api/cart-add-item.d.ts";
/** Représente un ensemble bouton-contenu d'une Section dans la description du Produit. */
type DetailEnsemble = {
button: HTMLButtonElement;
content: HTMLDivElement;
};
class ProductPageElements extends Context.Service<
ProductPageElements,
{
AddProductButton: HTMLButtonElement;
Details: HashMap.HashMap<string, DetailEnsemble>;
DetailsButtons: NonEmptyReadonlyArray<HTMLButtonElement>;
DetailsContents: NonEmptyReadonlyArray<HTMLDivElement>;
ProductPrice: HTMLParagraphElement;
ProductRawJson: HTMLScriptElement;
VariationChoiceForm: HTMLFormElement;
VariationSelectors: ReadonlyArray<HTMLSelectElement>;
}
>()("haikuatelier.fr/Produit/ProductPageElements") {
static readonly layer = Layer.effect(
ProductPageElements,
Effect.gen(function*() {
const AddProductButton = yield* getFirstSelectorFromDocument<HTMLButtonElement>(DOM_BOUTON_AJOUT_PANIER);
const DetailsButtons = yield* getAllSelectorFromDocument<HTMLButtonElement>(DOM_BOUTONS_ACCORDEON);
const DetailsContents = yield* getAllSelectorFromDocument<HTMLDivElement>(DOM_CONTENUS_ACCORDEON);
const ProductPrice = yield* getFirstSelectorFromDocument<HTMLParagraphElement>(DOM_PRIX_PRODUIT);
const ProductRawJson = yield* getFirstSelectorFromDocument<HTMLScriptElement>("#product-json");
const VariationChoiceForm = yield* getFirstSelectorFromDocument<HTMLFormElement>("#variation-choice");
const VariationSelectors = yield* pipe(
getAllSelectorFromDocument<HTMLSelectElement>(".selecteur-produit select"),
Option.orElseSome(() => FxArray.empty<HTMLSelectElement>()),
);
const Details = yield* pipe(
DetailsButtons,
FxArray.map(
(button: HTMLButtonElement, index: number): Effect.Effect<[string, DetailEnsemble], NoSuchElementError> =>
Effect.gen(function*() {
const contentId = yield* Option.fromNullishOr(button.getAttribute(ATTRIBUT_ARIA_CONTROLS));
const content = yield* FxArray.get(DetailsContents, index);
return [contentId, { button, content } satisfies DetailEnsemble];
}),
),
Effect.all,
Effect.map(HashMap.fromIterable<string, DetailEnsemble>),
);
return ProductPageElements.of({
AddProductButton,
Details,
DetailsButtons,
DetailsContents,
ProductPrice,
ProductRawJson,
VariationChoiceForm,
VariationSelectors,
});
}),
);
}
class ProductPageDOM extends Context.Service<
ProductPageDOM,
{
/**
* Récupère les Attributs du Produit depuis les Elements au sein du DOM.
*/
getProductAttributesFromDOM: () => Effect.Effect<ReadonlyArray<WCStoreCartAddItemArgsItems>>;
/**
* Replie toutes les sections de la description du Produit.
*/
toggleAllDetails: () => Effect.Effect<void>;
}
>()("haikuatelier.fr/Produit/ProductPageDOM") {
static readonly layer = Layer.effect(
ProductPageDOM,
Effect.gen(function*() {
const { Details, VariationSelectors } = yield* ProductPageElements;
const toggleAllDetails: () => Effect.Effect<void> = () =>
Effect.sync((): void => {
pipe(
// Récupère les Sections sous forme d'Ensembles.
[...HashMap.values(Details)],
FxArray.forEach((detail: DetailEnsemble) => {
detail.button.toggleAttribute(ATTRIBUT_ARIA_EXPANDED, false);
detail.content.toggleAttribute(ATTRIBUT_HIDDEN, true);
}),
);
});
const getProductAttributesFromDOM: () => Effect.Effect<ReadonlyArray<WCStoreCartAddItemArgsItems>> = () =>
Effect.sync(() =>
FxArray.map(VariationSelectors, (select: HTMLSelectElement) => ({
attribute: select.id,
value: select.value,
}))
);
return ProductPageDOM.of({
getProductAttributesFromDOM,
toggleAllDetails,
});
}),
);
}
const ProductPageRuntime = ManagedRuntime.make(
pipe(
ProductPageDOM.layer,
Layer.provide(ProductPageElements.layer),
Layer.tapError(error => Console.error("ManagedRuntime", "Impossible de créer le Layer :", error.name)),
),
);
export { type DetailEnsemble, ProductPageDOM, ProductPageElements, ProductPageRuntime };

View file

@ -3,25 +3,14 @@
import { pipe } from "@mobily/ts-belt"; import { pipe } from "@mobily/ts-belt";
import { get as dictGet } from "@mobily/ts-belt/Dict"; import { get as dictGet } from "@mobily/ts-belt/Dict";
import { tap as optionTap } from "@mobily/ts-belt/Option"; import { tap as optionTap } from "@mobily/ts-belt/Option";
import { import { Array as FxArray, Console, Effect, HashMap, Option, pipe as epipe, Stream } from "effect";
Array as FxArray,
Effect,
pipe as epipe,
Option,
Stream,
ServiceMap,
Layer,
ManagedRuntime,
Console,
HashMap,
} from "effect";
import { EitherAsync } from "purify-ts"; import { EitherAsync } from "purify-ts";
import { match, P } from "ts-pattern"; import { match, P } from "ts-pattern";
import { ValiError } from "valibot"; import { ValiError } from "valibot";
import type { AnySchema } from "valibot"; import type { AnySchema } from "valibot";
import type { WCStoreCart } from "./lib/types/api/cart.ts";
import type { WCStoreCartAddItemArgs, WCStoreCartAddItemArgsItems } from "./lib/types/api/cart-add-item.ts"; import type { WCStoreCartAddItemArgs, WCStoreCartAddItemArgsItems } from "./lib/types/api/cart-add-item.ts";
import type { WCStoreCart } from "./lib/types/api/cart.ts";
import type { FetchErrors } from "./lib/types/reseau.ts"; import type { FetchErrors } from "./lib/types/reseau.ts";
import { ROUTE_API_AJOUTE_ARTICLE_PANIER } from "./constantes/api.ts"; import { ROUTE_API_AJOUTE_ARTICLE_PANIER } from "./constantes/api.ts";
@ -44,15 +33,8 @@ import { emetMessageMajBoutonPanier } from "./lib/messages.ts";
import { newPartialResponse, postBackend, safeFetch } from "./lib/reseau.ts"; import { newPartialResponse, postBackend, safeFetch } from "./lib/reseau.ts";
import { WCStoreCartAddItemArgsSchema } from "./lib/schemas/api/cart-add-item.ts"; import { WCStoreCartAddItemArgsSchema } from "./lib/schemas/api/cart-add-item.ts";
import { WCStoreCartSchema } from "./lib/schemas/api/cart.ts"; import { WCStoreCartSchema } from "./lib/schemas/api/cart.ts";
import { safeSchemaParse } from "./lib/validation"; import { safeSchemaParse } from "./lib/validation.ts";
import { getAllSelectorFromDocument, getFirstSelectorFromDocument } from "../scripts-effect/lib/dom.ts"; import { ProductPageElements, ProductPageRuntime } from "./scripts-page-produit-service.ts";
import { NonEmptyReadonlyArray } from "effect/Array";
import { NoSuchElementError } from "effect/Cause";
type DetailEnsemble = {
button: HTMLButtonElement;
content: HTMLDivElement;
};
/** États utiles pour les scripts de la page. */ /** États utiles pour les scripts de la page. */
type EtatsPage = { type EtatsPage = {
@ -65,109 +47,6 @@ type EtatsPage = {
// @ts-expect-error -- États injectés par le modèle PHP // @ts-expect-error -- États injectés par le modèle PHP
const ETATS_PAGE: EtatsPage = _etats; const ETATS_PAGE: EtatsPage = _etats;
class ProductPageElements extends ServiceMap.Service<
ProductPageElements,
{
AddProductButton: HTMLButtonElement;
DetailsButtons: NonEmptyReadonlyArray<HTMLButtonElement>;
DetailsContents: NonEmptyReadonlyArray<HTMLDivElement>;
Details: HashMap.HashMap<string, DetailEnsemble>;
ProductPrice: HTMLParagraphElement;
ProductRawJson: HTMLScriptElement;
VariationChoiceForm: HTMLFormElement;
VariationSelectors: ReadonlyArray<HTMLSelectElement>;
}
>()("haikuatelier.fr/Produit/ProductPageElements") {
static readonly layer = Layer.effect(
ProductPageElements,
Effect.gen(function* () {
const AddProductButton = yield* getFirstSelectorFromDocument<HTMLButtonElement>(DOM_BOUTON_AJOUT_PANIER);
const DetailsButtons = yield* getAllSelectorFromDocument<HTMLButtonElement>(DOM_BOUTONS_ACCORDEON);
const DetailsContents = yield* getAllSelectorFromDocument<HTMLDivElement>(DOM_CONTENUS_ACCORDEON);
const ProductPrice = yield* getFirstSelectorFromDocument<HTMLParagraphElement>(DOM_PRIX_PRODUIT);
const ProductRawJson = yield* getFirstSelectorFromDocument<HTMLScriptElement>("#product-json");
const VariationChoiceForm = yield* getFirstSelectorFromDocument<HTMLFormElement>("#variation-choice");
const VariationSelectors = yield* pipe(
getAllSelectorFromDocument<HTMLSelectElement>(".selecteur-produit select"),
Option.orElseSome(() => FxArray.empty<HTMLSelectElement>()),
);
const Details = yield* pipe(
DetailsButtons,
FxArray.map(
(button: HTMLButtonElement, index: number): Effect.Effect<[string, DetailEnsemble], NoSuchElementError> =>
Effect.gen(function* () {
const contentId = yield* Option.fromNullishOr(button.getAttribute(ATTRIBUT_ARIA_CONTROLS));
const content = yield* FxArray.get(DetailsContents, index);
return [contentId, { button, content } satisfies DetailEnsemble];
}),
),
Effect.all,
Effect.map(HashMap.fromIterable<string, DetailEnsemble>),
);
return {
AddProductButton,
DetailsButtons,
DetailsContents,
Details,
ProductPrice,
ProductRawJson,
VariationChoiceForm,
VariationSelectors,
};
}),
);
}
const ProductPageRuntime = ManagedRuntime.make(
pipe(
ProductPageElements.layer,
Layer.tapError((error) => Console.error("ManagedRuntime", "Impossible de créer le Layer :", error.name)),
),
);
// Éléments d'intérêt
const E = {
BOUTON_AJOUT_PANIER: mustGetEleInDocument<HTMLButtonElement>(DOM_BOUTON_AJOUT_PANIER),
BOUTONS_ACCORDEON: mustGetElesInDocument<HTMLAnchorElement>(DOM_BOUTONS_ACCORDEON),
CONTENUS_ACCORDEON: mustGetElesInDocument<HTMLDivElement>(DOM_CONTENUS_ACCORDEON),
DOM_VARIATION: recupereElementDocumentEither<HTMLSelectElement>(DOM_DOM_QUANTITE),
PRIX_PRODUIT: mustGetEleInDocument<HTMLParagraphElement>(DOM_PRIX_PRODUIT),
PRODUCT_JSON: mustGetEleInDocument<HTMLScriptElement>("#product-json"),
VARIATION_CHOICE_FORM: mustGetEleInDocument<HTMLFormElement>("#variation-choice"),
};
const toggleAllDetails = Effect.fn("toggleAllDetails")(function* () {
const PageElements = yield* ProductPageElements;
// Récupère les Ensembles sous forme de tableau.
const details = [...HashMap.values(PageElements.Details)];
FxArray.forEach(details, (detail: DetailEnsemble) => {
detail.button.toggleAttribute(ATTRIBUT_ARIA_EXPANDED, false);
detail.content.toggleAttribute(ATTRIBUT_HIDDEN, true);
});
});
// TODO: Utiliser Effect.
const getAttributesFromDom = (): ReadonlyArray<WCStoreCartAddItemArgsItems> => {
const selectElements = epipe(
document.querySelectorAll<HTMLSelectElement>(".selecteur-produit select"),
Array.from<HTMLSelectElement>,
);
if (selectElements.length === 0) {
return [];
}
const attributes = selectElements.map((select: HTMLSelectElement) => ({
attribute: select.id,
value: select.value,
}));
return attributes;
};
const areArraysEqual = <T>(array1: Array<T>, array2: Array<T>): boolean => { const areArraysEqual = <T>(array1: Array<T>, array2: Array<T>): boolean => {
if (array1 !== array2) { if (array1 !== array2) {
const a1 = JSON.stringify(array1.toSorted()); const a1 = JSON.stringify(array1.toSorted());
@ -186,7 +65,7 @@ const updatePriceOnAttributeChange = (): void => {
const productVariations: Array<unknown> = epipe(E.PRODUCT_JSON.textContent, JSON.parse)?.variations; const productVariations: Array<unknown> = epipe(E.PRODUCT_JSON.textContent, JSON.parse)?.variations;
const chosenAttributes = getAttributesFromDom(); const chosenAttributes = getAttributesFromDom();
const chosenVariation = productVariations.find((v) => areArraysEqual(v.attributes, chosenAttributes)); const chosenVariation = productVariations.find(v => areArraysEqual(v.attributes, chosenAttributes));
const newPrice: string = chosenVariation.price; const newPrice: string = chosenVariation.price;
E.PRIX_PRODUIT.textContent = `${newPrice}`; E.PRIX_PRODUIT.textContent = `${newPrice}`;
@ -227,7 +106,7 @@ const ajouteProduitAuPanier = (event: MouseEvent): void => {
nonce: ETATS_PAGE.nonce, nonce: ETATS_PAGE.nonce,
route: ROUTE_API_AJOUTE_ARTICLE_PANIER, route: ROUTE_API_AJOUTE_ARTICLE_PANIER,
}), }),
), )
) )
// 4. Traite les cas d'Erreurs et récupère le Corps de la Réponse // 4. Traite les cas d'Erreurs et récupère le Corps de la Réponse
.chain((reponse: Response) => .chain((reponse: Response) =>
@ -236,9 +115,9 @@ const ajouteProduitAuPanier = (event: MouseEvent): void => {
match(await newPartialResponse(reponse)) match(await newPartialResponse(reponse))
.with({ status: 500 }, () => throwE(new ServerError("500 Server Error"))) .with({ status: 500 }, () => throwE(new ServerError("500 Server Error")))
.with({ status: 400 }, () => throwE(new BadRequestError("400 Bad Request Error"))) .with({ status: 400 }, () => throwE(new BadRequestError("400 Bad Request Error")))
.with({ status: 201 }, (r) => r.body) .with({ status: 201 }, r => r.body)
.otherwise((erreur) => throwE(new Error(`Erreur inconnue ${String(erreur.status)}`))), .otherwise(erreur => throwE(new Error(`Erreur inconnue ${String(erreur.status)}`)))
), )
) )
// 5. Vérifie le Schéma de la Réponse // 5. Vérifie le Schéma de la Réponse
.chain((corpsReponse: unknown) => EitherAsync.liftEither(safeSchemaParse(corpsReponse, WCStoreCartSchema))) .chain((corpsReponse: unknown) => EitherAsync.liftEither(safeSchemaParse(corpsReponse, WCStoreCartSchema)))
@ -250,21 +129,21 @@ const ajouteProduitAuPanier = (event: MouseEvent): void => {
E.BOUTON_AJOUT_PANIER.textContent = "Added to cart!"; E.BOUTON_AJOUT_PANIER.textContent = "Added to cart!";
emetMessageMajBoutonPanier({ quantiteProduits: totalArticles }); emetMessageMajBoutonPanier({ quantiteProduits: totalArticles });
}), }),
), )
) )
.ifLeft((erreur: BadRequestError | FetchErrors | ServerError | ValiError<AnySchema>) => { .ifLeft((erreur: BadRequestError | FetchErrors | ServerError | ValiError<AnySchema>) => {
match(erreur) match(erreur)
.with(P.instanceOf(ValiError), (e) => { .with(P.instanceOf(ValiError), e => {
reporteErreur(e); reporteErreur(e);
console.error(e.issues); console.error(e.issues);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
}) })
.with(P.instanceOf(ServerError), P.instanceOf(BadRequestError), (e) => { .with(P.instanceOf(ServerError), P.instanceOf(BadRequestError), e => {
reporteErreur(e); reporteErreur(e);
console.error(e); console.error(e);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_SOUMISSION_ADRESSES;
}) })
.with(P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), (e) => { .with(P.instanceOf(DOMException), P.instanceOf(TypeError), P.instanceOf(Error), e => {
reporteErreur(e); reporteErreur(e);
console.error(e); console.error(e);
// E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU; // E.MESSAGE_ADRESSES.textContent = ERREUR_GENERIQUE_RESEAU;
@ -284,7 +163,7 @@ const ajouteProduitAuPanier = (event: MouseEvent): void => {
/** /**
* Initialise l'état initial d'interactivité du Bouton d'ajout de Produit au Panier. * Initialise l'état initial d'interactivité du Bouton d'ajout de Produit au Panier.
*/ */
const initAddToCartButton = Effect.fn("initAddToCartButton")(function* () { const initAddToCartButton = Effect.fn("initAddToCartButton")(function*() {
const { AddProductButton, VariationSelectors } = yield* ProductPageElements; const { AddProductButton, VariationSelectors } = yield* ProductPageElements;
/** Est-ce que le Produit affiché est en stock ? */ /** Est-ce que le Produit affiché est en stock ? */
const isProductInStock = AddProductButton.hasAttribute("data-in-stock") === true; const isProductInStock = AddProductButton.hasAttribute("data-in-stock") === true;
@ -304,10 +183,10 @@ const initAddToCartButton = Effect.fn("initAddToCartButton")(function* () {
return yield* Effect.void; return yield* Effect.void;
}); });
const onFormChange = Effect.fnUntraced(function* (event: Event) { const onFormChange = Effect.fnUntraced(function*(evt: Event) {
const { AddProductButton } = yield* ProductPageElements; const { AddProductButton } = yield* ProductPageElements;
// La cible ne peut qu'être un Formulaire. // La cible ne peut qu'être un Formulaire.
const target = event.target as HTMLFormElement; const target: HTMLFormElement = evt.target as HTMLFormElement;
const isClickAllowed = target.checkValidity() === false; const isClickAllowed = target.checkValidity() === false;
// Active/désactive le Bouton en fonction de la validité du Formulaire du Produit. // Active/désactive le Bouton en fonction de la validité du Formulaire du Produit.
@ -319,7 +198,7 @@ const onFormChange = Effect.fnUntraced(function* (event: Event) {
/** /**
* Initialise la mise à jour de l'état d'interactivité du Bouton d'ajout de Produit au Panier en fonction des actions de l'Utilisateur. * Initialise la mise à jour de l'état d'interactivité du Bouton d'ajout de Produit au Panier en fonction des actions de l'Utilisateur.
*/ */
const initAddToCartInteractionUpdates = Effect.fn("initAddToCartInteractionUpdates")(function* () { const initAddToCartInteractionUpdates = Effect.fn("initAddToCartInteractionUpdates")(function*() {
return yield* pipe( return yield* pipe(
Stream.fromEventListener(E.VARIATION_CHOICE_FORM, "change"), Stream.fromEventListener(E.VARIATION_CHOICE_FORM, "change"),
Stream.tap(onFormChange), Stream.tap(onFormChange),
@ -327,13 +206,13 @@ const initAddToCartInteractionUpdates = Effect.fn("initAddToCartInteractionUpdat
); );
}); });
const onDetailButtonClick = Effect.fnUntraced(function* (event: Event) { const onDetailButtonClick = Effect.fnUntraced(function*(evt: Event) {
const { Details } = yield* ProductPageElements; const { Details } = yield* ProductPageElements;
// Empêche la pollution de l'historique de navigation // Empêche la pollution de l'historique de navigation
event.preventDefault(); evt.preventDefault();
// La cible est connue. // La cible est connue.
const target = event.target as HTMLButtonElement; const target = evt.target as HTMLButtonElement;
// Récupère le contenu correspondant. // Récupère le contenu correspondant.
const linkedSection = yield* pipe( const linkedSection = yield* pipe(
Option.fromNullishOr(target.getAttribute(ATTRIBUT_ARIA_CONTROLS)), Option.fromNullishOr(target.getAttribute(ATTRIBUT_ARIA_CONTROLS)),
@ -357,18 +236,36 @@ const onDetailButtonClick = Effect.fnUntraced(function* (event: Event) {
return yield* Effect.void; return yield* Effect.void;
}); });
const initDetailInteractions = Effect.fn("initDetailInteractions")(function* () { const initDetailInteractions = Effect.fn("initDetailInteractions")(function*() {
const PageElements = yield* ProductPageElements; const PageElements = yield* ProductPageElements;
return yield* pipe( return yield* pipe(
FxArray.map(PageElements.DetailsButtons, (button: HTMLButtonElement) => FxArray.map(
pipe(Stream.fromEventListener(button, "click"), Stream.tap(onDetailButtonClick)), PageElements.DetailsButtons,
(button: HTMLButtonElement) => pipe(Stream.fromEventListener(button, "click"), Stream.tap(onDetailButtonClick)),
), ),
Stream.mergeAll({ concurrency: "unbounded" }), Stream.mergeAll({ concurrency: "unbounded" }),
Stream.runDrain, Stream.runDrain,
); );
}); });
const getAttributesFromDom = (): ReadonlyArray<WCStoreCartAddItemArgsItems> => {
const selectElements = epipe(
document.querySelectorAll<HTMLSelectElement>(".selecteur-produit select"),
Array.from<HTMLSelectElement>,
);
if (selectElements.length === 0) {
return [];
}
const attributes = selectElements.map((select: HTMLSelectElement) => ({
attribute: select.id,
value: select.value,
}));
return attributes;
};
document.addEventListener("DOMContentLoaded", (): void => { document.addEventListener("DOMContentLoaded", (): void => {
ProductPageRuntime.runFork(pipe(initAddToCartButton(), Effect.tapCause(Console.error))); ProductPageRuntime.runFork(pipe(initAddToCartButton(), Effect.tapCause(Console.error)));
ProductPageRuntime.runFork(pipe(initAddToCartInteractionUpdates(), Effect.tapCause(Console.error))); ProductPageRuntime.runFork(pipe(initAddToCartInteractionUpdates(), Effect.tapCause(Console.error)));

View file

@ -1,7 +1,7 @@
/// <reference types="vite/client" /> /// <reference types="vite/client" />
type ImportMeta = { type ImportMeta = Readonly<{
readonly env: ImportMetaEnv; env: ImportMetaEnv;
}; }>;
type ImportMetaEnv = {}; type ImportMetaEnv = {};

View file

@ -37,6 +37,7 @@ $products = wc_get_products([
]) ])
|> function (/** @var list<WC_Product>|stdClass */ mixed $products): array { |> function (/** @var list<WC_Product>|stdClass */ mixed $products): array {
assert(is_array($products), 'Les Produits de la Catégorie doivent être un tableau.'); assert(is_array($products), 'Les Produits de la Catégorie doivent être un tableau.');
return $products; return $products;
} }
|> (static fn(/** @var list<WC_Product> */ array $products): array => Arr::map( |> (static fn(/** @var list<WC_Product> */ array $products): array => Arr::map(

View file

@ -12,7 +12,7 @@ use Illuminate\Support\Str;
use Timber\Timber; use Timber\Timber;
if (!defined('ABSPATH')) { if (!defined('ABSPATH')) {
exit(); exit();
} }
// Initialise Timber // Initialise Timber
@ -30,13 +30,13 @@ $commande = $order;
$date = new Carbon($commande->get_date_created()); $date = new Carbon($commande->get_date_created());
$email = [ $email = [
'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()], 'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()],
'livraison' => [ 'livraison' => [
'transporteur' => Str::of($commande->get_shipping_method())->replace(' (Free)', ''), 'transporteur' => Str::of($commande->get_shipping_method())->replace(' (Free)', ''),
'numero_suivi' => blank($commande->get_meta('tracking_number')) 'numero_suivi' => blank($commande->get_meta('tracking_number'))
? 'UNKNOWN_TRACKING_NUMBER' ? 'UNKNOWN_TRACKING_NUMBER'
: $commande->get_meta('tracking_number'), : $commande->get_meta('tracking_number'),
], ],
]; ];
$context['commande'] = $email; $context['commande'] = $email;

View file

@ -13,7 +13,7 @@ use Illuminate\Support\Str;
use Timber\Timber; use Timber\Timber;
if (!defined('ABSPATH')) { if (!defined('ABSPATH')) {
exit(); exit();
} }
// Initialise Timber // Initialise Timber
@ -31,44 +31,49 @@ $commande = $order;
$date = new Carbon($commande->get_date_created()); $date = new Carbon($commande->get_date_created());
$email = [ $email = [
'adresses' => ['facturation' => $commande->get_address('billing'), 'livraison' => $commande->get_address('shipping')], 'adresses' => [
'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()], 'facturation' => $commande->get_address('billing'),
'livraison' => [ 'livraison' => $commande->get_address('shipping'),
'methode' => $commande->get_shipping_method(), ],
'numero_suivi' => $commande->get_meta('tracking_number'), 'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()],
], 'livraison' => [
'paiement' => ['methode' => ''], 'methode' => $commande->get_shipping_method(),
'produits' => collect($commande->get_items())->map(static function (WC_Order_Item_Product $article) { 'numero_suivi' => $commande->get_meta('tracking_number'),
$produit = $article->get_product(); ],
'paiement' => ['methode' => ''],
'produits' => collect($commande->get_items())->map(static function (WC_Order_Item_Product $article) {
$produit = $article->get_product();
if (is_bool($produit) || $produit === null) { if (is_bool($produit) || $produit === null) {
return []; return [];
} }
return [ return [
// Récupère l'Attribut d'un Produit variable ou renvoie un tableau vide // Récupère l'Attribut d'un Produit variable ou renvoie un tableau vide
'attribut' => $produit->is_type('variable') 'attribut' => $produit->is_type('variable')
? collect($produit->get_attributes()) ? collect($produit->get_attributes())
->mapWithKeys(static fn($_atr, $cle): array => [ ->mapWithKeys(static fn($_atr, $cle): array => [
'nom' => Str::lower(wc_attribute_label($cle, $produit)), 'nom' => Str::lower(wc_attribute_label($cle, $produit)),
'valeur' => $produit->get_attribute($cle), 'valeur' => $produit->get_attribute($cle),
]) ])
->toArray() ->toArray()
: [], : [],
'lien' => $produit->get_permalink(), 'lien' => $produit->get_permalink(),
'nom' => $produit->get_title(), 'nom' => $produit->get_title(),
'prix_total' => $article->get_total(), 'prix_total' => $article->get_total(),
'quantite' => $article->get_quantity(), 'quantite' => $article->get_quantity(),
]; ];
}), }),
'totaux' => [ 'totaux' => [
'sous_total_livraison' => '0' === $commande->get_shipping_total() ? 'Free' : $commande->get_shipping_total() . '€', 'sous_total_livraison' => '0' === $commande->get_shipping_total()
'sous_total_produits' => $commande->get_subtotal() . '€', ? 'Free'
'sous_total_reduction' => '0.00' === $commande->get_discount_total() : $commande->get_shipping_total() . '€',
? '0' 'sous_total_produits' => $commande->get_subtotal() . '€',
: Number::format((float) $commande->get_discount_total(), maxPrecision: 2) . '€', 'sous_total_reduction' => '0.00' === $commande->get_discount_total()
'total' => Number::format((float) $commande->get_total(), maxPrecision: 2) . '€', ? '0'
], : Number::format((float) $commande->get_discount_total(), maxPrecision: 2) . '€',
'total' => Number::format((float) $commande->get_total(), maxPrecision: 2) . '€',
],
]; ];
// Transforme les codes de pays en noms de pays // Transforme les codes de pays en noms de pays
$email['adresses']['livraison']['country'] = WC()->countries->countries[$commande->get_shipping_country()]; $email['adresses']['livraison']['country'] = WC()->countries->countries[$commande->get_shipping_country()];

View file

@ -13,7 +13,7 @@ use Illuminate\Support\Str;
use Timber\Timber; use Timber\Timber;
if (!defined('ABSPATH')) { if (!defined('ABSPATH')) {
exit(); exit();
} }
// Initialise Timber // Initialise Timber
@ -31,40 +31,45 @@ $commande = $order;
$date = new Carbon($commande->get_date_created()); $date = new Carbon($commande->get_date_created());
$email = [ $email = [
'adresses' => ['facturation' => $commande->get_address('billing'), 'livraison' => $commande->get_address('shipping')], 'adresses' => [
'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()], 'facturation' => $commande->get_address('billing'),
'paiement' => ['methode' => ''], 'livraison' => $commande->get_address('shipping'),
'produits' => collect($commande->get_items())->map(static function (WC_Order_Item_Product $article) { ],
$produit = $article->get_product(); 'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()],
'paiement' => ['methode' => ''],
'produits' => collect($commande->get_items())->map(static function (WC_Order_Item_Product $article) {
$produit = $article->get_product();
if (is_bool($produit) || $produit === null) { if (is_bool($produit) || $produit === null) {
return []; return [];
} }
return [ return [
// Récupère l'Attribut d'un Produit variable ou renvoie un tableau vide // Récupère l'Attribut d'un Produit variable ou renvoie un tableau vide
'attribut' => $article->is_type('variable') 'attribut' => $article->is_type('variable')
? collect($produit->get_attributes()) ? collect($produit->get_attributes())
->mapWithKeys(static fn($_atr, $cle): array => [ ->mapWithKeys(static fn($_atr, $cle): array => [
'nom' => Str::lower(wc_attribute_label($cle, $produit)), 'nom' => Str::lower(wc_attribute_label($cle, $produit)),
'valeur' => $produit->get_attribute($cle), 'valeur' => $produit->get_attribute($cle),
]) ])
->toArray() ->toArray()
: [], : [],
'lien' => $produit->get_permalink(), 'lien' => $produit->get_permalink(),
'nom' => $produit->get_title(), 'nom' => $produit->get_title(),
'prix_total' => $article->get_total(), 'prix_total' => $article->get_total(),
'quantite' => $article->get_quantity(), 'quantite' => $article->get_quantity(),
]; ];
}), }),
'totaux' => [ 'totaux' => [
'sous_total_livraison' => '0' === $commande->get_shipping_total() ? 'Free' : $commande->get_shipping_total() . '€', 'sous_total_livraison' => '0' === $commande->get_shipping_total()
'sous_total_produits' => $commande->get_subtotal() . '€', ? 'Free'
'sous_total_reduction' => '0.00' === $commande->get_discount_total() : $commande->get_shipping_total() . '€',
? '0' 'sous_total_produits' => $commande->get_subtotal() . '€',
: Number::format((float) $commande->get_discount_total(), maxPrecision: 2) . '€', 'sous_total_reduction' => '0.00' === $commande->get_discount_total()
'total' => Number::format((float) $commande->get_total(), maxPrecision: 2) . '€', ? '0'
], : Number::format((float) $commande->get_discount_total(), maxPrecision: 2) . '€',
'total' => Number::format((float) $commande->get_total(), maxPrecision: 2) . '€',
],
]; ];
// Transforme les codes de pays en noms de pays // Transforme les codes de pays en noms de pays
$email['adresses']['livraison']['country'] = WC()->countries->countries[$commande->get_shipping_country()]; $email['adresses']['livraison']['country'] = WC()->countries->countries[$commande->get_shipping_country()];