Compare commits

...

11 commits

59 changed files with 1818 additions and 1190 deletions

View file

@ -24,15 +24,13 @@ return new Config()
'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' => [ 'class_attributes_separation' => ['elements' => [
'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,
@ -56,7 +54,11 @@ return new Config()
'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,
@ -75,7 +77,11 @@ return new Config()
'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' => [
'include' => ['@compiler_optimized'],
'scope' => 'namespaced',
'strict' => true,
],
'native_type_declaration_casing' => true, 'native_type_declaration_casing' => true,
'new_expression_parentheses' => true, 'new_expression_parentheses' => true,
'no_alias_functions' => ['sets' => ['@all']], 'no_alias_functions' => ['sets' => ['@all']],
@ -95,8 +101,7 @@ return new Config()
'no_trailing_comma_in_singleline' => true, 'no_trailing_comma_in_singleline' => true,
'no_trailing_whitespace_in_comment' => true, 'no_trailing_whitespace_in_comment' => true,
'no_unneeded_braces' => ['namespaces' => true], 'no_unneeded_braces' => ['namespaces' => true],
'no_unneeded_control_parentheses' => [ 'no_unneeded_control_parentheses' => ['statements' => [
'statements' => [
'break', 'break',
'clone', 'clone',
'continue', 'continue',
@ -107,8 +112,7 @@ return new Config()
'switch_case', 'switch_case',
'yield', 'yield',
'yield_from', 'yield_from',
], ]],
],
'no_unneeded_final_method' => true, 'no_unneeded_final_method' => true,
'no_unneeded_import_alias' => true, 'no_unneeded_import_alias' => true,
'no_unreachable_default_argument_value' => true, 'no_unreachable_default_argument_value' => true,
@ -139,9 +143,11 @@ return new Config()
'pow_to_exponentiation' => true, 'pow_to_exponentiation' => true,
'protected_to_private' => true, 'protected_to_private' => true,
'psr_autoloading' => true, 'psr_autoloading' => true,
'random_api_migration' => [ 'random_api_migration' => ['replacements' => [
'replacements' => ['getrandmax' => 'mt_getrandmax', 'rand' => 'mt_rand', 'srand' => 'mt_srand'], 'getrandmax' => 'mt_getrandmax',
], 'rand' => 'mt_rand',
'srand' => 'mt_srand',
]],
'return_assignment' => true, 'return_assignment' => true,
'self_accessor' => true, 'self_accessor' => true,
'self_static_accessor' => true, 'self_static_accessor' => true,
@ -216,8 +222,7 @@ return new Config()
// The type of @return annotations of methods returning a reference to itself must the configured one. // The type of @return annotations of methods returning a reference to itself must the configured one.
'phpdoc_return_self_reference' => true, 'phpdoc_return_self_reference' => true,
// Scalar types should always be written in the same form. int not integer, bool not boolean, float not real or double. // Scalar types should always be written in the same form. int not integer, bool not boolean, float not real or double.
'phpdoc_scalar' => [ 'phpdoc_scalar' => ['types' => [
'types' => [
'boolean', 'boolean',
'callback', 'callback',
'double', 'double',
@ -227,8 +232,7 @@ return new Config()
'no-return', 'no-return',
'real', 'real',
'str', 'str',
], ]],
],
// 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. // 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.
'phpdoc_separation' => [ 'phpdoc_separation' => [
'groups' => [ 'groups' => [

View file

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

19
.phpantom.toml Normal file
View file

@ -0,0 +1,19 @@
# :schema: https://github.com/AJenbo/phpantom_lsp/raw/main/config-schema.json
[php]
# Override the detected PHP version (default: inferred from composer.json, or 8.5).
# version = "8.5"
#
[diagnostics]
extra-arguments = true
# Report member access on subjects whose type could not be resolved.
# Useful for discovering gaps in type coverage. Off by default.
unresolved-member-access = false
[indexing]
# How PHPantom discovers classes across the workspace.
# "composer" (default) - use Composer classmap, self-scan on fallback
# "self" - always self-scan, ignore Composer classmap
# "none" - no proactive scanning, Composer classmap only
strategy = "composer"

View file

@ -9,8 +9,10 @@
"!oxc", "!oxc",
"!oxfmt", "!oxfmt",
"!oxlint", "!oxlint",
"!phptools",
"!prettier", "!prettier",
"!tailwindcss-language-server", "!tailwindcss-language-server",
"!tsgo",
"!vtsls", "!vtsls",
"..." "..."
], ],

View file

@ -4,6 +4,9 @@ settings:
autoInstallPeers: true autoInstallPeers: true
excludeLinksFromLockfile: false excludeLinksFromLockfile: false
time:
globals@17.6.0: 2026-05-01T16:37:48.055Z
importers: importers:
.: .:
@ -12,14 +15,17 @@ importers:
specifier: v4.0.0-rc.5 specifier: v4.0.0-rc.5
version: 4.0.0-rc.5 version: 4.0.0-rc.5
'@sentry/browser': '@sentry/browser':
specifier: ^10.50.0 specifier: ^10.51.0
version: 10.50.0 version: 10.51.0
a11y-dialog: a11y-dialog:
specifier: ^8.1.5 specifier: ^8.1.5
version: 8.1.5 version: 8.1.5
effect: effect:
specifier: ^4.0.0-beta.59 specifier: ^4.0.0-beta.59
version: 4.0.0-beta.59 version: 4.0.0-beta.59
html-template-tag:
specifier: ^5.0.0
version: 5.0.0
lit-html: lit-html:
specifier: ^3.3.2 specifier: ^3.3.2
version: 3.3.2 version: 3.3.2
@ -52,8 +58,8 @@ importers:
specifier: ^0.85.1 specifier: ^0.85.1
version: 0.85.1 version: 0.85.1
'@effect/tsgo': '@effect/tsgo':
specifier: 0.5.1 specifier: ^0.5.2
version: 0.5.1 version: 0.5.2
'@gcch/configuration-eslint': '@gcch/configuration-eslint':
specifier: git+https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54 specifier: git+https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54
version: https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54e5bfd6251566d7469ee99204c19f45 version: https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54e5bfd6251566d7469ee99204c19f45
@ -67,8 +73,8 @@ importers:
specifier: ^1.59.1 specifier: ^1.59.1
version: 1.59.1 version: 1.59.1
'@sentry/core': '@sentry/core':
specifier: ^10.50.0 specifier: ^10.51.0
version: 10.50.0 version: 10.51.0
'@types/bun': '@types/bun':
specifier: ^1.3.13 specifier: ^1.3.13
version: 1.3.13 version: 1.3.13
@ -76,8 +82,8 @@ importers:
specifier: ^25.6.0 specifier: ^25.6.0
version: 25.6.0 version: 25.6.0
'@typescript/native-preview': '@typescript/native-preview':
specifier: 7.0.0-dev.20260429.1 specifier: 7.0.0-dev.20260503.1
version: 7.0.0-dev.20260429.1 version: 7.0.0-dev.20260503.1
'@vitejs/plugin-legacy': '@vitejs/plugin-legacy':
specifier: ^8.0.1 specifier: ^8.0.1
version: 8.0.1(terser@5.46.2)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3)) version: 8.0.1(terser@5.46.2)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3))
@ -91,32 +97,32 @@ importers:
specifier: ^1.0.30001791 specifier: ^1.0.30001791
version: 1.0.30001791 version: 1.0.30001791
eslint: eslint:
specifier: ^10.2.1 specifier: ^10.3.0
version: 10.2.1(jiti@2.6.1) version: 10.3.0(jiti@2.6.1)
eslint-plugin-functional: eslint-plugin-functional:
specifier: ^9.0.4 specifier: ^9.0.4
version: 9.0.4(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) version: 9.0.4(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
eslint-plugin-jsx-a11y: eslint-plugin-jsx-a11y:
specifier: ^6.10.2 specifier: ^6.10.2
version: 6.10.2(eslint@10.2.1(jiti@2.6.1)) version: 6.10.2(eslint@10.3.0(jiti@2.6.1))
eslint-plugin-oxlint: eslint-plugin-oxlint:
specifier: ^1.62.0 specifier: ^1.62.0
version: 1.62.0(oxlint@1.62.0(oxlint-tsgolint@0.22.1)) version: 1.62.0(oxlint@1.62.0(oxlint-tsgolint@0.22.1))
eslint-plugin-perfectionist: eslint-plugin-perfectionist:
specifier: ^5.9.0 specifier: ^5.9.0
version: 5.9.0(eslint@10.2.1(jiti@2.6.1)) version: 5.9.0(eslint@10.3.0(jiti@2.6.1))
fdir: fdir:
specifier: ^6.5.0 specifier: ^6.5.0
version: 6.5.0(picomatch@4.0.4) version: 6.5.0(picomatch@4.0.4)
globals: globals:
specifier: ^17.5.0 specifier: ^17.6
version: 17.5.0 version: 17.6.0
jiti: jiti:
specifier: ^2.6.1 specifier: ^2.6.1
version: 2.6.1 version: 2.6.1
knip: knip:
specifier: ^6.8.0 specifier: ^6.11.0
version: 6.8.0 version: 6.11.0
lightningcss: lightningcss:
specifier: ^1.32.0 specifier: ^1.32.0
version: 1.32.0 version: 1.32.0
@ -179,7 +185,7 @@ importers:
version: 6.0.3 version: 6.0.3
typescript-eslint: typescript-eslint:
specifier: ^8.59.1 specifier: ^8.59.1
version: 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) version: 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
vite: vite:
specifier: ^8.0.10 specifier: ^8.0.10
version: 8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3) version: 8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3)
@ -740,15 +746,15 @@ packages:
resolution: {integrity: sha512-EXnJjIy6zQ3nUO/MZ+ynWUb8B895KZPotd1++oTs9JjDkplwM7cb6zo8Zq2zU6piwq+KflO7amXbEfj1UMpHkw==} resolution: {integrity: sha512-EXnJjIy6zQ3nUO/MZ+ynWUb8B895KZPotd1++oTs9JjDkplwM7cb6zo8Zq2zU6piwq+KflO7amXbEfj1UMpHkw==}
hasBin: true hasBin: true
'@effect/tsgo-linux-x64@0.5.1': '@effect/tsgo-linux-x64@0.5.2':
resolution: {integrity: sha512-70dMv3/H+P3KDNWb31qPXJiJh6s78k3+J+QXN8RatKiQYrJw2HhREYL6ToVx9y5WOV7XFvC0eCIIa4/AMwQLTw==} resolution: {integrity: sha512-V6sHIZlKQv693ABb9REX0RzIvzyCbNg2uP5+4MXwetlSxz8pmeAUCpraAQLXBkKlYL5rG9kMIobDFU9A88Nqig==}
os: os:
- linux - linux
cpu: cpu:
- x64 - x64
'@effect/tsgo@0.5.1': '@effect/tsgo@0.5.2':
resolution: {integrity: sha512-INANZ/NK9akOwSQVWpQgSDLjlegrs4gui21nuQsgN7zCjCmj4m/ixUDuVgtW2C0UfqhPWWabyFWCDntu7ryCZQ==} resolution: {integrity: sha512-LEKmx1rwP1j3l9mPW6Bx8VIdGKW+uEvvML89z4xiWnPC+h/uFm3y6FGHULop9Kl09Ybwn2TVuZzVPSZLj+ydmg==}
hasBin: true hasBin: true
'@es-joy/jsdoccomment@0.86.0': '@es-joy/jsdoccomment@0.86.0':
@ -969,28 +975,28 @@ packages:
'@rolldown/pluginutils@1.0.0-rc.17': '@rolldown/pluginutils@1.0.0-rc.17':
resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==}
'@sentry-internal/browser-utils@10.50.0': '@sentry-internal/browser-utils@10.51.0':
resolution: {integrity: sha512-42bxyRTxnCmYlWnvz4CxikuQNanw8UNma2WJrtxJ0f1MAJV2GhQGSHDLnA+lvFlmiz6qct3pfen/NXGyOTegTA==} resolution: {integrity: sha512-lNKBS4P7RUvf1niojXQWe9bU3gnBUCbST4Dj0pSiyat1N96cXVyHkeE+uGxowD0RrVWhs+kGHiVX3FcmRWF6sA==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sentry-internal/feedback@10.50.0': '@sentry-internal/feedback@10.51.0':
resolution: {integrity: sha512-0k9XZF0wn86f77mIO2U3gNNyDZooy139CnEanRzHinrN106vVzvBZ6TUEQoHtoO1fqQxr+nWWVrqV/PXUqk47w==} resolution: {integrity: sha512-bCM95bcpphx28e6aU0bwRLxOgwosYsdNzezM1sM0pVOkb0TB3hDFRamramVDK+/Hp1o8qmRxS4c5w/A7YBZGkA==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sentry-internal/replay-canvas@10.50.0': '@sentry-internal/replay-canvas@10.51.0':
resolution: {integrity: sha512-jx6RKBmcJSWdI92qDGS/sBv1w+7Cww879Z/moX7bw7ipHa/Ts3iDcB3rgZwvhmi17U+mvYsbJeL2DXkPo3TjPw==} resolution: {integrity: sha512-8PW1Pp+Yl3lPwYqhBCr5SgkuhDanu9ZLzUqD2bPKL/ElqbM2eDVIWxq4z4ZzePrmZa6IcCjTv6sVQJ7Z4dLyLA==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sentry-internal/replay@10.50.0': '@sentry-internal/replay@10.51.0':
resolution: {integrity: sha512-51FYNfnvVLAWw1rrEWPFfwHuMRb9mkVCFGA4J9/un7SpeGBsQDziGB0Di4fsCxI7+EdSBpfLHPF0csKtCCw0oQ==} resolution: {integrity: sha512-jCpI5HXSwK6ZT2HX70+mDRciAocHzSiDk4DTgvzV69Wvd+Ei5WLgE+d39eaEPsm8lUC0Ydntb5sJIB6uG9D4bw==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sentry/browser@10.50.0': '@sentry/browser@10.51.0':
resolution: {integrity: sha512-1f6rAvET6myiTaSeYqvaaBwvq1LfxqWjAPIoAW/NVC9bPMkeEcuvgDajHrnZMrBeWoJ81NMyoLkyX+iOc7MoFA==} resolution: {integrity: sha512-Zdc0sKfenxUtW/OGhtJ7xHFN44bXR7YqxJ1zBDzlZfW0nTbeTTUZBq9z5NUw6qdS0Vs/i3V4qzAKTbRKWfqSEA==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sentry/core@10.50.0': '@sentry/core@10.51.0':
resolution: {integrity: sha512-J4A+vzUO3adl0TkFCjaN1+4miamrjHiEIYuLHiuu1lmAjq5WIVw32ObvAh4yMwNtxyaEMosTrrh5M6f12XSJFg==} resolution: {integrity: sha512-Y45V/YXvVLEXmOdkbD1oG1gkRWFi9guCEGg3PlIlIpRjAbZUrvLGgjRJIc1E7XpSzmOnWbs5BbUxMv4PDaPj2w==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@sindresorhus/base62@1.0.0': '@sindresorhus/base62@1.0.0':
@ -1201,16 +1207,16 @@ packages:
typescript: '>=4.5.2' typescript: '>=4.5.2'
aliasOf: '@better-typescript-lib/webworker' aliasOf: '@better-typescript-lib/webworker'
'@typescript/native-preview-linux-x64@7.0.0-dev.20260429.1': '@typescript/native-preview-linux-x64@7.0.0-dev.20260503.1':
resolution: {integrity: sha512-haAOqc0fJCZkt4RDi0/ZQGBdDfpDzr2N+mEcR+FbiYQD3Y00kOK34hXSrjZafO2kq56ZDWunvCaUTCev0fJDbA==} resolution: {integrity: sha512-M64z7LwpqNfOXYCBKmD/ObwyxYOobUk4tDv0ECNLit7pDER1sswNZjJGjgRYjQsKokmydy6p3FqtJ1uUPUP/sw==}
engines: {node: '>=16.20.0'} engines: {node: '>=16.20.0'}
os: os:
- linux - linux
cpu: cpu:
- x64 - x64
'@typescript/native-preview@7.0.0-dev.20260429.1': '@typescript/native-preview@7.0.0-dev.20260503.1':
resolution: {integrity: sha512-SGKnvs5EA+V1spnraYJqum/lEajE0IQ2bVVPC72hFfWjoCfQ6N7iVYxLUGreiE3VFyQWWQBPgXZrRUFnawVvpQ==} resolution: {integrity: sha512-gDro38CPFiBUGbaFGNt+ufOsEd1OrZrfrOPxsLSfBcvvoGaqAxV++ul/BHTOShoEkIYHiFsoDX2az1IPCDV2jQ==}
engines: {node: '>=16.20.0'} engines: {node: '>=16.20.0'}
hasBin: true hasBin: true
@ -1688,8 +1694,8 @@ packages:
resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24} engines: {node: ^20.19.0 || ^22.13.0 || >=24}
eslint@10.2.1: eslint@10.3.0:
resolution: {integrity: sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==} resolution: {integrity: sha512-XbEXaRva5cF0ZQB8w6MluHA0kZZfV2DuCMJ3ozyEOHLwDpZX2Lmm/7Pp0xdJmI0GL1W05VH5VwIFHEm1Vcw2gw==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24} engines: {node: ^20.19.0 || ^22.13.0 || >=24}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -1869,6 +1875,10 @@ packages:
resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==} resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==}
engines: {node: '>=18'} engines: {node: '>=18'}
globals@17.6.0:
resolution: {integrity: sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==}
engines: {node: '>=18'}
globalthis@1.0.4: globalthis@1.0.4:
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -1928,13 +1938,22 @@ packages:
hookified@2.2.0: hookified@2.2.0:
resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==} resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==}
html-element-attributes@3.5.0:
resolution: {integrity: sha512-rU2BFhp0kQla9sqPBI46C+zbP6PFOtD7z6XNAJ6as+cGecCDXLx0W3aIs6XdPLmBBG/Fy1meRi/n65Exofz4Qw==}
html-entities@2.6.0: html-entities@2.6.0:
resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==}
html-es6cape@2.0.2:
resolution: {integrity: sha512-utzhH8rq2VABdW1LsPdv5tmxeMNOtP83If0jKCa79xPBgLWfcMvdf9K+EZoxJ5P7KioCxTs6WBnSDWLQHJ2lWA==}
html-tags@5.1.0: html-tags@5.1.0:
resolution: {integrity: sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==} resolution: {integrity: sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==}
engines: {node: '>=20.10'} engines: {node: '>=20.10'}
html-template-tag@5.0.0:
resolution: {integrity: sha512-FwF3Fi+v5Dr6ygxqqyJwJWdHteQtDusRXF5ae1syxTKbbVRC8UPtlfIua5KWbgXGneRAc7zNc+Z6x9efFl0W/w==}
ignore@5.3.2: ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'} engines: {node: '>= 4'}
@ -2164,8 +2183,8 @@ packages:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
knip@6.8.0: knip@6.11.0:
resolution: {integrity: sha512-FaTrNiqc74KTUMI4KZ5CWWxR2oVTm/bEEik16NKz7usiUJXG4+Df2XA2SPAm+mG9bBY22NvBMM4IeBcUZFslyg==} resolution: {integrity: sha512-84PTlN8Q5smLpTbzs8smTVh8PMbTDXtw0tFksXq/m6auGFC/KSzJykKFmnYh3As38kiWDkoDBvdTTyKk5M1TAQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true hasBin: true
@ -3830,11 +3849,11 @@ snapshots:
'@effect/language-service@0.85.1': {} '@effect/language-service@0.85.1': {}
'@effect/tsgo-linux-x64@0.5.1': {} '@effect/tsgo-linux-x64@0.5.2': {}
'@effect/tsgo@0.5.1': '@effect/tsgo@0.5.2':
optionalDependencies: optionalDependencies:
'@effect/tsgo-linux-x64': 0.5.1 '@effect/tsgo-linux-x64': 0.5.2
'@es-joy/jsdoccomment@0.86.0': '@es-joy/jsdoccomment@0.86.0':
dependencies: dependencies:
@ -3846,9 +3865,9 @@ snapshots:
'@es-joy/resolve.exports@1.2.0': {} '@es-joy/resolve.exports@1.2.0': {}
'@eslint-community/eslint-utils@4.9.1(eslint@10.2.1(jiti@2.6.1))': '@eslint-community/eslint-utils@4.9.1(eslint@10.3.0(jiti@2.6.1))':
dependencies: dependencies:
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.2': {} '@eslint-community/regexpp@4.12.2': {}
@ -3867,9 +3886,9 @@ snapshots:
dependencies: dependencies:
'@types/json-schema': 7.0.15 '@types/json-schema': 7.0.15
'@eslint/js@10.0.1(eslint@10.2.1(jiti@2.6.1))': '@eslint/js@10.0.1(eslint@10.3.0(jiti@2.6.1))':
dependencies: dependencies:
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
'@eslint/object-schema@3.0.5': {} '@eslint/object-schema@3.0.5': {}
@ -3880,24 +3899,24 @@ snapshots:
'@gcch/configuration-eslint@https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54e5bfd6251566d7469ee99204c19f45': '@gcch/configuration-eslint@https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54e5bfd6251566d7469ee99204c19f45':
dependencies: dependencies:
'@eslint/js': 10.0.1(eslint@10.2.1(jiti@2.6.1)) '@eslint/js': 10.0.1(eslint@10.3.0(jiti@2.6.1))
astro-eslint-parser: 1.4.0 astro-eslint-parser: 1.4.0
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
eslint-plugin-functional: 9.0.4(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) eslint-plugin-functional: 9.0.4(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
eslint-plugin-jsdoc: 62.9.0(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-jsdoc: 62.9.0(eslint@10.3.0(jiti@2.6.1))
eslint-plugin-perfectionist: 5.9.0(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-perfectionist: 5.9.0(eslint@10.3.0(jiti@2.6.1))
eslint-plugin-sonarjs: 4.0.3(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-sonarjs: 4.0.3(eslint@10.3.0(jiti@2.6.1))
eslint-plugin-unicorn: 64.0.0(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-unicorn: 64.0.0(eslint@10.3.0(jiti@2.6.1))
globals: 17.5.0 globals: 17.6.0
typescript-eslint: 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) typescript-eslint: 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
'@gcch/configuration-oxlint@https://git.gcch.fr/gcch/configuration-oxlint#83547fc1ebfd6cb402e3c7f074b3e267632ebf4a': '@gcch/configuration-oxlint@https://git.gcch.fr/gcch/configuration-oxlint#83547fc1ebfd6cb402e3c7f074b3e267632ebf4a':
dependencies: dependencies:
eslint-plugin-astro: 1.7.0(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-astro: 1.7.0(eslint@10.3.0(jiti@2.6.1))
eslint-plugin-functional: 9.0.4(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) eslint-plugin-functional: 9.0.4(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
eslint-plugin-jsx-a11y: 6.10.2(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@10.3.0(jiti@2.6.1))
eslint-plugin-perfectionist: 5.9.0(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-perfectionist: 5.9.0(eslint@10.3.0(jiti@2.6.1))
globals: 17.5.0 globals: 17.6.0
oxlint: 1.62.0(oxlint-tsgolint@0.22.1) oxlint: 1.62.0(oxlint-tsgolint@0.22.1)
oxlint-tsgolint: 0.22.1 oxlint-tsgolint: 0.22.1
@ -4007,33 +4026,33 @@ snapshots:
'@rolldown/pluginutils@1.0.0-rc.17': {} '@rolldown/pluginutils@1.0.0-rc.17': {}
'@sentry-internal/browser-utils@10.50.0': '@sentry-internal/browser-utils@10.51.0':
dependencies: dependencies:
'@sentry/core': 10.50.0 '@sentry/core': 10.51.0
'@sentry-internal/feedback@10.50.0': '@sentry-internal/feedback@10.51.0':
dependencies: dependencies:
'@sentry/core': 10.50.0 '@sentry/core': 10.51.0
'@sentry-internal/replay-canvas@10.50.0': '@sentry-internal/replay-canvas@10.51.0':
dependencies: dependencies:
'@sentry-internal/replay': 10.50.0 '@sentry-internal/replay': 10.51.0
'@sentry/core': 10.50.0 '@sentry/core': 10.51.0
'@sentry-internal/replay@10.50.0': '@sentry-internal/replay@10.51.0':
dependencies: dependencies:
'@sentry-internal/browser-utils': 10.50.0 '@sentry-internal/browser-utils': 10.51.0
'@sentry/core': 10.50.0 '@sentry/core': 10.51.0
'@sentry/browser@10.50.0': '@sentry/browser@10.51.0':
dependencies: dependencies:
'@sentry-internal/browser-utils': 10.50.0 '@sentry-internal/browser-utils': 10.51.0
'@sentry-internal/feedback': 10.50.0 '@sentry-internal/feedback': 10.51.0
'@sentry-internal/replay': 10.50.0 '@sentry-internal/replay': 10.51.0
'@sentry-internal/replay-canvas': 10.50.0 '@sentry-internal/replay-canvas': 10.51.0
'@sentry/core': 10.50.0 '@sentry/core': 10.51.0
'@sentry/core@10.50.0': {} '@sentry/core@10.51.0': {}
'@sindresorhus/base62@1.0.0': {} '@sindresorhus/base62@1.0.0': {}
@ -4079,29 +4098,29 @@ snapshots:
'@types/trusted-types@2.0.7': {} '@types/trusted-types@2.0.7': {}
'@types/unist@3.0.3': {} '@types/unist@3.0.3': {}
? '@typescript-eslint/eslint-plugin@8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)' ? '@typescript-eslint/eslint-plugin@8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3))(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)'
: dependencies: : dependencies:
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/parser': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
'@typescript-eslint/scope-manager': 8.59.1 '@typescript-eslint/scope-manager': 8.59.1
'@typescript-eslint/type-utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/type-utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
'@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.59.1 '@typescript-eslint/visitor-keys': 8.59.1
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
ignore: 7.0.5 ignore: 7.0.5
natural-compare: 1.4.0 natural-compare: 1.4.0
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
'@typescript-eslint/parser@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': '@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)':
dependencies: dependencies:
'@typescript-eslint/scope-manager': 8.59.1 '@typescript-eslint/scope-manager': 8.59.1
'@typescript-eslint/types': 8.59.1 '@typescript-eslint/types': 8.59.1
'@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3)
'@typescript-eslint/visitor-keys': 8.59.1 '@typescript-eslint/visitor-keys': 8.59.1
debug: 4.4.3 debug: 4.4.3
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
typescript: 6.0.3 typescript: 6.0.3
'@typescript-eslint/project-service@8.59.1(typescript@6.0.3)': '@typescript-eslint/project-service@8.59.1(typescript@6.0.3)':
@ -4120,13 +4139,13 @@ snapshots:
dependencies: dependencies:
typescript: 6.0.3 typescript: 6.0.3
'@typescript-eslint/type-utils@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': '@typescript-eslint/type-utils@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)':
dependencies: dependencies:
'@typescript-eslint/types': 8.59.1 '@typescript-eslint/types': 8.59.1
'@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3)
'@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
debug: 4.4.3 debug: 4.4.3
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
@ -4145,13 +4164,13 @@ snapshots:
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
'@typescript-eslint/utils@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': '@typescript-eslint/utils@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)':
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1))
'@typescript-eslint/scope-manager': 8.59.1 '@typescript-eslint/scope-manager': 8.59.1
'@typescript-eslint/types': 8.59.1 '@typescript-eslint/types': 8.59.1
'@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3)
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
typescript: 6.0.3 typescript: 6.0.3
'@typescript-eslint/visitor-keys@8.59.1': '@typescript-eslint/visitor-keys@8.59.1':
@ -4227,11 +4246,11 @@ snapshots:
dependencies: dependencies:
typescript: 6.0.3 typescript: 6.0.3
'@typescript/native-preview-linux-x64@7.0.0-dev.20260429.1': {} '@typescript/native-preview-linux-x64@7.0.0-dev.20260503.1': {}
'@typescript/native-preview@7.0.0-dev.20260429.1': '@typescript/native-preview@7.0.0-dev.20260503.1':
optionalDependencies: optionalDependencies:
'@typescript/native-preview-linux-x64': 7.0.0-dev.20260429.1 '@typescript/native-preview-linux-x64': 7.0.0-dev.20260503.1
? '@vitejs/plugin-legacy@8.0.1(terser@5.46.2)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3))' ? '@vitejs/plugin-legacy@8.0.1(terser@5.46.2)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)(sass-embedded@1.99.0)(terser@5.46.2)(yaml@2.8.3))'
: dependencies: : dependencies:
@ -4710,35 +4729,35 @@ snapshots:
escape-string-regexp@5.0.0: {} escape-string-regexp@5.0.0: {}
eslint-compat-utils@0.6.5(eslint@10.2.1(jiti@2.6.1)): eslint-compat-utils@0.6.5(eslint@10.3.0(jiti@2.6.1)):
dependencies: dependencies:
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
semver: 7.7.4 semver: 7.7.4
eslint-plugin-astro@1.7.0(eslint@10.2.1(jiti@2.6.1)): eslint-plugin-astro@1.7.0(eslint@10.3.0(jiti@2.6.1)):
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1))
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5
'@typescript-eslint/types': 8.59.1 '@typescript-eslint/types': 8.59.1
astro-eslint-parser: 1.4.0 astro-eslint-parser: 1.4.0
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
eslint-compat-utils: 0.6.5(eslint@10.2.1(jiti@2.6.1)) eslint-compat-utils: 0.6.5(eslint@10.3.0(jiti@2.6.1))
globals: 16.5.0 globals: 16.5.0
postcss: 8.5.12 postcss: 8.5.12
postcss-selector-parser: 7.1.1 postcss-selector-parser: 7.1.1
eslint-plugin-functional@9.0.4(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3): eslint-plugin-functional@9.0.4(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3):
dependencies: dependencies:
'@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
deepmerge-ts: 7.1.5 deepmerge-ts: 7.1.5
escape-string-regexp: 5.0.0 escape-string-regexp: 5.0.0
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
is-immutable-type: 5.0.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) is-immutable-type: 5.0.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
ts-declaration-location: 1.0.7(typescript@6.0.3) ts-declaration-location: 1.0.7(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
eslint-plugin-jsdoc@62.9.0(eslint@10.2.1(jiti@2.6.1)): eslint-plugin-jsdoc@62.9.0(eslint@10.3.0(jiti@2.6.1)):
dependencies: dependencies:
'@es-joy/jsdoccomment': 0.86.0 '@es-joy/jsdoccomment': 0.86.0
'@es-joy/resolve.exports': 1.2.0 '@es-joy/resolve.exports': 1.2.0
@ -4746,7 +4765,7 @@ snapshots:
comment-parser: 1.4.6 comment-parser: 1.4.6
debug: 4.4.3 debug: 4.4.3
escape-string-regexp: 4.0.0 escape-string-regexp: 4.0.0
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
espree: 11.2.0 espree: 11.2.0
esquery: 1.7.0 esquery: 1.7.0
html-entities: 2.6.0 html-entities: 2.6.0
@ -4756,7 +4775,7 @@ snapshots:
spdx-expression-parse: 4.0.0 spdx-expression-parse: 4.0.0
to-valid-identifier: 1.0.0 to-valid-identifier: 1.0.0
eslint-plugin-jsx-a11y@6.10.2(eslint@10.2.1(jiti@2.6.1)): eslint-plugin-jsx-a11y@6.10.2(eslint@10.3.0(jiti@2.6.1)):
dependencies: dependencies:
aria-query: 5.3.2 aria-query: 5.3.2
array-includes: 3.1.9 array-includes: 3.1.9
@ -4766,7 +4785,7 @@ snapshots:
axobject-query: 4.1.0 axobject-query: 4.1.0
damerau-levenshtein: 1.0.8 damerau-levenshtein: 1.0.8
emoji-regex: 9.2.2 emoji-regex: 9.2.2
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
hasown: 2.0.3 hasown: 2.0.3
jsx-ast-utils: 3.3.5 jsx-ast-utils: 3.3.5
language-tags: 1.0.9 language-tags: 1.0.9
@ -4780,18 +4799,18 @@ snapshots:
jsonc-parser: 3.3.1 jsonc-parser: 3.3.1
oxlint: 1.62.0(oxlint-tsgolint@0.22.1) oxlint: 1.62.0(oxlint-tsgolint@0.22.1)
eslint-plugin-perfectionist@5.9.0(eslint@10.2.1(jiti@2.6.1)): eslint-plugin-perfectionist@5.9.0(eslint@10.3.0(jiti@2.6.1)):
dependencies: dependencies:
'@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
natural-orderby: 5.0.0 natural-orderby: 5.0.0
eslint-plugin-sonarjs@4.0.3(eslint@10.2.1(jiti@2.6.1)): eslint-plugin-sonarjs@4.0.3(eslint@10.3.0(jiti@2.6.1)):
dependencies: dependencies:
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
builtin-modules: 3.3.0 builtin-modules: 3.3.0
bytes: 3.1.2 bytes: 3.1.2
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
functional-red-black-tree: 1.0.1 functional-red-black-tree: 1.0.1
globals: 17.5.0 globals: 17.5.0
jsx-ast-utils-x: 0.1.0 jsx-ast-utils-x: 0.1.0
@ -4802,15 +4821,15 @@ snapshots:
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
eslint-plugin-unicorn@64.0.0(eslint@10.2.1(jiti@2.6.1)): eslint-plugin-unicorn@64.0.0(eslint@10.3.0(jiti@2.6.1)):
dependencies: dependencies:
'@babel/helper-validator-identifier': 7.28.5 '@babel/helper-validator-identifier': 7.28.5
'@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1))
change-case: 5.4.4 change-case: 5.4.4
ci-info: 4.4.0 ci-info: 4.4.0
clean-regexp: 1.0.0 clean-regexp: 1.0.0
core-js-compat: 3.49.0 core-js-compat: 3.49.0
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
find-up-simple: 1.0.1 find-up-simple: 1.0.1
globals: 17.5.0 globals: 17.5.0
indent-string: 5.0.0 indent-string: 5.0.0
@ -4840,9 +4859,9 @@ snapshots:
eslint-visitor-keys@5.0.1: {} eslint-visitor-keys@5.0.1: {}
eslint@10.2.1(jiti@2.6.1): eslint@10.3.0(jiti@2.6.1):
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1))
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
'@eslint/config-array': 0.23.5 '@eslint/config-array': 0.23.5
'@eslint/config-helpers': 0.5.5 '@eslint/config-helpers': 0.5.5
@ -5050,6 +5069,8 @@ snapshots:
globals@17.5.0: {} globals@17.5.0: {}
globals@17.6.0: {}
globalthis@1.0.4: globalthis@1.0.4:
dependencies: dependencies:
define-properties: 1.2.1 define-properties: 1.2.1
@ -5102,10 +5123,19 @@ snapshots:
hookified@2.2.0: {} hookified@2.2.0: {}
html-element-attributes@3.5.0: {}
html-entities@2.6.0: {} html-entities@2.6.0: {}
html-es6cape@2.0.2: {}
html-tags@5.1.0: {} html-tags@5.1.0: {}
html-template-tag@5.0.0:
dependencies:
html-element-attributes: 3.5.0
html-es6cape: 2.0.2
ignore@5.3.2: {} ignore@5.3.2: {}
ignore@7.0.5: {} ignore@7.0.5: {}
@ -5199,10 +5229,10 @@ snapshots:
dependencies: dependencies:
is-extglob: 2.1.1 is-extglob: 2.1.1
is-immutable-type@5.0.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3): is-immutable-type@5.0.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3):
dependencies: dependencies:
'@typescript-eslint/type-utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/type-utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
ts-api-utils: 2.5.0(typescript@6.0.3) ts-api-utils: 2.5.0(typescript@6.0.3)
ts-declaration-location: 1.0.7(typescript@6.0.3) ts-declaration-location: 1.0.7(typescript@6.0.3)
typescript: 6.0.3 typescript: 6.0.3
@ -5310,7 +5340,7 @@ snapshots:
kind-of@6.0.3: {} kind-of@6.0.3: {}
knip@6.8.0: knip@6.11.0:
dependencies: dependencies:
fdir: 6.5.0(picomatch@4.0.4) fdir: 6.5.0(picomatch@4.0.4)
formatly: 0.3.0 formatly: 0.3.0
@ -6279,13 +6309,13 @@ snapshots:
possible-typed-array-names: 1.1.0 possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10 reflect.getprototypeof: 1.0.10
typescript-eslint@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3): typescript-eslint@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3):
dependencies: dependencies:
'@typescript-eslint/eslint-plugin': 8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/eslint-plugin': 8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3))(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
'@typescript-eslint/parser': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/parser': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
'@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3)
'@typescript-eslint/utils': 8.59.1(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)
eslint: 10.2.1(jiti@2.6.1) eslint: 10.3.0(jiti@2.6.1)
typescript: 6.0.3 typescript: 6.0.3
typescript@6.0.3: {} typescript@6.0.3: {}

View file

@ -1,33 +1,17 @@
import { defineConfig, devices } from "@playwright/test"; import { defineConfig, devices, PlaywrightTestConfig } from "@playwright/test";
export default defineConfig({ const playwrightConfig: PlaywrightTestConfig = defineConfig({
fullyParallel: true, fullyParallel: true,
projects: [ projects: [
{ {
name: "desktop-chromium-1920", name: "desktop-chromium-1920",
use: { ...devices["Desktop Chrome"], viewport: { height: 1080, width: 1920 } }, use: { ...devices["Desktop Chrome"], viewport: { height: 1080, width: 1920 } },
}, },
// {
// name: "desktop-chromium-1536",
// use: { ...devices["Desktop Chrome"], viewport: { width: 1536, height: 864 } },
// },
// {
// name: "desktop-chromium-1366",
// use: { ...devices["Desktop Chrome"], viewport: { width: 1366, height: 768 } },
// },
{ {
name: "desktop-firefox-1920", name: "desktop-firefox-1920",
use: { ...devices["Desktop Firefox"], viewport: { height: 1080, width: 1920 } }, use: { ...devices["Desktop Firefox"], viewport: { height: 1080, width: 1920 } },
}, },
// { // {
// name: "desktop-firefox-1536",
// use: { ...devices["Desktop Firefox"], viewport: { width: 1536, height: 864 } },
// },
// {
// name: "desktop-firefox-1366",
// use: { ...devices["Desktop Firefox"], viewport: { width: 1366, height: 768 } },
// },
// {
// name: "tablet-chromium-portrait", // name: "tablet-chromium-portrait",
// use: { ...devices["Galaxy Tab S9"] }, // use: { ...devices["Galaxy Tab S9"] },
// }, // },
@ -49,7 +33,6 @@ export default defineConfig({
testDir: "../tests", testDir: "../tests",
timeout: 10_000, timeout: 10_000,
use: { use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "https://haikuatelier.gcch.local", baseURL: "https://haikuatelier.gcch.local",
clientCertificates: [ clientCertificates: [
{ {
@ -61,5 +44,7 @@ export default defineConfig({
ignoreHTTPSErrors: true, ignoreHTTPSErrors: true,
trace: "retry-with-trace", trace: "retry-with-trace",
}, },
workers: "100%", workers: "50%",
}); });
export default playwrightConfig;

View file

@ -1,19 +1,10 @@
{ {
"authors": [ "$schema": "https://getcomposer.org/schema.json",
{ "authors": [],
"email": "scott.walkinshaw@gmail.com",
"homepage": "https://github.com/swalkinshaw",
"name": "Scott Walkinshaw"
},
{
"email": "ben@benword.com",
"homepage": "https://github.com/retlehs",
"name": "Ben Word"
}
],
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"HaikuAtelier\\": "web/app/themes/haiku-atelier-2024/src/inc/" "HaikuAtelier\\": "web/app/themes/haiku-atelier-2024/src/inc/",
"WooCommerce\\": "web/app/plugins/woocommerce"
} }
}, },
"config": { "config": {
@ -24,11 +15,12 @@
"phpstan/extension-installer": true, "phpstan/extension-installer": true,
"roots/wordpress-core-installer": true "roots/wordpress-core-installer": true
}, },
"classmap-authoritative": true,
"optimize-autoloader": true, "optimize-autoloader": true,
"preferred-install": "dist", "preferred-install": "dist",
"sort-packages": true "sort-packages": true
}, },
"description": "WordPress boilerplate with Composer, easier configuration, and an improved folder structure", "description": "",
"extra": { "extra": {
"installer-paths": { "installer-paths": {
"web/app/mu-plugins/{$name}/": [ "web/app/mu-plugins/{$name}/": [
@ -46,18 +38,8 @@
}, },
"wordpress-install-dir": "web/wp" "wordpress-install-dir": "web/wp"
}, },
"homepage": "https://roots.io/bedrock/", "minimum-stability": "stable",
"keywords": [ "name": "gcch/haiku-atelier",
"bedrock",
"composer",
"roots",
"wordpress",
"wp",
"wp-config"
],
"license": "MIT",
"minimum-stability": "dev",
"name": "roots/bedrock",
"prefer-stable": true, "prefer-stable": true,
"repositories": [ "repositories": [
{ {
@ -111,9 +93,5 @@
"szepeviktor/phpstan-wordpress": "2.x-dev", "szepeviktor/phpstan-wordpress": "2.x-dev",
"vincentlanglet/twig-cs-fixer": "^3.14" "vincentlanglet/twig-cs-fixer": "^3.14"
}, },
"support": {
"forum": "https://discourse.roots.io/category/bedrock",
"issues": "https://github.com/roots/bedrock/issues"
},
"type": "project" "type": "project"
} }

79
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": "3144138aa029c01a516e9b6ce664271b", "content-hash": "b81b62efbedadf3c57fb437e86ef6766",
"packages": [ "packages": [
{ {
"name": "carbonphp/carbon-doctrine-types", "name": "carbonphp/carbon-doctrine-types",
@ -3176,16 +3176,16 @@
}, },
{ {
"name": "symfony/uid", "name": "symfony/uid",
"version": "v8.0.8", "version": "v8.0.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/uid.git", "url": "https://github.com/symfony/uid.git",
"reference": "f63fa6096a24147283bce4d29327d285326438e0" "reference": "4d9d6510bbe88ebb4608b7200d18606cdf80825c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/uid/zipball/f63fa6096a24147283bce4d29327d285326438e0", "url": "https://api.github.com/repos/symfony/uid/zipball/4d9d6510bbe88ebb4608b7200d18606cdf80825c",
"reference": "f63fa6096a24147283bce4d29327d285326438e0", "reference": "4d9d6510bbe88ebb4608b7200d18606cdf80825c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3230,7 +3230,7 @@
"uuid" "uuid"
], ],
"support": { "support": {
"source": "https://github.com/symfony/uid/tree/v8.0.8" "source": "https://github.com/symfony/uid/tree/v8.0.9"
}, },
"funding": [ "funding": [
{ {
@ -3250,7 +3250,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-03-30T15:14:47+00:00" "time": "2026-04-30T16:10:06+00:00"
}, },
{ {
"name": "timber/timber", "name": "timber/timber",
@ -4532,11 +4532,11 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "2.1.53", "version": "2.1.54",
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/ef67586798c003274797b288a68b221e4270dca7", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8be50c3992107dc837b17da4d140fbbdf9a5c5bd",
"reference": "ef67586798c003274797b288a68b221e4270dca7", "reference": "8be50c3992107dc837b17da4d140fbbdf9a5c5bd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4581,7 +4581,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2026-04-28T16:09:00+00:00" "time": "2026-04-29T13:31:09+00:00"
}, },
{ {
"name": "psr/event-dispatcher", "name": "psr/event-dispatcher",
@ -5215,18 +5215,18 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git", "url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "87a281378fdad8f5926efe259f6ca72e7a395e68" "reference": "2221f6ef09e87784e78e188aadd8f7e3a50e679a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/87a281378fdad8f5926efe259f6ca72e7a395e68", "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/2221f6ef09e87784e78e188aadd8f7e3a50e679a",
"reference": "87a281378fdad8f5926efe259f6ca72e7a395e68", "reference": "2221f6ef09e87784e78e188aadd8f7e3a50e679a",
"shasum": "" "shasum": ""
}, },
"conflict": { "conflict": {
"3f/pygmentize": "<1.2", "3f/pygmentize": "<1.2",
"adaptcms/adaptcms": "<=1.3", "adaptcms/adaptcms": "<=1.3",
"admidio/admidio": "<5.0.8", "admidio/admidio": "<=5.0.8",
"adodb/adodb-php": "<=5.22.9", "adodb/adodb-php": "<=5.22.9",
"aheinze/cockpit": "<2.2", "aheinze/cockpit": "<2.2",
"aimeos/ai-admin-graphql": ">=2022.04.1,<2022.10.10|>=2023.04.1,<2023.10.6|>=2024.04.1,<2024.07.2", "aimeos/ai-admin-graphql": ">=2022.04.1,<2022.10.10|>=2023.04.1,<2023.10.6|>=2024.04.1,<2024.07.2",
@ -5335,7 +5335,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.5", "ci4-cms-erp/ci4ms": "<=0.31.6",
"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",
@ -5540,7 +5540,7 @@
"geshi/geshi": "<=1.0.9.1", "geshi/geshi": "<=1.0.9.1",
"getformwork/formwork": "<=2.3.3", "getformwork/formwork": "<=2.3.3",
"getgrav/grav": "<1.11.0.0-beta1", "getgrav/grav": "<1.11.0.0-beta1",
"getkirby/cms": "<5.4", "getkirby/cms": "<4.9|>=5,<5.4",
"getkirby/kirby": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1", "getkirby/kirby": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1",
"getkirby/panel": "<2.5.14", "getkirby/panel": "<2.5.14",
"getkirby/starterkit": "<=3.7.0.2", "getkirby/starterkit": "<=3.7.0.2",
@ -5600,7 +5600,7 @@
"intelliants/subrion": "<4.2.2", "intelliants/subrion": "<4.2.2",
"inter-mediator/inter-mediator": "==5.5", "inter-mediator/inter-mediator": "==5.5",
"invoiceninja/invoiceninja": "<5.13.4", "invoiceninja/invoiceninja": "<5.13.4",
"ipl/web": "<0.10.1", "ipl/web": "<=0.13",
"islandora/crayfish": "<4.1", "islandora/crayfish": "<4.1",
"islandora/islandora": ">=2,<2.4.1", "islandora/islandora": ">=2,<2.4.1",
"ivankristianto/phpwhois": "<=4.3", "ivankristianto/phpwhois": "<=4.3",
@ -5870,7 +5870,7 @@
"prestashop/gamification": "<2.3.2", "prestashop/gamification": "<2.3.2",
"prestashop/prestashop": "<8.2.5|>=9.0.0.0-alpha1,<9.1", "prestashop/prestashop": "<8.2.5|>=9.0.0.0-alpha1,<9.1",
"prestashop/productcomments": "<5.0.2", "prestashop/productcomments": "<5.0.2",
"prestashop/ps_checkout": "<4.4.1|>=5,<5.0.5", "prestashop/ps_checkout": "<5.3",
"prestashop/ps_contactinfo": "<=3.3.2", "prestashop/ps_contactinfo": "<=3.3.2",
"prestashop/ps_emailsubscription": "<2.6.1", "prestashop/ps_emailsubscription": "<2.6.1",
"prestashop/ps_facetedsearch": "<3.4.1", "prestashop/ps_facetedsearch": "<3.4.1",
@ -5907,6 +5907,7 @@
"rhukster/dom-sanitizer": "<1.0.10", "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",
"roadiz/openid": "<2.3.43|>=2.5,<2.5.45|>=2.6,<2.6.31|>=2.7,<2.7.18",
"robrichards/xmlseclibs": "<3.1.5", "robrichards/xmlseclibs": "<3.1.5",
"roots/soil": "<4.1", "roots/soil": "<4.1",
"roundcube/roundcubemail": "<1.5.10|>=1.6,<1.6.11|>=1.7.0.0-beta,<1.7.0.0-RC5-dev", "roundcube/roundcubemail": "<1.5.10|>=1.6,<1.6.11|>=1.7.0.0-beta,<1.7.0.0-RC5-dev",
@ -6264,7 +6265,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-04-28T23:21:55+00:00" "time": "2026-04-30T21:24:12+00:00"
}, },
{ {
"name": "sebastian/diff", "name": "sebastian/diff",
@ -6347,16 +6348,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v8.0.8", "version": "v8.0.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "5b66d385dc58f69652e56f78a4184615e3f2b7f7" "reference": "7113778e2e91f4709cb3194a75dfa9c0d028d94d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/5b66d385dc58f69652e56f78a4184615e3f2b7f7", "url": "https://api.github.com/repos/symfony/console/zipball/7113778e2e91f4709cb3194a75dfa9c0d028d94d",
"reference": "5b66d385dc58f69652e56f78a4184615e3f2b7f7", "reference": "7113778e2e91f4709cb3194a75dfa9c0d028d94d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6413,7 +6414,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v8.0.8" "source": "https://github.com/symfony/console/tree/v8.0.9"
}, },
"funding": [ "funding": [
{ {
@ -6433,20 +6434,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-03-30T15:14:47+00:00" "time": "2026-04-29T15:02:55+00:00"
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
"version": "v8.0.8", "version": "v8.0.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/event-dispatcher.git", "url": "https://github.com/symfony/event-dispatcher.git",
"reference": "f662acc6ab22a3d6d716dcb44c381c6002940df6" "reference": "0c3c1a17604c4dbbec4b93fe162c538482096e1f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f662acc6ab22a3d6d716dcb44c381c6002940df6", "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/0c3c1a17604c4dbbec4b93fe162c538482096e1f",
"reference": "f662acc6ab22a3d6d716dcb44c381c6002940df6", "reference": "0c3c1a17604c4dbbec4b93fe162c538482096e1f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6498,7 +6499,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v8.0.8" "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.9"
}, },
"funding": [ "funding": [
{ {
@ -6518,7 +6519,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-03-30T15:14:47+00:00" "time": "2026-04-18T13:51:42+00:00"
}, },
{ {
"name": "symfony/event-dispatcher-contracts", "name": "symfony/event-dispatcher-contracts",
@ -6598,16 +6599,16 @@
}, },
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
"version": "v8.0.8", "version": "v8.0.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/filesystem.git", "url": "https://github.com/symfony/filesystem.git",
"reference": "66b769ae743ce2d13e435528fbef4af03d623e5a" "reference": "d1ec4543d5c6c2dac78503c2fae5ea0b3608ce40"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/66b769ae743ce2d13e435528fbef4af03d623e5a", "url": "https://api.github.com/repos/symfony/filesystem/zipball/d1ec4543d5c6c2dac78503c2fae5ea0b3608ce40",
"reference": "66b769ae743ce2d13e435528fbef4af03d623e5a", "reference": "d1ec4543d5c6c2dac78503c2fae5ea0b3608ce40",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6644,7 +6645,7 @@
"description": "Provides basic utilities for the filesystem", "description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/filesystem/tree/v8.0.8" "source": "https://github.com/symfony/filesystem/tree/v8.0.9"
}, },
"funding": [ "funding": [
{ {
@ -6664,7 +6665,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-03-30T15:14:47+00:00" "time": "2026-04-18T13:51:42+00:00"
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
@ -7565,7 +7566,7 @@
} }
], ],
"aliases": [], "aliases": [],
"minimum-stability": "dev", "minimum-stability": "stable",
"stability-flags": { "stability-flags": {
"roave/security-advisories": 20, "roave/security-advisories": 20,
"szepeviktor/phpstan-wordpress": 20 "szepeviktor/phpstan-wordpress": 20

View file

@ -8,6 +8,7 @@ declare(strict_types=1);
use Roots\WPConfig\Config; use Roots\WPConfig\Config;
use function base64_encode;
use function Env\env; use function Env\env;
Config::define('SAVEQUERIES', true); Config::define('SAVEQUERIES', true);
@ -25,6 +26,10 @@ Config::define('DISALLOW_FILE_MODS', false);
// WooCommerce // WooCommerce
Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY')); Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY'));
Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET')); Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET'));
Config::define(
'WOOCOMMERCE_API_AUTH_STRING',
base64_encode(env('WOOCOMMERCE_API_CONSUMER_KEY') . ':' . env('WOOCOMMERCE_API_CONSUMER_SECRET')),
);
// Stripe // Stripe
Config::define('STRIPE_API_SECRET', env('STRIPE_API_SECRET')); Config::define('STRIPE_API_SECRET', env('STRIPE_API_SECRET'));

View file

@ -8,6 +8,7 @@ declare(strict_types=1);
use Roots\WPConfig\Config; use Roots\WPConfig\Config;
use function base64_encode;
use function Env\env; use function Env\env;
Config::define('WP_DEBUG', true); Config::define('WP_DEBUG', true);
@ -20,6 +21,10 @@ Config::define('DISALLOW_FILE_MODS', false);
Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY')); Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY'));
Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET')); Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET'));
Config::define(
'WOOCOMMERCE_API_AUTH_STRING',
base64_encode(env('WOOCOMMERCE_API_CONSUMER_KEY') . ':' . env('WOOCOMMERCE_API_CONSUMER_SECRET')),
);
// Stripe // Stripe
Config::define('STRIPE_API_SECRET', env('STRIPE_API_SECRET')); Config::define('STRIPE_API_SECRET', env('STRIPE_API_SECRET'));

View file

@ -8,8 +8,13 @@ declare(strict_types=1);
use Roots\WPConfig\Config; use Roots\WPConfig\Config;
use function base64_encode;
use function Env\env; use function Env\env;
Config::define('DISALLOW_INDEXING', true); Config::define('DISALLOW_INDEXING', true);
Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY')); Config::define('WOOCOMMERCE_API_CONSUMER_KEY', env('WOOCOMMERCE_API_CONSUMER_KEY'));
Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET')); Config::define('WOOCOMMERCE_API_CONSUMER_SECRET', env('WOOCOMMERCE_API_CONSUMER_SECRET'));
Config::define(
'WOOCOMMERCE_API_AUTH_STRING',
base64_encode(env('WOOCOMMERCE_API_CONSUMER_KEY') . ':' . env('WOOCOMMERCE_API_CONSUMER_SECRET')),
);

View file

@ -90,6 +90,11 @@ watch-css:
build-js: build-js:
aube x vite build --config "cfg/vite.config.ts" aube x vite build --config "cfg/vite.config.ts"
# Compile TypeScript à chaque changement de fichier.
[group('js')]
watch-js:
@watchexec -w "web/app/themes/haiku-atelier-2024/src/scripts" -w "web/app/themes/haiku-atelier-2024/src/scripts-effect" -- just build-js treefmt
# Compile tout. # Compile tout.
[group('css')] [group('css')]
[group('js')] [group('js')]
@ -98,11 +103,6 @@ build-all:
@just build-js @just build-js
@just format @just format
# Compile TypeScript à chaque changement de fichier.
[group('js')]
watch-js:
aube x vite build --config "cfg/vite.config.ts" --watch
# Vérifie le code TypeScript avec des analyseurs statiques. # Vérifie le code TypeScript avec des analyseurs statiques.
[group('js')] [group('js')]
[group('qualité')] [group('qualité')]
@ -170,3 +170,6 @@ pull-images:
export_production_db: export_production_db:
fish "scripts/déclenche-sauvegarde-bdd-production.fish" fish "scripts/déclenche-sauvegarde-bdd-production.fish"
ui_tests:
aube x playwright test --config cfg/playwright.config.ts --ui

File diff suppressed because it is too large Load diff

View file

@ -36,6 +36,7 @@ threads = 0
no-else-clause = { enabled = false } no-else-clause = { enabled = false }
[analyzer] [analyzer]
allow-implicit-pipe-callable-types = false
allow-possibly-undefined-array-keys = false allow-possibly-undefined-array-keys = false
allow-side-effects-in-conditions = true allow-side-effects-in-conditions = true
analyze-dead-code = true analyze-dead-code = true

2
mise.toml Normal file
View file

@ -0,0 +1,2 @@
[tools]
"github:AJenbo/phpantom_lsp" = "latest"

View file

@ -13,9 +13,10 @@
}, },
"dependencies": { "dependencies": {
"@mobily/ts-belt": "v4.0.0-rc.5", "@mobily/ts-belt": "v4.0.0-rc.5",
"@sentry/browser": "^10.50.0", "@sentry/browser": "^10.51.0",
"a11y-dialog": "^8.1.5", "a11y-dialog": "^8.1.5",
"effect": "^4.0.0-beta.59", "effect": "^4.0.0-beta.59",
"html-template-tag": "^5.0.0",
"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",
@ -23,28 +24,28 @@
}, },
"devDependencies": { "devDependencies": {
"@effect/language-service": "^0.85.1", "@effect/language-service": "^0.85.1",
"@effect/tsgo": "0.5.1", "@effect/tsgo": "^0.5.2",
"@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54", "@gcch/configuration-eslint": "git+https://git.gcch.fr/gcch/configuration-eslint#888eb4aa54",
"@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#83547fc1ebfd", "@gcch/configuration-oxlint": "git+https://git.gcch.fr/gcch/configuration-oxlint#83547fc1ebfd",
"@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#d267d6dc5e", "@gcch/configuration-prettier": "git+https://git.gcch.fr/gcch/configuration-prettier#d267d6dc5e",
"@playwright/test": "^1.59.1", "@playwright/test": "^1.59.1",
"@sentry/core": "^10.50.0", "@sentry/core": "^10.51.0",
"@types/bun": "^1.3.13", "@types/bun": "^1.3.13",
"@types/node": "^25.6.0", "@types/node": "^25.6.0",
"@typescript/native-preview": "7.0.0-dev.20260429.1", "@typescript/native-preview": "7.0.0-dev.20260503.1",
"@vitejs/plugin-legacy": "^8.0.1", "@vitejs/plugin-legacy": "^8.0.1",
"better-typescript-lib": "^2.12.0", "better-typescript-lib": "^2.12.0",
"browserslist": "^4.28.2", "browserslist": "^4.28.2",
"caniuse-lite": "^1.0.30001791", "caniuse-lite": "^1.0.30001791",
"eslint": "^10.2.1", "eslint": "^10.3.0",
"eslint-plugin-functional": "^9.0.4", "eslint-plugin-functional": "^9.0.4",
"eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-oxlint": "^1.62.0", "eslint-plugin-oxlint": "^1.62.0",
"eslint-plugin-perfectionist": "^5.9.0", "eslint-plugin-perfectionist": "^5.9.0",
"fdir": "^6.5.0", "fdir": "^6.5.0",
"globals": "^17.5.0", "globals": "^17.6",
"jiti": "^2.6.1", "jiti": "^2.6.1",
"knip": "^6.8.0", "knip": "^6.11.0",
"lightningcss": "^1.32.0", "lightningcss": "^1.32.0",
"lightningcss-cli": "^1.32.0", "lightningcss-cli": "^1.32.0",
"oxlint": "^1.62.0", "oxlint": "^1.62.0",

View file

@ -236,6 +236,21 @@
"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"
}, },
"core.project_config_candidates": {
"default": [],
"description": "(internal) list of potential project-level configuration files"
},
"core.trust": {
"default": {
"path": null,
"trust": []
},
"description": "(internal) map of trusted project directories"
},
"core.trusted": {
"default": false,
"description": "(internal) if the configuration is trusted"
},
"file_path_resolver.app_name": { "file_path_resolver.app_name": {
"default": "phpactor", "default": "phpactor",
"description": null "description": null
@ -278,7 +293,8 @@
"default": [ "default": [
"/vendor/**/tests/**/*", "/vendor/**/tests/**/*",
"/vendor/**/Tests/**/*", "/vendor/**/Tests/**/*",
"/vendor/composer/**/*" "/vendor/composer/**/*",
"/vendor/rector/rector/stubs-rector"
], ],
"description": "Glob patterns to exclude while indexing", "description": "Glob patterns to exclude while indexing",
"type": [ "type": [
@ -316,6 +332,13 @@
"string" "string"
] ]
}, },
"indexer.max_filesize_to_index": {
"default": 1000000,
"description": "Files larger than this will not be indexed. (Size in bytes)",
"type": [
"integer"
]
},
"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)",
@ -337,6 +360,13 @@
"boolean" "boolean"
] ]
}, },
"indexer.search_include_patterns": {
"default": [],
"description": "When searching the index exclude records whose fully qualified names match any of these regex patterns (use to exclude suggestions from search results). Namespace separators must be escaped as `\\\\\\\\` for example `^Foo\\\\\\\\` to include all namespaces whose first segment is `Foo`",
"type": [
"object"
]
},
"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.",
@ -362,6 +392,10 @@
"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_ignore_codes": {
"default": [],
"description": "Ignore diagnostics that have the codes listed here, e.g. [\"fix_namespace_class_name\"]. The codes match those shown in the LSP client."
},
"language_server.diagnostic_outsource": { "language_server.diagnostic_outsource": {
"default": true, "default": true,
"description": "If applicable diagnostics should be \"outsourced\" to a different process" "description": "If applicable diagnostics should be \"outsourced\" to a different process"
@ -389,6 +423,10 @@
"default": true, "default": true,
"description": "Perform diagnostics when the text document is updated" "description": "Perform diagnostics when the text document is updated"
}, },
"language_server.enable_trust_check": {
"default": true,
"description": "Check to see if project path is trusted before loading configurations from it"
},
"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)"
@ -450,6 +488,17 @@
"boolean" "boolean"
] ]
}, },
"language_server_highlight.enabled": {
"default": true,
"description": "Enable or disable the highlighter (can be expensive on large documents)"
},
"language_server_indexer.optimiser_timeout": {
"default": 3600,
"description": "Optimise the index every N seconds",
"type": [
"integer"
]
},
"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"
@ -467,15 +516,17 @@
}, },
"language_server_php_cs_fixer.env": { "language_server_php_cs_fixer.env": {
"default": { "default": {
"PHP_CS_FIXER_IGNORE_ENV": true,
"XDEBUG_MODE": "off" "XDEBUG_MODE": "off"
}, },
"description": "Environment for PHP CS Fixer (e.g. to set PHP_CS_FIXER_IGNORE_ENV)" "description": "Environment for PHP CS Fixer"
}, },
"language_server_php_cs_fixer.show_diagnostics": { "language_server_php_cs_fixer.show_diagnostics": {
"default": true, "default": true,
"description": "Whether PHP CS Fixer diagnostics are shown" "description": "Whether PHP CS Fixer diagnostics are shown"
}, },
"language_server_php_cs_fixer.version": {
"description": "Arbitrary version (if not provided, phpactor tries to detect it - only to run it on unsupported PHP versions)"
},
"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"
@ -483,12 +534,24 @@
"language_server_phpstan.config": { "language_server_phpstan.config": {
"description": "Override the PHPStan configuration file" "description": "Override the PHPStan configuration file"
}, },
"language_server_phpstan.editor_mode": {
"default": false,
"description": "DEPRECATED. Editor mode of Phpstan is used automatically when it's supported."
},
"language_server_phpstan.level": { "language_server_phpstan.level": {
"description": "Override the PHPStan level" "description": "Override the PHPStan level"
}, },
"language_server_phpstan.mem_limit": { "language_server_phpstan.mem_limit": {
"description": "Override the PHPStan memory limit" "description": "Override the PHPStan memory limit"
}, },
"language_server_phpstan.severity": {
"default": 1,
"description": "Severity at which PHPStan diagnostics should be reported. Ranges from 1 (error) to 4 (hint)."
},
"language_server_phpstan.tmp_file_disabled": {
"default": false,
"description": "Disable the use of temporary files when. This prevents as-you-type diagnostics, but ensures paths in phpstan config are respected. See https://github.com/phpactor/phpactor/issues/2763"
},
"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",
@ -496,6 +559,13 @@
"string" "string"
] ]
}, },
"language_server_psalm.config": {
"default": "",
"description": "Path to psalm config. Like %project_root%/psalm.xml",
"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)"
}, },
@ -527,6 +597,10 @@
"boolean" "boolean"
] ]
}, },
"language_server_reference_finder.soft_timeout": {
"default": 10,
"description": "Interupt and ask for confirmation to continue after this timeout (in seconds)"
},
"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"
@ -658,6 +732,10 @@
"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.additive_stubs": {
"default": [],
"description": "Additive stubs files relative to the project root. These stubs augment existing defininitions."
},
"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"

View file

@ -1,3 +1,4 @@
/** @effect-diagnostics asyncFunction:skip-file */
import type { APIRequestContext, Locator, Page, Response } from "@playwright/test"; import type { APIRequestContext, Locator, Page, Response } from "@playwright/test";
import { expect, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import type { WCV3Products } from "../../web/app/themes/haiku-atelier-2024/src/scripts/lib/types/api/v3/products"; import type { WCV3Products } from "../../web/app/themes/haiku-atelier-2024/src/scripts/lib/types/api/v3/products";
@ -10,7 +11,7 @@ test("can scroll to the end of the grid", async ({ page }): Promise<void> => {
await scrollToGridsEnd(page); await scrollToGridsEnd(page);
}); });
test.skip("can access all Products' pages", async ({ page, request }): Promise<void> => { test("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);

View file

@ -17,7 +17,6 @@ use WC_Product;
use function add_action; use function add_action;
use function array_map; use function array_map;
use function assert; use function assert;
use function base64_encode;
use function is_string; use function is_string;
use function wc_get_products; use function wc_get_products;
use function wp_create_nonce; use function wp_create_nonce;
@ -33,12 +32,7 @@ $products = array_map(callback: Product::from_wc_product(...), array: $wc_produc
$context['products'] = $products; $context['products'] = $products;
// Injecte les états initiaux des données du Produit sous forme de JSON dans le contexte. // Injecte les états initiaux des données du Produit sous forme de JSON dans le contexte.
$page_states = [ $page_states = ['authString' => Config::get('WOOCOMMERCE_API_AUTH_STRING'), 'nonce' => wp_create_nonce('wc_store_api')]
'nonce' => wp_create_nonce('wc_store_api'),
'authString' => base64_encode(
Config::get('WOOCOMMERCE_API_CONSUMER_KEY') . ':' . Config::get('WOOCOMMERCE_API_CONSUMER_SECRET'),
),
]
|> wp_json_encode(...); |> wp_json_encode(...);
assert(is_string($page_states)); assert(is_string($page_states));
$context['page_states'] = $page_states; $context['page_states'] = $page_states;

View file

@ -462,8 +462,8 @@ input[type="checkbox"], input[type="radio"] {
transition: 0.2s background; transition: 0.2s background;
} }
input[type="checkbox"]:checked, input[type="radio"]:checked { input[type="checkbox"]:checked, input[type="radio"]:checked {
color: var(--couleur-blanc); color: var(--couleur-noir);
background: var(--couleur-gris-fonce); background: var(--arriere-plan-points);
} }
input[type="checkbox"]:checked::before, input[type="radio"]:checked::before { input[type="checkbox"]:checked::before, input[type="radio"]:checked::before {
content: "x"; content: "x";
@ -492,7 +492,7 @@ input[type="radio"] + label {
} }
@media (hover: hover) { @media (hover: hover) {
input[type="checkbox"]:hover, input[type="radio"]:hover { input[type="checkbox"]:hover, input[type="radio"]:hover {
background: var(--couleur-gris-fonce); background: var(--arriere-plan-points);
} }
} }

File diff suppressed because one or more lines are too long

View file

@ -95,8 +95,7 @@ final class StarterSite extends Site {
$url_courante = URLHelper::get_current_url(); $url_courante = URLHelper::get_current_url();
$context['page_courante'] = $url_courante; $context['page_courante'] = $url_courante;
$context['est_page_tous_produits'] = preg_match(pattern: '/(\bshop\b)/', subject: $url_courante); $context['est_page_tous_produits'] = preg_match(pattern: '/(\bshop\b)/', subject: $url_courante);
$context['est_page_boutique'] = $context['est_page_boutique'] = preg_match(pattern: '/(\bshop\b)/', subject: $url_courante)
preg_match(pattern: '/(\bshop\b)/', subject: $url_courante)
|| preg_match(pattern: '/(\bproduct\b)/', subject: $url_courante) || preg_match(pattern: '/(\bproduct\b)/', subject: $url_courante)
|| preg_match(pattern: '/(\bproduct-category\b)/', subject: $url_courante); || preg_match(pattern: '/(\bproduct-category\b)/', subject: $url_courante);

View file

@ -26,8 +26,10 @@ final readonly class Attribute {
public static function new(WC_Product_Attribute $attribute): self { public static function new(WC_Product_Attribute $attribute): self {
$name = wc_attribute_label($attribute->get_name()); $name = wc_attribute_label($attribute->get_name());
$slug = $attribute->get_name(); $slug = $attribute->get_name();
/** @var list<WP_Term> */ /** @var list<WP_Term> */
$terms = $attribute->get_terms() ?? []; $terms = $attribute->get_terms() ?? [];
/** @var list<AttributeOption> */ /** @var list<AttributeOption> */
$options = Arr::map($terms, AttributeOption::new(...)) $options = Arr::map($terms, AttributeOption::new(...))
|> (static fn($options) => Arr::sort($options, static fn($attribute) => $attribute->id)) |> (static fn($options) => Arr::sort($options, static fn($attribute) => $attribute->id))

View file

@ -18,9 +18,12 @@ use function Psl\Option\from_nullable;
use function wc_get_products; use function wc_get_products;
use function wpautop; use function wpautop;
/**
* Représente un **Produit** (selon _WooCommerce_) avec de nombreuses données d'intérêt pour les opérations courantes.
*/
final readonly class Product { final readonly class Product {
/** /**
* @param list<Attribute> $attributes * @param list<Attribute> $attributes La liste des `Attribute` appliquées.
* @param list<string> $left_column_photos * @param list<string> $left_column_photos
* @param list<string> $right_column_photos * @param list<string> $right_column_photos
* @param array<ProductVariation> $variations * @param array<ProductVariation> $variations

View file

@ -58,6 +58,9 @@ function retire_styles_core_block(): void {
add_filter('async_update_translation', '__return_false'); add_filter('async_update_translation', '__return_false');
add_filter('auto_update_translation', '__return_false'); add_filter('auto_update_translation', '__return_false');
// Désactive la génération automatique de sitemaps.
add_filter('wp_sitemaps_enabled', '__return_false');
add_action('init', desactive_wpautop(...)); add_action('init', desactive_wpautop(...));
add_filter('tiny_mce_before_init', desactive_transformation_contenu_tinymce(...)); add_filter('tiny_mce_before_init', desactive_transformation_contenu_tinymce(...));
add_filter('upload_mimes', autorise_import_svg_mediatheque(...)); add_filter('upload_mimes', autorise_import_svg_mediatheque(...));

View file

@ -131,7 +131,8 @@ function retire_merdes_wc(): void {
*/ */
function genere_balises_img_dans_produit_dans_reponse_rest( function genere_balises_img_dans_produit_dans_reponse_rest(
WP_REST_Response $response, WP_REST_Response $response,
mixed $_product, WC_Data $_product,
WP_REST_Request $_request,
): WP_REST_Response { ): WP_REST_Response {
// Vérifie que la Réponse a des données // Vérifie que la Réponse a des données
if (empty($response->data)) { if (empty($response->data)) {
@ -169,37 +170,34 @@ function genere_balises_img_dans_produit_dans_reponse_rest(
return $response; return $response;
} }
add_filter('woocommerce_rest_prepare_product_object', 'genere_balises_img_dans_produit_dans_reponse_rest', 10, 2);
/** /**
* TODO. * TODO.
*/ */
function genere_prix_maximal_produit_variable_dans_reponse_rest( function genere_prix_maximal_produit_variable_dans_reponse_rest(
WP_REST_Response $reponse, WP_REST_Response $response,
WC_Data $_produit, WC_Data $_product,
WP_REST_Request $_request,
): WP_REST_Response { ): WP_REST_Response {
// Vérifie que la Réponse a des données // Vérifie que la Réponse a des données
if (empty($reponse->data)) { if (empty($response->data)) {
return $reponse; return $response;
} }
// Si le Produit n'est pas Variable, assigner le prix du Produit comme prix maximal // Si le Produit n'est pas Variable, assigner le prix du Produit comme prix maximal
if ('variable' !== $reponse->data['type']) { if ('variable' !== $response->data['type']) {
$reponse->data['prix_maximal'] = $reponse->data['regular_price']; $response->data['prix_maximal'] = $response->data['regular_price'];
return $reponse; return $response;
} }
// Assigne le prix de la Variation la plus chère dans la Réponse // Assigne le prix de la Variation la plus chère dans la Réponse
$reponse->data['prix_maximal'] = collect($reponse->data['variations']) $response->data['prix_maximal'] = collect($response->data['variations'])
->map(wc_get_product(...)) ->map(wc_get_product(...))
->map(static fn($p) => $p->get_price())->max(); ->map(static fn($p) => $p->get_price())->max();
return $reponse; return $response;
} }
add_filter('woocommerce_rest_prepare_product_object', 'genere_prix_maximal_produit_variable_dans_reponse_rest', 10, 2);
/** /**
* Retire la propagande commerciale de WooCommerce du menu. * Retire la propagande commerciale de WooCommerce du menu.
*/ */
@ -216,3 +214,8 @@ add_action('init', 'retire_script_galerie');
add_action('template_redirect', 'retire_merdes_wc'); add_action('template_redirect', 'retire_merdes_wc');
add_action('wp_enqueue_scripts', 'dequeue_woocommerce_styles_scripts'); add_action('wp_enqueue_scripts', 'dequeue_woocommerce_styles_scripts');
add_filter('woocommerce_enqueue_styles', '__return_empty_array'); add_filter('woocommerce_enqueue_styles', '__return_empty_array');
add_filter('woocommerce_rest_prepare_product_object', 'genere_balises_img_dans_produit_dans_reponse_rest', 10, 3);
add_filter('woocommerce_rest_prepare_product_object', 'genere_prix_maximal_produit_variable_dans_reponse_rest', 10, 3);
// DEBUG
// add_filter('woocommerce_store_api_disable_nonce_check', '__return_true');

View file

@ -84,8 +84,7 @@ final readonly class Resource {
static fn($tableau): array => array_map(array: $tableau, callback: static fn($chemin_format): array => [ static fn($tableau): array => array_map(array: $tableau, callback: static fn($chemin_format): array => [
'format' => pathinfo((string) $chemin_format)['extension'], 'format' => pathinfo((string) $chemin_format)['extension'],
'taille' => filesize($chemin_format), 'taille' => filesize($chemin_format),
'url' => 'url' => pathinfo($url)['dirname']
pathinfo($url)['dirname']
. '/' . '/'
. pathinfo($url)['filename'] . pathinfo($url)['filename']
. '.' . '.'

View file

@ -66,8 +66,8 @@ input[type="checkbox"], input[type="radio"] {
transition: 0.2s background; transition: 0.2s background;
&:checked { &:checked {
color: var(--couleur-blanc); color: var(--couleur-noir);
background: var(--couleur-gris-fonce); background: var(--arriere-plan-points);
// TODO: Utiliser un SVG plutôt qu'un « x » ? // TODO: Utiliser un SVG plutôt qu'un « x » ?
&::before { &::before {
@ -98,7 +98,7 @@ input[type="checkbox"], input[type="radio"] {
@media (hover: hover) { @media (hover: hover) {
&:hover { &:hover {
background: var(--couleur-gris-fonce); background: var(--arriere-plan-points);
} }
} }
} }

View file

@ -1,4 +1,4 @@
import { Console, Context, Effect, Layer, Match, pipe, Schedule, Schema, SchemaIssue } from "effect"; import { Console, Context, Effect, Layer, Match, pipe, References, Schedule, Schema, SchemaIssue } from "effect";
import type { SchemaError } from "effect/Schema"; import type { SchemaError } from "effect/Schema";
import type { import type {
HttpClientError, HttpClientError,
@ -11,6 +11,7 @@ import {
} from "effect/unstable/http"; } from "effect/unstable/http";
import { HttpClientErrorSchema } from "effect/unstable/http/HttpClientError"; import { HttpClientErrorSchema } from "effect/unstable/http/HttpClientError";
import type { CartProduct, GetProducts } from "../schemas/api.ts"; import type { CartProduct, GetProducts } from "../schemas/api.ts";
import { Product } from "../schemas/api.ts";
import { WooCommerceCart } from "../schemas/cart.ts"; import { WooCommerceCart } from "../schemas/cart.ts";
/** Le nombre maximal d'essais pour une Requête. */ /** Le nombre maximal d'essais pour une Requête. */
@ -52,7 +53,7 @@ const APIFetchClient = FetchHttpClient.layer.pipe(
Layer.succeed( Layer.succeed(
FetchHttpClient.RequestInit, FetchHttpClient.RequestInit,
{ {
credentials: "same-origin", credentials: "include",
headers: { headers: {
Accept: "application/json", Accept: "application/json",
"Content-Type": "application/json", "Content-Type": "application/json",
@ -135,18 +136,22 @@ class APIClient extends Context.Service<APIClient>()("haikuatelier.fr/APIClient"
); );
const GetProducts = Effect.fn("APIClient.GetProducts")( const GetProducts = Effect.fn("APIClient.GetProducts")(
function*(nonce: string, authString: string, queryParams: GetProducts) { function*(nonce: string, queryParams: GetProducts) {
const request = pipe( const request = pipe(
HttpClientRequest.get(`/wp-json/wc/store/products`), HttpClientRequest.get(`/wp-json/wc/v3/products`),
HttpClientRequest.setHeader("Nonce", nonce), HttpClientRequest.setHeader("Nonce", nonce),
HttpClientRequest.bearerToken(authString), // TODO: Utiliser l'environnement
HttpClientRequest.basicAuth(
"ck_ed966a2265099a6dfe9915db692cbd2450cceed6",
"cs_a046c91647af95188a3e39a736ebe02f2024e430",
),
// Le corps de la Requête a été validée en amont, on peut utiliser Unsafe. // Le corps de la Requête a été validée en amont, on peut utiliser Unsafe.
HttpClientRequest.setUrlParams(queryParams), HttpClientRequest.setUrlParams(queryParams),
); );
const response = yield* pipe( const response = yield* pipe(
haikuHTTPClient.execute(request), haikuHTTPClient.execute(request),
Effect.flatMap(HttpClientResponse.schemaBodyJson(Schema.Unknown)), Effect.flatMap(HttpClientResponse.schemaBodyJson(Schema.Array(Product))),
Effect.mapError(error => matchAPIError(error)), Effect.mapError(error => matchAPIError(error)),
Effect.tapError(error => printErrorAsSuccinctMessage(error)), Effect.tapError(error => printErrorAsSuccinctMessage(error)),
); );

View file

@ -1,5 +1,5 @@
import { Schema } from "effect"; import { Schema } from "effect";
import { ProductId, ProductQuantity, ProductVariationAttribute } from "./product.ts"; import { ProductId, ProductQuantity, ProductStatus, ProductVariationAttribute } from "./product.ts";
class CartProduct extends Schema.Class<CartProduct>("CartProduct")({ class CartProduct extends Schema.Class<CartProduct>("CartProduct")({
id: ProductId, id: ProductId,
@ -7,4 +7,58 @@ class CartProduct extends Schema.Class<CartProduct>("CartProduct")({
variation: Schema.Array(ProductVariationAttribute), variation: Schema.Array(ProductVariationAttribute),
}) {} }) {}
export { CartProduct }; class GetProducts extends Schema.Class<GetProducts>("GetProducts")({
/** L'ID de la Catégorie de Produits demandé. */
category: Schema.Int.pipe(Schema.optional),
/** Le numéro de page demandé. */
page: Schema.Int,
/** Le nombre de Produits par page demandé. */
per_page: Schema.Int,
/** Le statut demandé des Produits. */
status: ProductStatus,
}) {}
class Product extends Schema.Class<Product>("Product")({
attributes: Schema.Unknown,
brands: Schema.Unknown,
// TODO: Pourrait être une énumération.
catalog_visibility: Schema.String,
categories: Schema.Unknown,
description: Schema.String,
dimensions: Schema.Unknown,
featured: Schema.Boolean,
grouped_products: Schema.Unknown,
has_options: Schema.Boolean,
id: Schema.Int,
// NOTE: Non-standard, injecté dans la Réponse.
image_repos: Schema.String,
// NOTE: Non-standard, injecté dans la Réponse.
image_survol: Schema.String,
images: Schema.Unknown,
low_stock_amount: Schema.Union([Schema.Number, Schema.Null]),
menu_order: Schema.Int,
meta_data: Schema.Unknown,
name: Schema.String,
on_sale: Schema.Boolean,
parent_id: Schema.Int,
permalink: Schema.URLFromString,
price: Schema.String,
// NOTE: Non-standard, injecté dans la Réponse.
prix_maximal: Schema.String,
regular_price: Schema.String,
sale_price: Schema.String,
short_description: Schema.String,
sku: Schema.String,
slug: Schema.String,
sold_individually: Schema.Boolean,
stock_quantity: Schema.Union([Schema.Int, Schema.Null]),
// TODO: Pourrait être une énumération.
stock_status: Schema.String,
tags: Schema.Unknown,
type: Schema.Literals(["external", "grouped", "simple", "variable"]),
variations: Schema.Array(Schema.Int),
virtual: Schema.Boolean,
weight: Schema.String,
}) {}
export { CartProduct, GetProducts, Product };

View file

@ -2,6 +2,8 @@
import { Effect, Option, pipe, Schema, SchemaIssue, SchemaTransformation } from "effect"; import { Effect, Option, pipe, Schema, SchemaIssue, SchemaTransformation } from "effect";
import type { SchemaError } from "effect/Schema"; import type { SchemaError } from "effect/Schema";
const ProductStatus = Schema.Literals(["any", "draft", "future", "pending", "private", "publish", "trash"]);
/** Représente l'identifiant numérique unique d'un Produit. */ /** Représente l'identifiant numérique unique d'un Produit. */
const ProductId = Schema.Int.pipe(Schema.brand("ProductId")).check(Schema.isGreaterThan(0)); const ProductId = Schema.Int.pipe(Schema.brand("ProductId")).check(Schema.isGreaterThan(0));
@ -78,6 +80,7 @@ export {
ProductId, ProductId,
ProductQuantity, ProductQuantity,
ProductQuantityFromString, ProductQuantityFromString,
ProductStatus,
ProductVariation, ProductVariation,
ProductVariationAttribute, ProductVariationAttribute,
}; };

View file

@ -0,0 +1,17 @@
import { Console, Layer, ManagedRuntime, pipe } from "effect";
import { APIClient } from "../../scripts-effect/lib/api.ts";
import ShopPageDOM from "./service-dom.ts";
import ShopPageElements from "./service-elements.ts";
import ShopPageMessages from "./service-messages.ts";
const ShopPageRuntime = ManagedRuntime.make(
pipe(
ShopPageDOM.Live,
Layer.provideMerge(ShopPageMessages.Live),
Layer.provideMerge(ShopPageElements.Live),
Layer.provide(APIClient.Live),
Layer.tapError(error => Console.error("ProductPageRuntime", "Impossible de créer le Layer :", error)),
),
);
export default ShopPageRuntime;

View file

@ -0,0 +1,174 @@
import {
Array as FxArray,
Console,
Context,
Effect,
Layer,
Option,
pipe,
Ref,
Schema,
SchemaIssue,
Stream,
SubscriptionRef,
} from "effect";
import { SchemaError } from "effect/Schema";
import html from "html-template-tag";
import { APIClient } from "../../scripts-effect/lib/api.ts";
import { setLoadingState } from "../../scripts-effect/lib/elements.ts";
import { GetProducts, Product } from "../../scripts-effect/schemas/api.ts";
import { ATTRIBUT_HIDDEN, ATTRIBUT_ID_CATEGORIE_PRODUITS, ATTRIBUT_PAGE } from "../constantes/dom.ts";
import ShopPageElements from "./service-elements.ts";
import ShopPageMessages from "./service-messages.ts";
/** Le nombre de Produits à afficher par « page ». */
const PRODUCTS_PER_PAGE = 18;
/** Forme attendue des données injectées dans la page sous forme de JSON. */
class PageStates extends Schema.Opaque<PageStates>()(
Schema.Struct({
authString: Schema.NonEmptyString,
nonce: Schema.NonEmptyString,
}),
) {}
/** Représente une Erreur liée à un état de page invalide ou incohérent empêchant la poursuite des interactions/de la navigation. */
class InvalidShopPageStateError
extends Schema.TaggedErrorClass<InvalidShopPageStateError>()("InvalidShopPageStateError", {
cause: Schema.String,
})
{
/** Créé une `InvalidShopPageStateError` depuis une `SchemaError` levée suite à une validation. */
static readonly fromSchemaError = (schemaError: SchemaError): InvalidShopPageStateError =>
new InvalidShopPageStateError({
cause: SchemaIssue.makeFormatterDefault()(schemaError.issue),
});
}
class ShopPageDOM extends Context.Service<ShopPageDOM>()("haikuatelier.fr/Shop/ShopPageDOM", {
make: Effect.gen(function*() {
const { PageStatesRawJson, ProductsGrid, ShowMoreButton } = yield* ShopPageElements;
const { ShowMoreButtonText } = yield* ShopPageMessages;
const API = yield* APIClient;
const { authString, nonce } = yield* pipe(
PageStatesRawJson.textContent,
(textContent: string) =>
Schema.decodeUnknownEffect(Schema.fromJsonString(PageStates))(textContent, { errors: "all" }),
Effect.mapError(InvalidShopPageStateError.fromSchemaError),
);
/** ID de la Catégorie des Produits de la Page, si la Page courante est une Archive. */
const ProductsCategoryId = yield* pipe(
ProductsGrid.getAttribute(ATTRIBUT_ID_CATEGORIE_PRODUITS),
Number,
Option.fromNullishOr,
Ref.make,
);
// TODO: Créer une SubscriptionRef mettant à jour le DOM au changement de valeur.
const PageNumber = yield* Ref.make(1);
/**
* Créé le `DOM` d'une Carte de Produit sous forme de `<article>`.
*/
const createProductDOM = (product: Product): HTMLElement => {
const article = document.createElement("article");
article.classList.add("produit");
article.innerHTML = html`<figure>
<a href="/product/${product.slug}">
<picture class="produit__illustration produit__illustration__principale">
$${product.image_repos}
</picture>
<picture class="produit__illustration produit__illustration__survol">
$${product.image_survol}
</picture>
</a>
<figcaption class="produit__textuel">
<h3 class="produit__textuel__titre">
<a href="$${product.permalink.toString()}">${product.name}</a>
</h3>
<p class="produit__textuel__prix">
${product.prix_maximal}
</p>
</figcaption>
</figure>
`;
return article;
};
/**
* Créé le `DOM` des Cartes d'une nouvelle page de Produits sous forme d'un `DocumentFragment`.
*/
const createNewPageDOM = (products: ReadonlyArray<Product>) => {
const fragment: DocumentFragment = document.createDocumentFragment();
// Ajoute le HTML des Produits au fragment.
pipe(
FxArray.take(products, PRODUCTS_PER_PAGE),
FxArray.forEach(product => {
const productHTML = createProductDOM(product);
fragment.append(productHTML);
}),
);
return fragment;
};
const onMoreProductsWantedHandler = Effect.fn("onMoreProductsWantedHandler")(function*() {
yield* Console.debug("onMoreProductsWantedHandler");
/** Le numéro de page souhaitée. */
const newPageNumber = yield* Ref.updateAndGet(PageNumber, pageNumber => pageNumber + 1);
/** L'ID de la Catégorie de Produits affichée dans la page si elle existe. */
const categoryId = pipe(yield* Ref.get(ProductsCategoryId), Option.getOrUndefined);
const requestBody = yield* GetProducts.makeEffect({
page: newPageNumber,
per_page: PRODUCTS_PER_PAGE,
status: "publish",
...(categoryId && { category: categoryId }),
});
// Désactive les interactions et affiche un texte de chargement le temps de la requête.
yield* setLoadingState(ShowMoreButton, true);
yield* SubscriptionRef.set(ShowMoreButtonText, "Getting Products...");
const newProducts = yield* API.GetProducts(nonce, requestBody);
yield* Console.debug("onMoreProductsWantedHandler", newProducts);
// Rétablis le texte du Bouton et réactive les interactions.
yield* SubscriptionRef.set(ShowMoreButtonText, "Show more");
yield* setLoadingState(ShowMoreButton, false);
// Cache le bouton s'il y a moins de Produits disponibles que PRODUCTS_PER_PAGE (que l'on est donc à la dernière page).
ShowMoreButton.toggleAttribute(ATTRIBUT_HIDDEN, newProducts.length < PRODUCTS_PER_PAGE);
// Ajoute les nouveaux Produits dans le DOM.
const newProductsFragment = createNewPageDOM(newProducts);
ProductsGrid.append(newProductsFragment);
ProductsGrid.setAttribute(ATTRIBUT_PAGE, String(newPageNumber));
});
/**
* Initialise l'écouteur d'événements de clic sur le bouton de chargement d'une nouvelle page de Produits (« Show more »).
*/
const initMoreProductsOnButtonClick = Effect.fn("initMoreProductsOnButtonClick")(function*() {
return yield* pipe(
Stream.fromEventListener(ShowMoreButton, "click"),
Stream.tap(onMoreProductsWantedHandler),
Stream.runDrain,
);
});
return {
ProductsCategoryId,
initMoreProductsOnButtonClick,
};
}),
}) {
static readonly Live = Layer.effect(this, this.make);
}
export default ShopPageDOM;

View file

@ -0,0 +1,26 @@
import { Context, Effect, Layer } from "effect";
import { getFirstSelectorFromDocument } from "../../scripts-effect/lib/dom.ts";
import { IncoherentDOMError } from "../page-produit/errors.ts";
class ShopPageElements extends Context.Service<ShopPageElements>()("haikuatelier.fr/Shop/ShopPageElements", {
make: Effect.gen(function*() {
const PageStatesRawJson = yield* getFirstSelectorFromDocument<HTMLScriptElement>("#page-states");
/** Le Bouton « Show more » pour afficher plus de Produits à la suite de la Grille. */
const ShowMoreButton = yield* getFirstSelectorFromDocument<HTMLButtonElement>(
"#page-boutique #bouton-plus-de-produits",
);
/** Le conteneur de la Grille des Produits. */
const ProductsGrid = yield* getFirstSelectorFromDocument<HTMLDivElement>("#page-boutique .grille-produits");
return {
PageStatesRawJson,
ProductsGrid,
ShowMoreButton,
};
}).pipe(Effect.mapErrorEager(IncoherentDOMError.fromNoSuchElementError)),
}) {
static readonly Live = Layer.effect(this, this.make);
}
export default ShopPageElements;

View file

@ -0,0 +1,29 @@
import { Context, Effect, Layer, pipe, Stream, SubscriptionRef } from "effect";
import ShopPageElements from "./service-elements.ts";
class ShopPageMessages extends Context.Service<ShopPageMessages>()("haikuatelier.fr/Shop/Messages", {
make: Effect.gen(function*() {
const { ShowMoreButton } = yield* ShopPageElements;
const ShowMoreButtonText = yield* SubscriptionRef.make("Show more");
// Const ShowMoreErrorText = yield* SubscriptionRef.make<Option.Option<string>>(Option.none());
const initShowMoreButtonUpdates = Effect.fn("initShowMoreButtonUpdates")(function*() {
return yield* pipe(
SubscriptionRef.changes(ShowMoreButtonText),
Stream.tap(newText => {
ShowMoreButton.textContent = newText;
return Effect.succeed(newText);
}),
Stream.runDrain,
);
});
return { ShowMoreButtonText, initShowMoreButtonUpdates };
}),
}) {
static readonly Live = Layer.effect(this, this.make);
}
export default ShopPageMessages;

View file

@ -2,75 +2,24 @@
* Scripts pour les fonctionnalités de la page Boutique. * Scripts pour les fonctionnalités de la page Boutique.
*/ */
import { pipe } from "@mobily/ts-belt"; import { Console, Effect } from "effect";
import { tap } from "@mobily/ts-belt/Function"; import ShopPageRuntime from "./page-boutique/runtime.ts";
import { EitherAsync } from "purify-ts"; import ShopPageDOM from "./page-boutique/service-dom.ts";
import { match, P } from "ts-pattern"; import ShopPageElements from "./page-boutique/service-elements.ts";
import { ValiError } from "valibot"; import ShopPageMessages from "./page-boutique/service-messages.ts";
import type { APIFetchErrors } from "./lib/types/api/erreurs";
import type { WCV3Products, WCV3ProductsArgs } from "./lib/types/api/v3/products.ts";
import type { GenericPageState } from "./lib/types/pages";
import { ROUTE_API_NOUVELLE_PRODUCTS } from "./constantes/api.ts";
import { PRODUCT_STATUTES } from "./constantes/api/products.ts";
import {
ATTRIBUT_CHARGEMENT,
ATTRIBUT_DESACTIVE,
ATTRIBUT_HIDDEN,
ATTRIBUT_ID_CATEGORIE_PRODUITS,
ATTRIBUT_PAGE,
DOM_BOUTON_PLUS_PRODUITS,
DOM_GRILLE_PRODUITS,
} from "./constantes/dom.ts";
import { lanceAnimationCycleLoading } from "./lib/animations.ts";
import { html, mustGetEleInDocument } from "./lib/dom.ts";
import { BadRequestError, reporteErreur, ServerError } from "./lib/erreurs.ts";
import { getBackendAvecParametresUrl, newPartialResponse } from "./lib/reseau.ts";
import { WCV3ProductsArgsSchema, WCV3ProductsSchema } from "./lib/schemas/api/v3/products.ts";
import { safeSchemaParse } from "./lib/validation.ts";
type APIProductsErrors =
| APIFetchErrors
| ValiError<typeof WCV3ProductsArgsSchema>
| ValiError<typeof WCV3ProductsSchema>;
// @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
const ETATS_PAGE: GenericPageState = _etats;
// Numéros magiques
const PRODUCTS_PER_PAGE = 12;
// Éléments d'intérêt
const E = {
BOUTON_PLUS_DE_PRODUITS: mustGetEleInDocument<HTMLButtonElement>(DOM_BOUTON_PLUS_PRODUITS),
GRILLE_PRODUITS: mustGetEleInDocument<HTMLDivElement>(DOM_GRILLE_PRODUITS),
};
/**
* TODO
*/
const initialisePageBoutique = (): void => {
/** ID de la Catégorie de Produits si la Page courante est l'Archive d'une Catégorie. */
const idCategorieProduits: null | string = E.GRILLE_PRODUITS.getAttribute(ATTRIBUT_ID_CATEGORIE_PRODUITS);
E.BOUTON_PLUS_DE_PRODUITS.addEventListener("click", (): void => {
/** Le numéro de page demandée par l'Utilisateur. */
const nouveauNumeroPage = Number(E.GRILLE_PRODUITS.getAttribute(ATTRIBUT_PAGE)) + 1;
/** Les arguments passés à la requête auprès Backend pour la nouvelle page de Produits. */
const args: WCV3ProductsArgs = {
page: nouveauNumeroPage,
per_page: PRODUCTS_PER_PAGE,
status: PRODUCT_STATUTES.PUBLISH,
// Ajoute conditionnellement la Catégorie de Produits
...(idCategorieProduits && { category: idCategorieProduits }),
};
undefined;
});
};
document.addEventListener("DOMContentLoaded", (): void => { document.addEventListener("DOMContentLoaded", (): void => {
initialisePageBoutique(); console.debug("scripts-page-boutique");
// initialisePageBoutique();
ShopPageRuntime.runFork(Effect.gen(function*() {
const Elements = yield* ShopPageElements;
const DOM = yield* ShopPageDOM;
const Messages = yield* ShopPageMessages;
yield* Effect.all([DOM.initLoadMoreProductsOnButtonClick(), Messages.initShowMoreButtonUpdates()], {
concurrency: "unbounded",
}).pipe(Effect.tapCause(Console.error));
console.debug(Elements.ProductsGrid);
}));
}); });

View file

@ -31,7 +31,10 @@ $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' => [
'facturation' => $commande->get_address('billing'),
'livraison' => $commande->get_address('shipping'),
],
'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()], 'commande' => ['date' => $date->toDateString(), 'id' => $commande->get_id()],
'livraison' => [ 'livraison' => [
'methode' => $commande->get_shipping_method(), 'methode' => $commande->get_shipping_method(),