Skip to content

fix(config): allow LogLevel to work with isolatedModules and update all warns and errors to respect logLevel #30350

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Apr 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/src/components/accordion-group/accordion-group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class AccordionGroup implements ComponentInterface {
* Custom behavior: ['a', 'b']
*/
printIonWarning(
`ion-accordion-group was passed an array of values, but multiple="false". This is incorrect usage and may result in unexpected behaviors. To dismiss this warning, pass a string to the "value" property when multiple="false".
`[ion-accordion-group] - An array of values was passed, but multiple is "false". This is incorrect usage and may result in unexpected behaviors. To dismiss this warning, pass a string to the "value" property when multiple="false".

Value Passed: [${value.map((v) => `'${v}'`).join(', ')}]
`,
Expand Down
5 changes: 3 additions & 2 deletions core/src/components/alert/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { Gesture } from '@utils/gesture';
import { createButtonActiveGesture } from '@utils/gesture/button-active';
import { raf } from '@utils/helpers';
import { createLockController } from '@utils/lock-controller';
import { printIonWarning } from '@utils/logging';
import {
createDelegateController,
createTriggerController,
Expand Down Expand Up @@ -318,8 +319,8 @@ export class Alert implements ComponentInterface, OverlayInterface {
// checkboxes and inputs are all accepted, but they cannot be mixed.
const inputTypes = new Set(inputs.map((i) => i.type));
if (inputTypes.has('checkbox') && inputTypes.has('radio')) {
console.warn(
`Alert cannot mix input types: ${Array.from(inputTypes.values()).join(
printIonWarning(
`[ion-alert] - Alert cannot mix input types: ${Array.from(inputTypes.values()).join(
'/'
)}. Please see alert docs for more info.`
);
Expand Down
2 changes: 1 addition & 1 deletion core/src/components/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class App implements ComponentInterface {
*/
if (shouldUseCloseWatcher()) {
printIonWarning(
'experimentalCloseWatcher was set to `true`, but hardwareBackButton was set to `false`. Both config options must be `true` for the Close Watcher API to be used.'
'[ion-app] - experimentalCloseWatcher was set to `true`, but hardwareBackButton was set to `false`. Both config options must be `true` for the Close Watcher API to be used.'
);
}

Expand Down
6 changes: 3 additions & 3 deletions core/src/components/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
* element with that id is not a form element.
*/
printIonWarning(
`Form with selector: "#${form}" could not be found. Verify that the id is attached to a <form> element.`,
`[ion-button] - Form with selector: "#${form}" could not be found. Verify that the id is attached to a <form> element.`,
this.el
);
return null;
Expand All @@ -246,7 +246,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
* element with that id could not be found in the DOM.
*/
printIonWarning(
`Form with selector: "#${form}" could not be found. Verify that the id is correct and the form is rendered in the DOM.`,
`[ion-button] - Form with selector: "#${form}" could not be found. Verify that the id is correct and the form is rendered in the DOM.`,
this.el
);
return null;
Expand All @@ -260,7 +260,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
* as the form attribute.
*/
printIonWarning(
`The provided "form" element is invalid. Verify that the form is a HTMLFormElement and rendered in the DOM.`,
`[ion-button] - The provided "form" element is invalid. Verify that the form is a HTMLFormElement and rendered in the DOM.`,
this.el
);
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>

expect(logs.length).toBe(1);
expect(logs[0]).toContain(
'[Ionic Warning]: Form with selector: "#missingForm" could not be found. Verify that the id is correct and the form is rendered in the DOM.'
'[Ionic Warning]: [ion-button] - Form with selector: "#missingForm" could not be found. Verify that the id is correct and the form is rendered in the DOM.'
);
});

Expand Down Expand Up @@ -197,7 +197,7 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>

expect(logs.length).toBe(1);
expect(logs[0]).toContain(
'[Ionic Warning]: The provided "form" element is invalid. Verify that the form is a HTMLFormElement and rendered in the DOM.'
'[Ionic Warning]: [ion-button] - The provided "form" element is invalid. Verify that the form is a HTMLFormElement and rendered in the DOM.'
);
});
});
Expand Down
8 changes: 4 additions & 4 deletions core/src/components/datetime-button/datetime-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ export class DatetimeButton implements ComponentInterface {
const { datetime } = this;
if (!datetime) {
printIonError(
'An ID associated with an ion-datetime instance is required for ion-datetime-button to function properly.',
'[ion-datetime-button] - An ID associated with an ion-datetime instance is required to function properly.',
this.el
);
return;
}

const datetimeEl = (this.datetimeEl = document.getElementById(datetime) as HTMLIonDatetimeElement | null);
if (!datetimeEl) {
printIonError(`No ion-datetime instance found for ID '${datetime}'.`, this.el);
printIonError(`[ion-datetime-button] - No ion-datetime instance found for ID '${datetime}'.`, this.el);
return;
}

Expand All @@ -81,7 +81,7 @@ export class DatetimeButton implements ComponentInterface {
*/
if (datetimeEl.tagName !== 'ION-DATETIME') {
printIonError(
`Expected an ion-datetime instance for ID '${datetime}' but received '${datetimeEl.tagName.toLowerCase()}' instead.`,
`[ion-datetime-button] - Expected an ion-datetime instance for ID '${datetime}' but received '${datetimeEl.tagName.toLowerCase()}' instead.`,
datetimeEl
);
return;
Expand Down Expand Up @@ -245,7 +245,7 @@ export class DatetimeButton implements ComponentInterface {
try {
headerText = titleSelectedDatesFormatter(parsedValues);
} catch (e) {
printIonError('Exception in provided `titleSelectedDatesFormatter`: ', e);
printIonError('[ion-datetime-button] - Exception in provided `titleSelectedDatesFormatter`:', e);
}
}
this.dateText = headerText;
Expand Down
18 changes: 9 additions & 9 deletions core/src/components/datetime/datetime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ export class Datetime implements ComponentInterface {
* Custom behavior: ['a', 'b']
*/
printIonWarning(
`ion-datetime was passed an array of values, but multiple="false". This is incorrect usage and may result in unexpected behaviors. To dismiss this warning, pass a string to the "value" property when multiple="false".
`[ion-datetime] - An array of values was passed, but multiple is "false". This is incorrect usage and may result in unexpected behaviors. To dismiss this warning, pass a string to the "value" property when multiple="false".

Value Passed: [${value.map((v) => `'${v}'`).join(', ')}]
`,
Expand Down Expand Up @@ -1389,24 +1389,24 @@ export class Datetime implements ComponentInterface {

if (multiple) {
if (presentation !== 'date') {
printIonWarning('Multiple date selection is only supported for presentation="date".', el);
printIonWarning('[ion-datetime] - Multiple date selection is only supported for presentation="date".', el);
}

if (preferWheel) {
printIonWarning('Multiple date selection is not supported with preferWheel="true".', el);
printIonWarning('[ion-datetime] - Multiple date selection is not supported with preferWheel="true".', el);
}
}

if (highlightedDates !== undefined) {
if (presentation !== 'date' && presentation !== 'date-time' && presentation !== 'time-date') {
printIonWarning(
'The highlightedDates property is only supported with the date, date-time, and time-date presentations.',
'[ion-datetime] - The highlightedDates property is only supported with the date, date-time, and time-date presentations.',
el
);
}

if (preferWheel) {
printIonWarning('The highlightedDates property is not supported with preferWheel="true".', el);
printIonWarning('[ion-datetime] - The highlightedDates property is not supported with preferWheel="true".', el);
}
}

Expand Down Expand Up @@ -1668,7 +1668,7 @@ export class Datetime implements ComponentInterface {
disabled = !isDateEnabled(convertDataToISO(referenceParts));
} catch (e) {
printIonError(
'Exception thrown from provided `isDateEnabled` function. Please check your function and try again.',
'[ion-datetime] - Exception thrown from provided `isDateEnabled` function. Please check your function and try again.',
e
);
}
Expand Down Expand Up @@ -1759,7 +1759,7 @@ export class Datetime implements ComponentInterface {
disabled = !isDateEnabled(convertDataToISO(referenceParts));
} catch (e) {
printIonError(
'Exception thrown from provided `isDateEnabled` function. Please check your function and try again.',
'[ion-datetime] - Exception thrown from provided `isDateEnabled` function. Please check your function and try again.',
e
);
}
Expand Down Expand Up @@ -2262,7 +2262,7 @@ export class Datetime implements ComponentInterface {
isCalDayDisabled = !isDateEnabled(dateIsoString);
} catch (e) {
printIonError(
'Exception thrown from provided `isDateEnabled` function. Please check your function and try again.',
'[ion-datetime] - Exception thrown from provided `isDateEnabled` function. Please check your function and try again.',
el,
e
);
Expand Down Expand Up @@ -2483,7 +2483,7 @@ export class Datetime implements ComponentInterface {
try {
headerText = titleSelectedDatesFormatter(convertDataToISO(activeParts));
} catch (e) {
printIonError('Exception in provided `titleSelectedDatesFormatter`: ', e);
printIonError('[ion-datetime] - Exception in provided `titleSelectedDatesFormatter`:', e);
}
}
} else {
Expand Down
4 changes: 2 additions & 2 deletions core/src/components/datetime/test/basic/datetime.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {

expect(logs.length).toBe(1);
expect(logs[0]).toContain(
'[Ionic Warning]: Datetime: "timeZone" and "timeZoneName" are not supported in "formatOptions".'
'[Ionic Warning]: [ion-datetime] - "timeZone" and "timeZoneName" are not supported in "formatOptions".'
);
});

Expand Down Expand Up @@ -717,7 +717,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {

expect(logs.length).toBe(1);
expect(logs[0]).toContain(
"[Ionic Warning]: Datetime: The 'date-time' presentation requires either a date or time object (or both) in formatOptions."
"[Ionic Warning]: [ion-datetime] - The 'date-time' presentation requires either a date or time object (or both) in formatOptions."
);
});
});
Expand Down
2 changes: 1 addition & 1 deletion core/src/components/datetime/utils/comparison.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const warnIfValueOutOfBounds = (
for (const val of valueArray) {
if ((min !== undefined && isBefore(val, min)) || (max !== undefined && isAfter(val, max))) {
printIonWarning(
'The value provided to ion-datetime is out of bounds.\n\n' +
'[ion-datetime] - The value provided to ion-datetime is out of bounds.\n\n' +
`Min: ${JSON.stringify(min)}\n` +
`Max: ${JSON.stringify(max)}\n` +
`Value: ${JSON.stringify(value)}`
Expand Down
4 changes: 3 additions & 1 deletion core/src/components/datetime/utils/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ export function parseDate(val: string | string[] | undefined | null): DatetimePa

if (parse === null) {
// wasn't able to parse the ISO datetime
printIonWarning(`Unable to parse date string: ${val}. Please provide a valid ISO 8601 datetime string.`);
printIonWarning(
`[ion-datetime] - Unable to parse date string: ${val}. Please provide a valid ISO 8601 datetime string.`
);
return undefined;
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/components/datetime/utils/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ export const getHighlightStyles = (
return highlightedDates(dateIsoString);
} catch (e) {
printIonError(
'Exception thrown from provided `highlightedDates` callback. Please check your function and try again.',
'[ion-datetime] - Exception thrown from provided `highlightedDates` callback. Please check your function and try again.',
el,
e
);
Expand Down
11 changes: 7 additions & 4 deletions core/src/components/datetime/utils/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const warnIfTimeZoneProvided = (el: HTMLElement, formatOptions?: FormatOp
formatOptions?.time?.timeZone ||
formatOptions?.time?.timeZoneName
) {
printIonWarning('Datetime: "timeZone" and "timeZoneName" are not supported in "formatOptions".', el);
printIonWarning('[ion-datetime] - "timeZone" and "timeZoneName" are not supported in "formatOptions".', el);
}
};

Expand All @@ -33,19 +33,22 @@ export const checkForPresentationFormatMismatch = (
case 'month':
case 'year':
if (formatOptions.date === undefined) {
printIonWarning(`Datetime: The '${presentation}' presentation requires a date object in formatOptions.`, el);
printIonWarning(
`[ion-datetime] - The '${presentation}' presentation requires a date object in formatOptions.`,
el
);
}
break;
case 'time':
if (formatOptions.time === undefined) {
printIonWarning(`Datetime: The 'time' presentation requires a time object in formatOptions.`, el);
printIonWarning(`[ion-datetime] - The 'time' presentation requires a time object in formatOptions.`, el);
}
break;
case 'date-time':
case 'time-date':
if (formatOptions.date === undefined && formatOptions.time === undefined) {
printIonWarning(
`Datetime: The '${presentation}' presentation requires either a date or time object (or both) in formatOptions.`,
`[ion-datetime] - The '${presentation}' presentation requires either a date or time object (or both) in formatOptions.`,
el
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class InputPasswordToggle implements ComponentInterface {
onTypeChange(newValue: TextFieldTypes) {
if (newValue !== 'text' && newValue !== 'password') {
printIonWarning(
`ion-input-password-toggle only supports inputs of type "text" or "password". Input of type "${newValue}" is not compatible.`,
`[ion-input-password-toggle] - Only inputs of type "text" or "password" are supported. Input of type "${newValue}" is not compatible.`,
this.el
);

Expand All @@ -74,7 +74,7 @@ export class InputPasswordToggle implements ComponentInterface {

if (!inputElRef) {
printIonWarning(
'No ancestor ion-input found for ion-input-password-toggle. This component must be slotted inside of an ion-input.',
'[ion-input-password-toggle] - No ancestor ion-input found. This component must be slotted inside of an ion-input.',
el
);

Expand Down
2 changes: 1 addition & 1 deletion core/src/components/input/input.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const getCounterText = (
try {
return counterFormatter(valueLength, maxLength);
} catch (e) {
printIonError('Exception in provided `counterFormatter`.', e);
printIonError('[ion-input] - Exception in provided `counterFormatter`:', e);
return defaultCounterText;
}
};
Expand Down
3 changes: 2 additions & 1 deletion core/src/components/item-sliding/item-sliding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Method, Prop, State, Watch, h } from '@stencil/core';
import { findClosestIonContent, disableContentScrollY, resetContentScrollY } from '@utils/content';
import { isEndSide } from '@utils/helpers';
import { printIonWarning } from '@utils/logging';
import { watchForOptions } from '@utils/watch-options';

import { getIonMode } from '../../global/ionic-global';
Expand Down Expand Up @@ -343,7 +344,7 @@ export class ItemSliding implements ComponentInterface {
case ItemSide.None:
return;
default:
console.warn('invalid ItemSideFlags value', this.sides);
printIonWarning('[ion-item-sliding] - invalid ItemSideFlags value', this.sides);
break;
}

Expand Down
7 changes: 4 additions & 3 deletions core/src/components/menu/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { GESTURE_CONTROLLER } from '@utils/gesture';
import { shouldUseCloseWatcher } from '@utils/hardware-back-button';
import type { Attributes } from '@utils/helpers';
import { inheritAriaAttributes, assert, clamp, isEndSide as isEnd } from '@utils/helpers';
import { printIonError } from '@utils/logging';
import { menuController } from '@utils/menu-controller';
import { BACKDROP, GESTURE, getPresentedOverlay } from '@utils/overlays';
import { isPlatform } from '@utils/platform';
Expand Down Expand Up @@ -215,13 +216,13 @@ export class Menu implements ComponentInterface, MenuI {
const content = this.contentId !== undefined ? document.getElementById(this.contentId) : null;

if (content === null) {
console.error('Menu: must have a "content" element to listen for drag events on.');
printIonError('[ion-menu] - Must have a "content" element to listen for drag events on.');
return;
}

if (this.el.contains(content)) {
console.error(
`Menu: "contentId" should refer to the main view's ion-content, not the ion-content inside of the ion-menu.`
printIonError(
`[ion-menu] - The "contentId" should refer to the main view's ion-content, not the ion-content inside of the ion-menu.`
);
}

Expand Down
6 changes: 3 additions & 3 deletions core/src/components/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
}

if (breakpoints !== undefined && initialBreakpoint !== undefined && !breakpoints.includes(initialBreakpoint)) {
printIonWarning('Your breakpoints array must include the initialBreakpoint value.');
printIonWarning('[ion-modal] - Your breakpoints array must include the initialBreakpoint value.');
}

if (!this.htmlAttributes?.id) {
Expand Down Expand Up @@ -847,12 +847,12 @@ export class Modal implements ComponentInterface, OverlayInterface {
@Method()
async setCurrentBreakpoint(breakpoint: number): Promise<void> {
if (!this.isSheetModal) {
printIonWarning('setCurrentBreakpoint is only supported on sheet modals.');
printIonWarning('[ion-modal] - setCurrentBreakpoint is only supported on sheet modals.');
return;
}
if (!this.breakpoints!.includes(breakpoint)) {
printIonWarning(
`Attempted to set invalid breakpoint value ${breakpoint}. Please double check that the breakpoint value is part of your defined breakpoints.`
`[ion-modal] - Attempted to set invalid breakpoint value ${breakpoint}. Please double check that the breakpoint value is part of your defined breakpoints.`
);
return;
}
Expand Down
4 changes: 3 additions & 1 deletion core/src/components/modal/test/basic/modal.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,9 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await modal.evaluate((el: HTMLIonModalElement) => el.setCurrentBreakpoint(0.5));

expect(warnings.length).toBe(1);
expect(warnings[0]).toBe('[Ionic Warning]: setCurrentBreakpoint is only supported on sheet modals.');
expect(warnings[0]).toBe(
'[Ionic Warning]: [ion-modal] - setCurrentBreakpoint is only supported on sheet modals.'
);
});

test('it should return undefined when getting the breakpoint on a non-sheet modal', async ({ page }) => {
Expand Down
2 changes: 1 addition & 1 deletion core/src/components/modal/test/sheet/modal.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
test('it should warn when setting an invalid breakpoint', async () => {
expect(warnings.length).toBe(1);
expect(warnings[0]).toBe(
'[Ionic Warning]: Attempted to set invalid breakpoint value 0.01. Please double check that the breakpoint value is part of your defined breakpoints.'
'[Ionic Warning]: [ion-modal] - Attempted to set invalid breakpoint value 0.01. Please double check that the breakpoint value is part of your defined breakpoints.'
);
});
});
Expand Down
Loading
Loading