Conversation
commit: |
📝 WalkthroughWalkthroughChanges add a feature-options system and type redesign enabling per-feature option objects. A new generic Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/runtime/core/features.ts`:
- Around line 7-11: The object-type checks access properties without guarding
against null; update the conditions in isFeatureLogsEnabled and the analogous
function isFeatureDevtoolsEnabled (and any similar checks in this file) to first
ensure the feature value is not null before testing typeof (e.g., use
features[feature] !== null && typeof features[feature] === 'object' or
features[feature] != null && typeof ...), then read .logs or .devtools as before
so the expression preserves the original boolean semantics but avoids a runtime
crash when a feature is null.
In `@src/runtime/core/types.ts`:
- Line 5: The generic type bound for FeatureFlags uses an explicit any which
violates lint; update the declaration of FeatureFlags so the generic constraint
uses unknown instead of any (e.g., change T extends Record<string, any> to T
extends Record<string, unknown> and keep the default as Record<string, never>)
so that the type remains equivalent but avoids
`@typescript-eslint/no-explicit-any`; modify the FeatureFlags<T ...> declaration
accordingly.
In `@src/runtime/html-validate/nitro.plugin.ts`:
- Line 33: Remove the trailing whitespace after the object passed to defu when
creating opts (the const opts: ConfigData = defu({...}) expression) so the code
contains no trailing spaces; update the line in the nitro.plugin.ts file (around
the defu call that initializes opts) to eliminate the extra space at the end of
the line to satisfy CI style checks.
- Around line 33-36: The options are being merged with defu in the wrong order
so user options from getFeatureOptions('htmlValidate') are shadowed by
DEFAULT_EXTENDS/DEFAULT_RULES; change the merge to pass the user options
(getFeatureOptions('htmlValidate') ?? {}) as the first argument and the defaults
({ extends: DEFAULT_EXTENDS, rules: DEFAULT_RULES }) as the subsequent argument
so that user-provided values override the defaults when building opts
(ConfigData) using defu.
In `@src/runtime/third-party-scripts/plugin.client.ts`:
- Around line 9-10: The function buildExtensionSchemesRegex is vulnerable
because it interpolates raw scheme strings into a RegExp; map the input schemes
through a regex-escaping routine (e.g., escape any -\/\^$*+?.()|[]{} characters)
before joining, then build the RegExp from the escaped strings so metacharacters
in configured schemes cannot break or change the pattern; add a small helper
named escapeRegExp and use it when constructing the regex in
buildExtensionSchemesRegex.
- Line 5: Remove the unused type import ThirdPartyScriptsFeatureOptions from
plugin.client.ts; locate the import statement "import type {
ThirdPartyScriptsFeatureOptions } from './types'" and delete it (or remove
ThirdPartyScriptsFeatureOptions from the import list) so the file no longer
references that unused symbol and the linter/CI error is resolved.
In `@src/runtime/types.d.ts`:
- Line 5: Remove the unused type import FeaturesName from the import statement:
update the import that currently reads "import type { FeaturesName, Features }
from './core/types'" to only import Features (i.e., "import type { Features }
from './core/types'") so the unused symbol FeaturesName is no longer imported
and the lint error is resolved.
In `@src/runtime/web-vitals/plugin.client.ts`:
- Around line 162-167: Inside the onCLS callback loop that iterates CLS
performance entries, don't use return when an entry is missing sources or when
sourceElement is absent/ignored; replace those early returns with continue so
you skip only the current performanceEntry and continue processing remaining
entries (look for variables/perimeter names performanceEntry, sourceElement and
the onCLS callback loop in plugin.client.ts).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 08e9c8ac-7209-4ac2-86c7-dd2ccf58f313
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (14)
client/app/composables/features.tspackage.jsonsrc/features.tssrc/module.tssrc/runtime/core/features.tssrc/runtime/core/types.tssrc/runtime/feature-options.tssrc/runtime/html-validate/nitro.plugin.tssrc/runtime/html-validate/types.tssrc/runtime/third-party-scripts/plugin.client.tssrc/runtime/third-party-scripts/types.tssrc/runtime/types.d.tssrc/runtime/web-vitals/plugin.client.tssrc/runtime/web-vitals/types.ts
| return typeof features[feature] === 'object' ? features[feature].devtools !== false : !!features[feature] | ||
| } | ||
|
|
||
| export function isFeatureLogsEnabled(feature: FeaturesName): boolean { | ||
| return typeof features[feature] === 'object' ? features[feature].logs : !!features[feature] | ||
| return typeof features[feature] === 'object' ? features[feature].logs !== false : !!features[feature] |
There was a problem hiding this comment.
Guard object checks against null before property access.
Lines 7, 11, and 20 use typeof value === 'object' and then access fields. If a feature is null, this will throw at runtime.
Suggested fix
export function isFeatureDevtoolsEnabled(feature: FeaturesName): boolean {
- return typeof features[feature] === 'object' ? features[feature].devtools !== false : !!features[feature]
+ const value = features[feature]
+ return value && typeof value === 'object' ? value.devtools !== false : !!value
}
export function isFeatureLogsEnabled(feature: FeaturesName): boolean {
- return typeof features[feature] === 'object' ? features[feature].logs !== false : !!features[feature]
+ const value = features[feature]
+ return value && typeof value === 'object' ? value.logs !== false : !!value
}
@@
export function getFeatureOptions<K extends keyof FeatureOptionsMap>(feature: K): FeatureOptionsMap[K] | undefined {
const val = features[feature]
- if (typeof val === 'object' && val.options) {
+ if (val && typeof val === 'object' && val.options) {
return val.options as FeatureOptionsMap[K]
}
return undefined
}Also applies to: 18-23
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/core/features.ts` around lines 7 - 11, The object-type checks
access properties without guarding against null; update the conditions in
isFeatureLogsEnabled and the analogous function isFeatureDevtoolsEnabled (and
any similar checks in this file) to first ensure the feature value is not null
before testing typeof (e.g., use features[feature] !== null && typeof
features[feature] === 'object' or features[feature] != null && typeof ...), then
read .logs or .devtools as before so the expression preserves the original
boolean semantics but avoids a runtime crash when a feature is null.
|
|
||
| export type FeaturesName = 'hydration' | 'lazyLoad' | 'webVitals' | 'thirdPartyScripts' | 'htmlValidate' | ||
|
|
||
| export type FeatureFlags<T extends Record<string, any> = Record<string, never>> = { |
There was a problem hiding this comment.
Replace explicit any in generic bound to fix lint failure.
Line 5 violates @typescript-eslint/no-explicit-any, which is currently failing CI.
Suggested fix
-export type FeatureFlags<T extends Record<string, any> = Record<string, never>> = {
+export type FeatureFlags<T extends Record<string, unknown> = Record<string, never>> = {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export type FeatureFlags<T extends Record<string, any> = Record<string, never>> = { | |
| export type FeatureFlags<T extends Record<string, unknown> = Record<string, never>> = { |
🧰 Tools
🪛 GitHub Actions: ci
[error] 5-5: eslint error: Unexpected any. Specify a different type (@typescript-eslint/no-explicit-any)
🪛 GitHub Check: ci
[failure] 5-5:
Unexpected any. Specify a different type
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/core/types.ts` at line 5, The generic type bound for FeatureFlags
uses an explicit any which violates lint; update the declaration of FeatureFlags
so the generic constraint uses unknown instead of any (e.g., change T extends
Record<string, any> to T extends Record<string, unknown> and keep the default as
Record<string, never>) so that the type remains equivalent but avoids
`@typescript-eslint/no-explicit-any`; modify the FeatureFlags<T ...> declaration
accordingly.
| 'no-inline-style': 'off', | ||
| }, | ||
| }) | ||
| const opts: ConfigData = defu({ |
There was a problem hiding this comment.
Remove trailing whitespace on Line 33 to clear CI style checks.
The current CI output flags trailing spaces here.
🧰 Tools
🪛 GitHub Check: ci
[failure] 33-33:
Trailing spaces not allowed
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/html-validate/nitro.plugin.ts` at line 33, Remove the trailing
whitespace after the object passed to defu when creating opts (the const opts:
ConfigData = defu({...}) expression) so the code contains no trailing spaces;
update the line in the nitro.plugin.ts file (around the defu call that
initializes opts) to eliminate the extra space at the end of the line to satisfy
CI style checks.
| const opts: ConfigData = defu({ | ||
| extends: DEFAULT_EXTENDS, | ||
| rules: DEFAULT_RULES, | ||
| }, getFeatureOptions('htmlValidate') ?? {}) |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
defu npm package function argument precedence which argument has priority
💡 Result:
In defu(object, ...defaults), the leftmost argument wins.
Priority order (highest → lowest):
object(first argument)- first item in
defaults - next item in
defaults - … last default (lowest)
So if the same key exists in multiple arguments, the earliest (leftmost) value is kept, and later arguments only fill in missing properties. [1]
Example: defu({ a: 2 }, { a: 1 }, { a: 0 }) → { a: 2 } (because the first arg has priority). [1]
Source: UnJS defu docs. [1]
References:
[1] (unjs.pages.dev)
Citations:
🏁 Script executed:
find . -name "nitro.plugin.ts" -type fRepository: nuxt/hints
Length of output: 227
🏁 Script executed:
cat -n ./src/runtime/html-validate/nitro.plugin.ts | head -50Repository: nuxt/hints
Length of output: 2154
User htmlValidate options are shadowed by defaults due to defu argument order.
In defu(object, ...defaults), the first argument has priority. Currently, defaults are passed first, preventing user-provided options from getFeatureOptions('htmlValidate') from overriding them. This prevents customization of validation rules and extended configurations.
Suggested fix
- const opts: ConfigData = defu({
- extends: DEFAULT_EXTENDS,
- rules: DEFAULT_RULES,
- }, getFeatureOptions('htmlValidate') ?? {})
+ const opts: ConfigData = defu(getFeatureOptions('htmlValidate') ?? {}, {
+ extends: DEFAULT_EXTENDS,
+ rules: DEFAULT_RULES,
+ })📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const opts: ConfigData = defu({ | |
| extends: DEFAULT_EXTENDS, | |
| rules: DEFAULT_RULES, | |
| }, getFeatureOptions('htmlValidate') ?? {}) | |
| const opts: ConfigData = defu(getFeatureOptions('htmlValidate') ?? {}, { | |
| extends: DEFAULT_EXTENDS, | |
| rules: DEFAULT_RULES, | |
| }) |
🧰 Tools
🪛 GitHub Check: ci
[failure] 33-33:
Trailing spaces not allowed
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/html-validate/nitro.plugin.ts` around lines 33 - 36, The options
are being merged with defu in the wrong order so user options from
getFeatureOptions('htmlValidate') are shadowed by DEFAULT_EXTENDS/DEFAULT_RULES;
change the merge to pass the user options (getFeatureOptions('htmlValidate') ??
{}) as the first argument and the defaults ({ extends: DEFAULT_EXTENDS, rules:
DEFAULT_RULES }) as the subsequent argument so that user-provided values
override the defaults when building opts (ConfigData) using defu.
| import { defu } from 'defu' | ||
| import { logger } from './utils' | ||
| import { getFeatureOptions } from '../core/features' | ||
| import type { ThirdPartyScriptsFeatureOptions } from './types' |
There was a problem hiding this comment.
Remove unused ThirdPartyScriptsFeatureOptions import to unblock CI.
Line 5 is currently unused and reported by the lint job.
Suggested fix
-import type { ThirdPartyScriptsFeatureOptions } from './types'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import type { ThirdPartyScriptsFeatureOptions } from './types' |
🧰 Tools
🪛 GitHub Check: ci
[failure] 5-5:
'ThirdPartyScriptsFeatureOptions' is defined but never used. Allowed unused vars must match /^_/u
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/third-party-scripts/plugin.client.ts` at line 5, Remove the
unused type import ThirdPartyScriptsFeatureOptions from plugin.client.ts; locate
the import statement "import type { ThirdPartyScriptsFeatureOptions } from
'./types'" and delete it (or remove ThirdPartyScriptsFeatureOptions from the
import list) so the file no longer references that unused symbol and the
linter/CI error is resolved.
| function buildExtensionSchemesRegex(schemes: string[]) { | ||
| return new RegExp(`^(${schemes.join('|')}):`) |
There was a problem hiding this comment.
Escape configured schemes before interpolating into RegExp.
Lines 9–10 directly join config values into regex source. A scheme containing regex metacharacters can produce invalid patterns or unintended matches.
Suggested fix
+function escapeRegex(source: string): string {
+ return source.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+}
+
function buildExtensionSchemesRegex(schemes: string[]) {
- return new RegExp(`^(${schemes.join('|')}):`)
+ return new RegExp(`^(${schemes.map(escapeRegex).join('|')}):`)
}🧰 Tools
🪛 ast-grep (0.41.0)
[warning] 9-9: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^(${schemes.join('|')}):)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/third-party-scripts/plugin.client.ts` around lines 9 - 10, The
function buildExtensionSchemesRegex is vulnerable because it interpolates raw
scheme strings into a RegExp; map the input schemes through a regex-escaping
routine (e.g., escape any -\/\^$*+?.()|[]{} characters) before joining, then
build the RegExp from the escaped strings so metacharacters in configured
schemes cannot break or change the pattern; add a small helper named
escapeRegExp and use it when constructing the regex in
buildExtensionSchemesRegex.
| import type { HydrationMismatchPayload, LocalHydrationMismatch } from './hydration/types' | ||
| import type { DirectImportInfo, LazyHydrationState } from './lazy-load/composables' | ||
| import type { FeaturesName, FeatureFlags } from './core/types' | ||
| import type { FeaturesName, Features } from './core/types' |
There was a problem hiding this comment.
Remove unused FeaturesName import to satisfy lint gate.
FeaturesName on Line 5 is never referenced, and CI already reports this as a failure.
Suggested fix
-import type { FeaturesName, Features } from './core/types'
+import type { Features } from './core/types'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import type { FeaturesName, Features } from './core/types' | |
| import type { Features } from './core/types' |
🧰 Tools
🪛 GitHub Check: ci
[failure] 5-5:
'FeaturesName' is defined but never used. Allowed unused vars must match /^_/u
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/types.d.ts` at line 5, Remove the unused type import FeaturesName
from the import statement: update the import that currently reads "import type {
FeaturesName, Features } from './core/types'" to only import Features (i.e.,
"import type { Features } from './core/types'") so the unused symbol
FeaturesName is no longer imported and the lint error is resolved.
| if (!performanceEntry.sources?.[0]) return | ||
|
|
||
| logger.info( | ||
| '[performance] Potential CLS Element: ', | ||
| sourceElement, | ||
| ) | ||
| const sourceElement = performanceEntry.sources?.[0].node | ||
|
|
||
| if ((performanceEntry.value ?? 0) > 0.1) { | ||
| logger.warn( | ||
| `[performance] CLS was ${performanceEntry.value}. Good result is below 0.1 \n\n Learn more: https://web.dev/articles/cls#what-is-a-good-cls-score`, | ||
| ) | ||
| } | ||
| // Nuxt DevTools button causes small layout shift so we ignore it | ||
| if (!sourceElement || sourceElement.parentElement?.className.includes('nuxt-devtools')) return |
There was a problem hiding this comment.
Use continue instead of return inside the CLS entries loop.
On Lines 162 and 167, return exits the entire onCLS callback, so one incomplete/ignored entry prevents processing remaining entries.
Suggested fix
- if (!performanceEntry.sources?.[0]) return
+ if (!performanceEntry.sources?.[0]) continue
@@
- if (!sourceElement || sourceElement.parentElement?.className.includes('nuxt-devtools')) return
+ if (!sourceElement || sourceElement.parentElement?.className.includes('nuxt-devtools')) continue📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (!performanceEntry.sources?.[0]) return | |
| logger.info( | |
| '[performance] Potential CLS Element: ', | |
| sourceElement, | |
| ) | |
| const sourceElement = performanceEntry.sources?.[0].node | |
| if ((performanceEntry.value ?? 0) > 0.1) { | |
| logger.warn( | |
| `[performance] CLS was ${performanceEntry.value}. Good result is below 0.1 \n\n Learn more: https://web.dev/articles/cls#what-is-a-good-cls-score`, | |
| ) | |
| } | |
| // Nuxt DevTools button causes small layout shift so we ignore it | |
| if (!sourceElement || sourceElement.parentElement?.className.includes('nuxt-devtools')) return | |
| if (!performanceEntry.sources?.[0]) continue | |
| const sourceElement = performanceEntry.sources?.[0].node | |
| // Nuxt DevTools button causes small layout shift so we ignore it | |
| if (!sourceElement || sourceElement.parentElement?.className.includes('nuxt-devtools')) continue |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/runtime/web-vitals/plugin.client.ts` around lines 162 - 167, Inside the
onCLS callback loop that iterates CLS performance entries, don't use return when
an entry is missing sources or when sourceElement is absent/ignored; replace
those early returns with continue so you skip only the current performanceEntry
and continue processing remaining entries (look for variables/perimeter names
performanceEntry, sourceElement and the onCLS callback loop in
plugin.client.ts).
There was a problem hiding this comment.
🧹 Nitpick comments (2)
test/unit/build-features.test.ts (1)
45-90: Add build-timeisFeatureLogsEnabledparity tests.This suite validates devtools defaults well, but logs behavior for build-time helpers is currently untested. Adding the same matrix here would reduce regression risk.
✅ Suggested test addition
-import { isFeatureDevtoolsEnabled, isFeatureEnabled, getFeatureOptions } from '../../src/features' +import { isFeatureDevtoolsEnabled, isFeatureEnabled, isFeatureLogsEnabled, getFeatureOptions } from '../../src/features' ... + describe('isFeatureLogsEnabled', () => { + it('returns true for a boolean-enabled feature', () => { + const opts = makeOptions({ + hydration: true, + lazyLoad: true, + webVitals: true, + thirdPartyScripts: true, + htmlValidate: true, + }) + expect(isFeatureLogsEnabled(opts, 'hydration')).toBe(true) + }) + + it('returns false for a boolean-disabled feature', () => { + const opts = makeOptions({ + hydration: false, + lazyLoad: true, + webVitals: true, + thirdPartyScripts: true, + htmlValidate: true, + }) + expect(isFeatureLogsEnabled(opts, 'hydration')).toBe(false) + }) + + it('reads logs flag from object config and defaults to true when omitted', () => { + const opts = makeOptions({ + hydration: true, + lazyLoad: true, + webVitals: { logs: false }, + thirdPartyScripts: { logs: true }, + htmlValidate: { devtools: true }, + }) + expect(isFeatureLogsEnabled(opts, 'webVitals')).toBe(false) + expect(isFeatureLogsEnabled(opts, 'thirdPartyScripts')).toBe(true) + expect(isFeatureLogsEnabled(opts, 'htmlValidate')).toBe(true) + }) + })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/unit/build-features.test.ts` around lines 45 - 90, Add unit tests for parity between devtools and logs by creating a new describe block for isFeatureLogsEnabled that mirrors the existing isFeatureDevtoolsEnabled cases: 1) assert true when the feature is boolean-enabled, 2) assert false when boolean-disabled, 3) read logs flag from object config (e.g., webVitals: { logs: false } and thirdPartyScripts: { logs: true }), and 4) default logs to true when not specified in an object (e.g., webVitals: { devtools: false, logs: undefined } or only other flags present). Use the same test helper makeOptions and call isFeatureLogsEnabled(opts, '<featureName>') in each test to match the existing test matrix for isFeatureDevtoolsEnabled.test/unit/core/features.test.ts (1)
91-109: Add a boolean-featuregetFeatureOptionsundefined case.You already test object-without-options; adding the boolean path makes the runtime contract fully explicit.
✅ Suggested test addition
describe('getFeatureOptions', () => { @@ it('returns undefined for a feature with no options', () => { expect(getFeatureOptions('htmlValidate')).toBeUndefined() }) + + it('returns undefined when feature is configured as a boolean', () => { + expect(getFeatureOptions('hydration')).toBeUndefined() + }) })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/unit/core/features.test.ts` around lines 91 - 109, Add a test case to cover the boolean-feature path by calling getFeatureOptions with a feature key that is configured as a boolean and asserting it returns undefined; specifically, inside the describe('getFeatureOptions') block add an it('returns undefined for a boolean feature') that calls getFeatureOptions('FEATURE_KEY_THAT_IS_BOOLEAN') and expects .toBeUndefined(), replacing FEATURE_KEY_THAT_IS_BOOLEAN with an actual boolean-configured feature key from the codebase so the runtime contract is fully exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@test/unit/build-features.test.ts`:
- Around line 45-90: Add unit tests for parity between devtools and logs by
creating a new describe block for isFeatureLogsEnabled that mirrors the existing
isFeatureDevtoolsEnabled cases: 1) assert true when the feature is
boolean-enabled, 2) assert false when boolean-disabled, 3) read logs flag from
object config (e.g., webVitals: { logs: false } and thirdPartyScripts: { logs:
true }), and 4) default logs to true when not specified in an object (e.g.,
webVitals: { devtools: false, logs: undefined } or only other flags present).
Use the same test helper makeOptions and call isFeatureLogsEnabled(opts,
'<featureName>') in each test to match the existing test matrix for
isFeatureDevtoolsEnabled.
In `@test/unit/core/features.test.ts`:
- Around line 91-109: Add a test case to cover the boolean-feature path by
calling getFeatureOptions with a feature key that is configured as a boolean and
asserting it returns undefined; specifically, inside the
describe('getFeatureOptions') block add an it('returns undefined for a boolean
feature') that calls getFeatureOptions('FEATURE_KEY_THAT_IS_BOOLEAN') and
expects .toBeUndefined(), replacing FEATURE_KEY_THAT_IS_BOOLEAN with an actual
boolean-configured feature key from the codebase so the runtime contract is
fully exercised.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a662f9d9-99c7-4d1f-a47d-3f0af171fade
📒 Files selected for processing (2)
test/unit/build-features.test.tstest/unit/core/features.test.ts
🔗 Linked issue
📚 Description
This PR adds configuration related to features themselves. Allows for example to users to ignore some domains in wbevitals.
AI
This pull request introduces per-feature configuration options for Nuxt Hints features, allowing each feature to accept its own options object in addition to simple boolean or flag settings. It refactors the feature flag types, updates feature detection logic to handle these new options, and adds support for customizing behavior in the
htmlValidate,thirdPartyScripts, andwebVitalsfeatures via user-provided options. The changes also include dependency updates and code improvements for clarity and maintainability.Feature configuration and type system refactor:
src/runtime/core/types.tsto allow each feature to be configured as a boolean or with aFeatureFlagsobject containinglogs,devtools, and anoptionsfield for per-feature options. AddedFeatureOptionsMapfor strong typing of feature-specific options. [1] [2]isFeatureDevtoolsEnabled,isFeatureLogsEnabled, etc.) to treatdevtoolsandlogsas enabled unless explicitly set tofalse, and to properly handle the new options structure. [1] [2] [3]Per-feature options support and usage:
getFeatureOptionshelper functions to extract per-feature options from configuration, used throughout the codebase for type-safe access to options. [1] [2]htmlValidate: Allows user to override default config/rules via options, merged with defaults usingdefu. [1] [2] [3]thirdPartyScripts: Supports custom ignored domains and schemes via options, improving script detection logic. [1] [2] [3]webVitals: Supports configuring tracked metrics and ignored domains for LCP image checks. [1] [2] [3] [4] [5] [6] [7] [8] [9]Dependency and configuration updates:
defuas a dependency for deep merging of configuration objects inpackage.jsonandpnpm-lock.yaml. [1] [2]General code improvements:
Type and interface additions:
src/runtime/feature-options.ts,src/runtime/html-validate/types.ts,src/runtime/third-party-scripts/types.ts, andsrc/runtime/web-vitals/types.tsto ensure type safety and extensibility. [1] [2] [3] [4]