Skip to content
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

BREAKING CHANGE: string literal types in favour of const enums #1870

Merged
merged 35 commits into from
Jan 18, 2024

Conversation

Sayan751
Copy link
Member

@Sayan751 Sayan751 commented Jan 7, 2024

Pull Request

📖 Description

This PR introduces a BREAKING CHANGE, as it converts the following exported const enums to string literal types, as those are more developer friendly, and does not suffers from the issue outlined in #1736.

  • @aurelia/dialog
    • DialogDeactivationStatuses
      - const enum DialogDeactivationStatuses {
      -   Ok = 'ok',
      -   Error = 'error',
      -   Cancel = 'cancel',
      -   Abort = 'abort',
      - }
      +  type DialogDeactivationStatuses = 'ok' | 'error' | 'cancel' | 'abort';
  • @aurelia/kernel
    • ColorOptions
    - const enum ColorOptions {
    -   noColors = 0,
    -   colors = 1,
    - }
    + type ColorOptions = 'no-colors' | 'colors';
  • @aurelia/platform
    • TaskStatus
    - const enum TaskStatus {
    -   pending = 0,
    -   running = 1,
    -   completed = 2,
    -   canceled = 3,
    - }
    + type TaskStatus = 'pending' | 'running' | 'completed' | 'canceled';
  • @aurelia/router-lite
    • ExpressionKind
    - const enum ExpressionKind {
    -   Route,
    -   CompositeSegment,
    -   ScopedSegment,
    -   SegmentGroup,
    -   Segment,
    -   Component,
    -   Action,
    -   Viewport,
    -   ParameterList,
    -   Parameter,
    - }
    + type ExpressionKind = 'Route' | 'CompositeSegment' | 'ScopedSegment' | 'SegmentGroup' | 'Segment' | 'Component' | 'Action' | 'Viewport' | 'ParameterList' | 'Parameter';
  • @aurelia/router
    • ReloadBehavior
    - const enum ReloadBehavior {
    -   default = 'default',
    -   disallow = 'disallow',
    -   reload = 'reload',
    -   refresh = 'refresh',
    - }
    + type ReloadBehavior = 'default' | 'disallow' | 'reload' | 'refresh';
  • @aurelia/runtime-html
    • CommandType
    - const enum CommandType {
    -   None       = 0b0_000,
    -   IgnoreAttr = 0b0_001,
    - }
    + type CommandType = 'None' | 'IgnoreAttr';
    • DefinitionType
    - const enum DefinitionType {
    -   Element = 1,
    -   Attribute = 2,
    - }
    + type DefinitionType = 'Element' | 'Attribute';
    • ViewModelKind
    - const enum ViewModelKind {
    -   customElement,
    -   customAttribute,
    -   synthetic
    - }
    + type ViewModelKind = 'customElement' |  'customAttribute' |  'synthetic';
  • @aurelia/runtime
    • ExpressionKind
    - const enum ExpressionKind {
    -   AccessThis,
    -   AccessGlobal,
    -   AccessScope,
    -   ArrayLiteral,
    -   ObjectLiteral,
    -   PrimitiveLiteral,
    -   Template,
    -   Unary,
    -   CallScope,
    -   CallMember,
    -   CallFunction,
    -   CallGlobal,
    -   AccessMember,
    -   AccessKeyed,
    -   TaggedTemplate,
    -   Binary,
    -   Conditional,
    -   Assign,
    -   ArrowFunction,
    -   ValueConverter,
    -   BindingBehavior,
    -   ArrayBindingPattern,
    -   ObjectBindingPattern,
    -   BindingIdentifier,
    -   ForOfStatement,
    -   Interpolation,
    -   ArrayDestructuring,
    -   ObjectDestructuring,
    -   DestructuringAssignmentLeaf,
    -   DestructuringAssignmentRestLeaf,
    -   Custom,
    - }
    + type ExpressionKind = 'AccessThis' | 'AccessGlobal' | 'AccessScope' | 'ArrayLiteral' | 'ObjectLiteral' | 'PrimitiveLiteral' | 'Template' | 'Unary' | 'CallScope' | 'CallMember' | 'CallFunction' | 'CallGlobal' | 'AccessMember' | 'AccessKeyed' | 'TaggedTemplate' | 'Binary' | 'Conditional' | 'Assign' | 'ArrowFunction' | 'ValueConverter' | 'BindingBehavior' | 'ArrayBindingPattern' | 'ObjectBindingPattern' | 'BindingIdentifier' | 'ForOfStatement' | 'Interpolation' | 'ArrayDestructuring' | 'ObjectDestructuring' | 'DestructuringAssignmentLeaf' | 'DestructuringAssignmentRestLeaf' | 'Custom';
    • ExpressionType
    - const enum ExpressionType {
    -           None = 0,
    -  Interpolation = 0b0_000001,
    -     IsIterator = 0b0_000010,
    -    IsChainable = 0b0_000100,
    -     IsFunction = 0b0_001000,
    -     IsProperty = 0b0_010000,
    -     IsCustom   = 0b0_100000,
    - }
    + type ExpressionType = 'None' | 'Interpolation' | 'IsIterator' | 'IsChainable' | 'IsFunction' | 'IsProperty' | 'IsCustom';
    • CollectionKind
    - const enum CollectionKind {
    -   indexed = 0b1000,
    -   keyed   = 0b0100,
    -   array   = 0b1001,
    -   map     = 0b0110,
    -   set     = 0b0111,
    - }
    + type CollectionKind = 'indexed' | 'keyed' | 'array' | 'map' | 'set';
  • @aurelia/validation-html
    • ValidateEventKind
    - const enum ValidateEventKind {
    -   validate = 'validate',
    -   reset = 'reset',
    - }
    + type ValidateEventKind = 'validate' | 'reset';

🎫 Issues

Closes #1736.

👩‍💻 Reviewer Notes

There are still const enums in code. These fall under the following categories:

  • Used internally; not for public consumption.
  • Flags enum, and hence a string literal type won't make sense.
  • Used widely, and hence a replacement will cause larger bundle size.
  • Ordinal enums like LogLevel from @aurelia/kernel (LogLevel.warn < LogLevel.error), where the string literal type would make the comparison needlessly difficult.

Here is a list of publicly consumable const enums:

  • @aurelia/kernel: LogLevel
  • @aurelia/runtime: AccessorType
  • @aurelia/runtime-html: InstructionType, BindingMode, State

The docs have been updated to include information for TypeScript users.

📑 Test Plan

⏭ Next Steps

Copy link

codecov bot commented Jan 7, 2024

Codecov Report

Attention: 36 lines in your changes are missing coverage. Please review.

Comparison is base (71f82cf) 88.78% compared to head (5cd4e18) 88.78%.

❗ Current head 5cd4e18 differs from pull request most recent head 8b08369. Consider uploading reports for the commit 8b08369 to get more accurate results

Files Patch % Lines
packages/runtime-html/src/templating/controller.ts 74.28% 9 Missing ⚠️
packages/runtime/src/binding/ast.visitor.ts 78.12% 7 Missing ⚠️
packages/router-lite/src/route-expression.ts 33.33% 6 Missing ⚠️
packages/runtime/src/binding/ast.eval.ts 90.00% 5 Missing ⚠️
packages/platform/src/index.ts 81.81% 4 Missing ⚠️
.../router/src/instructions/instruction-parameters.ts 81.81% 2 Missing ⚠️
packages/compat-v1/src/compat-delegate.ts 50.00% 1 Missing ⚠️
packages/i18n/src/t/translation-binding.ts 50.00% 1 Missing ⚠️
packages/state/src/state-templating.ts 75.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1870   +/-   ##
=======================================
  Coverage   88.78%   88.78%           
=======================================
  Files         248      247    -1     
  Lines       22349    22307   -42     
  Branches     5205     5192   -13     
=======================================
- Hits        19842    19806   -36     
+ Misses       2507     2501    -6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Sayan751 Sayan751 changed the title wip: string literal types in favor of const enums BREAKING CHANGE: string literal types in favour of const enums Jan 7, 2024
@Sayan751 Sayan751 marked this pull request as ready for review January 7, 2024 22:25
@Sayan751 Sayan751 requested a review from bigopon January 7, 2024 22:25
@bigopon
Copy link
Member

bigopon commented Jan 8, 2024

There may be enums that feel uncomfortable to express in string, as they used bits to express multiple characteristics. But probably we can try to ignore that since atm, its only the binding command type.
Ill do a simple check for size based on the examples/helloworld app.

@Sayan751 Sayan751 force-pushed the topic/1736-string-literal-types-over-const-enum branch from 531c71c to 5cd4e18 Compare January 12, 2024 19:20
@Sayan751 Sayan751 force-pushed the topic/1736-string-literal-types-over-const-enum branch from 5cd4e18 to 8b08369 Compare January 15, 2024 16:23
Copy link
Member

@bigopon bigopon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work 👍
Quite a tedious PR thanks @Sayan751
For bundle size, it's actually few hundred bytes smaller for a helloworld app 😄

@@ -111,19 +111,24 @@ You can specify the binding mode using the `mode` property and passing in a vali
Please consult the [binding modes](bindable-properties.md#one-way-binding) documentation below to learn how to change the binding modes. By default, the binding mode for bindable properties will be `one-way`
{% endhint %}


{% hint style="warning" %}
When you are developing using TypeScript, ensure that you don't set the `verbatimModuleSyntax` flag (TypeScript `compilerOptions`) to `true`. This is required as the `BindingMode` enum is a const enum. Aurelia applies this same strategy to several other publicly consumable enums, to reduce bundle size. If you set the flag to `true`, you might get a runtime error.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe eventually we won't use const enum. Applications shouldn't be restricted by what we do. The cost isn't too high.

@bigopon
Copy link
Member

bigopon commented Jan 18, 2024

I think we can convert binding mode to numbers & type as well instead of enum.

const toView = 1;
const ...

/**
 * Comment explaining the modes here
 */
export type BindingMode =
  | typeof toView
  | typeof ...

It'll be fine I think as the places that use BindingMode are limited, and normally devs know what to be the values with literal primitive type easily if we have enough comments like this:

export interface BindableDefinition {
  /**
   * Some more comments here if really necessary <<<<<<<
   */
  mode: BindingMode;
}

We can also export a literal BindingMode object for convenience:

export const BindingMode = {
  toView = ...
} as const;

So it'll be just as good compared to the enum.

@bigopon bigopon merged commit e21e0c9 into master Jan 18, 2024
26 checks passed
@bigopon bigopon deleted the topic/1736-string-literal-types-over-const-enum branch January 18, 2024 16:54
@bigopon
Copy link
Member

bigopon commented Jan 18, 2024

@Sayan751 I've merged it for now. For the comments, please address them in a follow up PRs, if you prefer to have me handle them, pls let me know. Nice work 👍

@Sayan751
Copy link
Member Author

I think we can convert binding mode to numbers & type as well instead of enum.

const toView = 1;
const ...

/**
 * Comment explaining the modes here
 */
export type BindingMode =
  | typeof toView
  | typeof ...

It'll be fine I think as the places that use BindingMode are limited, and normally devs know what to be the values with literal primitive type easily if we have enough comments like this:

export interface BindableDefinition {
  /**
   * Some more comments here if really necessary <<<<<<<
   */
  mode: BindingMode;
}

We can also export a literal BindingMode object for convenience:

export const BindingMode = {
  toView = ...
} as const;

So it'll be just as good compared to the enum.

This is a good idea. We can do this.

@Sayan751 I've merged it for now. For the comments, please address them in a follow up PRs, if you prefer to have me handle them, pls let me know. Nice work 👍

I will do a follow-up PR.

AureliaEffect pushed a commit that referenced this pull request Jan 26, 2024
2.0.0-beta.10 (2024-01-26)

**BREAKING CHANGE:**

* **enums:** string literal types replace const enums (#1870) ([e21e0c9](e21e0c9))

**Features:**

* **route-recognizer:** support for route parameter constraints (#1862) ([8f29cfd](8f29cfd))

**Bug Fixes:**

* **docs:** various doc fix
* **au-slot:** properly handle nested projection registration (#1881) ([00e8dee](00e8dee))
* **kernel:** stack preserving error logging for console (#1884) ([030bfa1](030bfa1))
* **portal:** remove target marker when deactivated (#1883) ([3db4c17](3db4c17))
* **validation:** evaluation of tagged rules from bindings (#1878) ([43d12f6](43d12f6))
* **validation:** property parsing with lambda and istanbul (#1877) ([71f82cf](71f82cf))
* **router:** store root/default page instruction correctly (#1869) ([84e6380](84e6380))
* **runtime-html:** template wrapping  (#1875) ([bfdaa3b](bfdaa3b))
* **i18n:** handle change of key in t.bind (#1868) ([c185764](c185764))
* **router-lite:** Router injection and ignoring null/undefined values for query parameters (#1859) ([6a79bc9](6a79bc9))
* **router-lite:** injection of Router alias ([6a79bc9](6a79bc9))
* **runtime-html:** fix broken tests ([bfdaa3b](bfdaa3b))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Consumable enums should not be const enum - support TypeScript verbatimModuleSyntax (and JS projects)
2 participants