From c97251ba9224ecd88d782de5c7a84f5ebf2234ec Mon Sep 17 00:00:00 2001 From: Yashank Aggarwal Date: Thu, 9 Oct 2025 19:48:19 +0530 Subject: [PATCH 1/5] refactor: remove unnecessary regex check for decorator error detection --- packages/@lwc/compiler/src/transformers/javascript.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/@lwc/compiler/src/transformers/javascript.ts b/packages/@lwc/compiler/src/transformers/javascript.ts index 724c503145..88b19e9196 100755 --- a/packages/@lwc/compiler/src/transformers/javascript.ts +++ b/packages/@lwc/compiler/src/transformers/javascript.ts @@ -90,8 +90,7 @@ export default function scriptTransform( // Sniff for a Babel decorator error, so we can provide a more helpful error message. if ( (e as any).code === 'BABEL_TRANSFORM_ERROR' && - (e as any).message?.includes('Decorators are not enabled.') && - /\b(track|api|wire)\b/.test((e as any).message) // sniff for @track/@api/@wire + (e as any).message?.includes('Decorators are not enabled.') ) { transformerError = TransformerErrors.JS_TRANSFORMER_DECORATOR_ERROR; } From e6e7c85f3240fc7e98ca6c0f98ae9e962b7fc2a7 Mon Sep 17 00:00:00 2001 From: Yashank Aggarwal Date: Tue, 14 Oct 2025 20:48:12 +0530 Subject: [PATCH 2/5] refactor: add and fix regex --- packages/@lwc/compiler/src/transformers/javascript.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/@lwc/compiler/src/transformers/javascript.ts b/packages/@lwc/compiler/src/transformers/javascript.ts index 88b19e9196..4b13b2abb4 100755 --- a/packages/@lwc/compiler/src/transformers/javascript.ts +++ b/packages/@lwc/compiler/src/transformers/javascript.ts @@ -88,9 +88,12 @@ export default function scriptTransform( let transformerError = TransformerErrors.JS_TRANSFORMER_ERROR; // Sniff for a Babel decorator error, so we can provide a more helpful error message. + // The regex handles both plain text (@api) and ANSI-formatted ([33m@[39mapi) decorator names if ( (e as any).code === 'BABEL_TRANSFORM_ERROR' && - (e as any).message?.includes('Decorators are not enabled.') + (e as any).message?.includes('Decorators are not enabled.') && + // eslint-disable-next-line no-control-regex -- Intentionally matching ANSI escape sequences + /@[\x1b[0-9;m]*(track|api|wire)\b/.test((e as any).message) ) { transformerError = TransformerErrors.JS_TRANSFORMER_DECORATOR_ERROR; } From ee6caf920e1d5356a35fe6a5483382aae52cd253 Mon Sep 17 00:00:00 2001 From: Yashank Aggarwal Date: Tue, 14 Oct 2025 21:08:14 +0530 Subject: [PATCH 3/5] fix: update regex --- packages/@lwc/compiler/src/transformers/javascript.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/@lwc/compiler/src/transformers/javascript.ts b/packages/@lwc/compiler/src/transformers/javascript.ts index 4b13b2abb4..3cdfee6927 100755 --- a/packages/@lwc/compiler/src/transformers/javascript.ts +++ b/packages/@lwc/compiler/src/transformers/javascript.ts @@ -92,8 +92,7 @@ export default function scriptTransform( if ( (e as any).code === 'BABEL_TRANSFORM_ERROR' && (e as any).message?.includes('Decorators are not enabled.') && - // eslint-disable-next-line no-control-regex -- Intentionally matching ANSI escape sequences - /@[\x1b[0-9;m]*(track|api|wire)\b/.test((e as any).message) + /(track|api|wire)/.test((e as any).message) // sniff for track/api/wire ) { transformerError = TransformerErrors.JS_TRANSFORMER_DECORATOR_ERROR; } From 727ba7a8616bf59299c9d696c3e98fc35a6270b6 Mon Sep 17 00:00:00 2001 From: yashank676 <83955004+yashank676@users.noreply.github.com> Date: Tue, 14 Oct 2025 21:08:50 +0530 Subject: [PATCH 4/5] Update comment --- packages/@lwc/compiler/src/transformers/javascript.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/@lwc/compiler/src/transformers/javascript.ts b/packages/@lwc/compiler/src/transformers/javascript.ts index 3cdfee6927..4067f977f6 100755 --- a/packages/@lwc/compiler/src/transformers/javascript.ts +++ b/packages/@lwc/compiler/src/transformers/javascript.ts @@ -88,7 +88,6 @@ export default function scriptTransform( let transformerError = TransformerErrors.JS_TRANSFORMER_ERROR; // Sniff for a Babel decorator error, so we can provide a more helpful error message. - // The regex handles both plain text (@api) and ANSI-formatted ([33m@[39mapi) decorator names if ( (e as any).code === 'BABEL_TRANSFORM_ERROR' && (e as any).message?.includes('Decorators are not enabled.') && From 0cef3a8ec73ff6b917ad7c2dac17c4db71755c14 Mon Sep 17 00:00:00 2001 From: Yashank Aggarwal Date: Fri, 17 Oct 2025 01:19:38 +0530 Subject: [PATCH 5/5] test: add comprehensive test cases and update regex --- .../__tests__/transform-javascript.spec.ts | 125 ++++++++++++------ .../compiler/src/transformers/javascript.ts | 3 +- 2 files changed, 89 insertions(+), 39 deletions(-) diff --git a/packages/@lwc/compiler/src/transformers/__tests__/transform-javascript.spec.ts b/packages/@lwc/compiler/src/transformers/__tests__/transform-javascript.spec.ts index a2a21e7e3f..28802ea70e 100644 --- a/packages/@lwc/compiler/src/transformers/__tests__/transform-javascript.spec.ts +++ b/packages/@lwc/compiler/src/transformers/__tests__/transform-javascript.spec.ts @@ -152,49 +152,98 @@ describe('instrumentation', () => { }); describe('unnecessary registerDecorators', () => { - it('should provide helpful error for decorator outside of LightningElement, apiVersion=latest', () => { - const actual = ` - import { track } from 'lwc' - class Foo { - @track bar = 'baz'; + it.for([ + { + name: '@api decorator', + code: ` + import { api } from 'lwc' + export default class NotComponent { + @api prop + } + `, + }, + { + name: '@api decorator with comment between import and usage', + code: ` + import { api } from 'lwc' + // the error message should not include the above import + export default class NotComponent { + @api prop + } + `, + }, + ])( + 'should provide helpful error for decorator outside of LightningElement, apiVersion=latest', + ({ code }) => { + let error; + try { + transformSync(code, 'foo.js', { + ...TRANSFORMATION_OPTIONS, + }); + } catch (err) { + error = err; } - `; - let error; - try { - transformSync(actual, 'foo.js', { - ...TRANSFORMATION_OPTIONS, - }); - } catch (err) { - error = err; - } - expect(error).not.toBeUndefined(); - expect((error as any).message).toContain( - 'Decorators like @api, @track, and @wire are only supported in LightningElement classes.' - ); - }); + expect(error).not.toBeUndefined(); + expect((error as any).message).toContain( + 'Decorators like @api, @track, and @wire are only supported in LightningElement classes.' + ); + } + ); - it('should not customize the error message for non-@track/@wire/@api decorators, apiVersion=latest', () => { - const actual = ` - const thisIsNotASupportedDecorator = {}; - class Foo { - @thisIsNotASupportedDecorator bar = 'baz'; + it.for([ + { + name: 'non-LWC decorator', + code: ` + const thisIsNotASupportedDecorator = {}; + class Foo { + @thisIsNotASupportedDecorator bar = 'baz'; + } + `, + }, + { + name: 'almost-LWC decorator name (@apitrackwire)', + code: ` + const apitrackwire = () => {} + export default class NotComponent { + @apitrackwire prop + } + `, + }, + { + name: 'decorator from non-lwc import', + code: `import { eschatology } from 'vermont' + export default class Bananaphone { + @eschatology prewire + }`, + }, + { + name: 'generic decorator', + code: ` + const decorator = () => {} + export default class NotComponent { + @decorator prop + } + `, + }, + ])( + 'should not customize the error message for non-@track/@wire/@api decorators, apiVersion=latest', + ({ code }) => { + let error; + try { + transformSync(code, 'foo.js', { + ...TRANSFORMATION_OPTIONS, + }); + } catch (err) { + error = err; } - `; - let error; - try { - transformSync(actual, 'foo.js', { - ...TRANSFORMATION_OPTIONS, - }); - } catch (err) { - error = err; - } - expect(error).not.toBeUndefined(); - expect((error as any).message).not.toContain( - 'Decorators like @api, @track, and @wire are only supported in LightningElement classes.' - ); - }); + expect(error).not.toBeUndefined(); + expect((error as any).message).not.toContain( + 'Decorators like @api, @track, and @wire are only supported in LightningElement classes.' + ); + } + ); it('should allow decorator outside of LightningElement, apiVersion=59', () => { const actual = ` diff --git a/packages/@lwc/compiler/src/transformers/javascript.ts b/packages/@lwc/compiler/src/transformers/javascript.ts index 4067f977f6..452ca7e1f6 100755 --- a/packages/@lwc/compiler/src/transformers/javascript.ts +++ b/packages/@lwc/compiler/src/transformers/javascript.ts @@ -91,7 +91,8 @@ export default function scriptTransform( if ( (e as any).code === 'BABEL_TRANSFORM_ERROR' && (e as any).message?.includes('Decorators are not enabled.') && - /(track|api|wire)/.test((e as any).message) // sniff for track/api/wire + // eslint-disable-next-line no-control-regex + /(?:\b|\x1b\S*?)(api|wire|track)\b/.test((e as any).message) // sniff for track/api/wire ) { transformerError = TransformerErrors.JS_TRANSFORMER_DECORATOR_ERROR; }