Skip to content

flex-development/decorator-regex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

decorator-regex

github release npm codecov module type: esm license conventional commits typescript vitest yarn

Decorator regex

Contents

What is this?

This package exports a regular expression for matching decorators. Decorators are functions called on classes, class accessors, class fields, class methods, and/or class method parameters.

When should I use this?

The regular expression exported from this package can be used to match multi and single-line decorators in JavaScript and TypeScript source code.

Note:

  • Decorators in comments (/** */, /* */, //) are ignored
  • Regular expression is ECMAScript-compatible. It has not been tested with other flavors (PCRE, PCRE2, etc)

Install

This package is ESM only.

yarn add @flex-development/decorator-regex

From Git:

yarn add @flex-development/decorator-regex@flex-development/decorator-regex
See Git - Protocols | Yarn  for details on requesting a specific branch, commit, or tag.

Use

Suppose we have the following module:

import { DECORATOR_REGEX } from '@flex-development/decorator-regex'
import { omit } from '@flex-development/tutils'
import { dedent } from 'ts-dedent'

const code: string = dedent`
  /**
    * [Data access object][1] for the {@linkcode DatabaseTable.USERS} table.
    *
    * [1]: https://en.wikipedia.org/wiki/Data_access_object
    *
    * @extends {Entity<IUserRaw,CreateUserDTO,IUser>}
    * @implements {IUser}
    */
   @Table<User>({
     defaultScope: {
       attributes: ['created_at', 'email', 'id', 'provider'],
       order: [['id', OrderDirection.ASC]],
       raw: false
     },
     deletedAt: false,
     hooks: {
       /**
        * Normalizes data before a user is persisted to the database.
        *
        * This includes:
        *
        * - Trimming and lowercasing string fields
        *
        * @param {User} instance - Current user instance
        * @return {void} Nothing when complete
        */
       beforeSave(instance: User): void {
         trimmedLowercasedFields(instance.dataValues)
       }
     },
     omitNull: false,
     paranoid: false,
     tableName: DatabaseTable.USERS,
     timestamps: true
   })
     class User
       extends Entity<IUserRaw, CreateUserDTO, IUser> implements IUser {
       @ApiProperty({ description: 'When user was created', type: Number })
       @Column({
         allowNull: false,
         defaultValue: User.CURRENT_TIMESTAMP,
         type: DataType.BIGINT,
         validate: { isUnixTimestamp: User.isUnixTimestamp }
       })
       declare created_at: IUser['created_at']

       @ApiProperty({
         description: 'Email address',
         maxLength: 254,
         minLength: 3,
         type: String
       })
       @Column({
         allowNull: false,
         type: DataType.STRING(254),
         unique: true,
         validate: { isEmail: true, len: [3, 254] }
       })
       declare email: IUser['email']

       @ApiProperty({ description: 'Unique identifier', type: Number })
       @Column({
         allowNull: false,
         autoIncrementIdentity: true,
         defaultValue: Sequelize.fn('nextval', DatabaseSequence.USERS),
         primaryKey: true,
         type: 'NUMERIC',
         unique: true,
         validate: { notNull: true }
       })
       declare id: IUser['id']

       @ApiProperty({
         description: 'Authentication provider',
         enum: OAuthProvider,
         enumName: 'OAuthProvider',
         nullable: true
       })
       @Column({
         allowNull: true,
         defaultValue: null,
         type: DataType.ENUM(...User.AUTH_PROVIDERS)
       })
       declare provider: IUser['provider']

       @HasMany(() => Token)
       declare tokens: Token[]
     }
`

const print = (matches: IterableIterator<RegExpMatchArray>): void => {
  console.debug([...matches].map(match => omit(match, ['input'])))
}

print(code.matchAll(DECORATOR_REGEX))

...running that yields:

[
  {
    '0': '@Table<User>({\n' +
      '   defaultScope: {\n' +
      "     attributes: ['created_at', 'email', 'id', 'provider'],\n" +
      "     order: [['id', OrderDirection.ASC]],\n" +
      '     raw: false\n' +
      '   },\n' +
      '   deletedAt: false,\n' +
      '   hooks: {\n' +
      '     /**\n' +
      '      * Normalizes data before a user is persisted to the database.\n' +
      '      *\n' +
      '      * This includes:\n' +
      '      *\n' +
      '      * - Trimming and lowercasing string fields\n' +
      '      *\n' +
      '      * @param {User} instance - Current user instance\n' +
      '      * @return {void} Nothing when complete\n' +
      '      */\n' +
      '     beforeSave(instance: User): void {\n' +
      '       trimmedLowercasedFields(instance.dataValues)\n' +
      '     }\n' +
      '   },\n' +
      '   omitNull: false,\n' +
      '   paranoid: false,\n' +
      '   tableName: DatabaseTable.USERS,\n' +
      '   timestamps: true\n' +
      ' })',
    '1': 'Table',
    '2': '({\n' +
      '   defaultScope: {\n' +
      "     attributes: ['created_at', 'email', 'id', 'provider'],\n" +
      "     order: [['id', OrderDirection.ASC]],\n" +
      '     raw: false\n' +
      '   },\n' +
      '   deletedAt: false,\n' +
      '   hooks: {\n' +
      '     /**\n' +
      '      * Normalizes data before a user is persisted to the database.\n' +
      '      *\n' +
      '      * This includes:\n' +
      '      *\n' +
      '      * - Trimming and lowercasing string fields\n' +
      '      *\n' +
      '      * @param {User} instance - Current user instance\n' +
      '      * @return {void} Nothing when complete\n' +
      '      */\n' +
      '     beforeSave(instance: User): void {\n' +
      '       trimmedLowercasedFields(instance.dataValues)\n' +
      '     }\n' +
      '   },\n' +
      '   omitNull: false,\n' +
      '   paranoid: false,\n' +
      '   tableName: DatabaseTable.USERS,\n' +
      '   timestamps: true\n' +
      ' })',
    index: 227,
    groups: [Object: null prototype] {
      identifier: 'Table',
      parameters: '({\n' +
        '   defaultScope: {\n' +
        "     attributes: ['created_at', 'email', 'id', 'provider'],\n" +
        "     order: [['id', OrderDirection.ASC]],\n" +
        '     raw: false\n' +
        '   },\n' +
        '   deletedAt: false,\n' +
        '   hooks: {\n' +
        '     /**\n' +
        '      * Normalizes data before a user is persisted to the database.\n' +
        '      *\n' +
        '      * This includes:\n' +
        '      *\n' +
        '      * - Trimming and lowercasing string fields\n' +
        '      *\n' +
        '      * @param {User} instance - Current user instance\n' +
        '      * @return {void} Nothing when complete\n' +
        '      */\n' +
        '     beforeSave(instance: User): void {\n' +
        '       trimmedLowercasedFields(instance.dataValues)\n' +
        '     }\n' +
        '   },\n' +
        '   omitNull: false,\n' +
        '   paranoid: false,\n' +
        '   tableName: DatabaseTable.USERS,\n' +
        '   timestamps: true\n' +
        ' })'
    }
  },
  {
    '0': "@ApiProperty({ description: 'When user was created', type: Number })",
    '1': 'ApiProperty',
    '2': "({ description: 'When user was created', type: Number })",
    index: 994,
    groups: [Object: null prototype] {
      identifier: 'ApiProperty',
      parameters: "({ description: 'When user was created', type: Number })"
    }
  },
  {
    '0': '@Column({\n' +
      '       allowNull: false,\n' +
      '       defaultValue: User.CURRENT_TIMESTAMP,\n' +
      '       type: DataType.BIGINT,\n' +
      '       validate: { isUnixTimestamp: User.isUnixTimestamp }\n' +
      '     })',
    '1': 'Column',
    '2': '({\n' +
      '       allowNull: false,\n' +
      '       defaultValue: User.CURRENT_TIMESTAMP,\n' +
      '       type: DataType.BIGINT,\n' +
      '       validate: { isUnixTimestamp: User.isUnixTimestamp }\n' +
      '     })',
    index: 1068,
    groups: [Object: null prototype] {
      identifier: 'Column',
      parameters: '({\n' +
        '       allowNull: false,\n' +
        '       defaultValue: User.CURRENT_TIMESTAMP,\n' +
        '       type: DataType.BIGINT,\n' +
        '       validate: { isUnixTimestamp: User.isUnixTimestamp }\n' +
        '     })'
    }
  },
  {
    '0': '@ApiProperty({\n' +
      "       description: 'Email address',\n" +
      '       maxLength: 254,\n' +
      '       minLength: 3,\n' +
      '       type: String\n' +
      '     })',
    '1': 'ApiProperty',
    '2': '({\n' +
      "       description: 'Email address',\n" +
      '       maxLength: 254,\n' +
      '       minLength: 3,\n' +
      '       type: String\n' +
      '     })',
    index: 1296,
    groups: [Object: null prototype] {
      identifier: 'ApiProperty',
      parameters: '({\n' +
        "       description: 'Email address',\n" +
        '       maxLength: 254,\n' +
        '       minLength: 3,\n' +
        '       type: String\n' +
        '     })'
    }
  },
  {
    '0': '@Column({\n' +
      '       allowNull: false,\n' +
      '       type: DataType.STRING(254),\n' +
      '       unique: true,\n' +
      '       validate: { isEmail: true, len: [3, 254] }\n' +
      '     })',
    '1': 'Column',
    '2': '({\n' +
      '       allowNull: false,\n' +
      '       type: DataType.STRING(254),\n' +
      '       unique: true,\n' +
      '       validate: { isEmail: true, len: [3, 254] }\n' +
      '     })',
    index: 1425,
    groups: [Object: null prototype] {
      identifier: 'Column',
      parameters: '({\n' +
        '       allowNull: false,\n' +
        '       type: DataType.STRING(254),\n' +
        '       unique: true,\n' +
        '       validate: { isEmail: true, len: [3, 254] }\n' +
        '     })'
    }
  },
  {
    '0': "@ApiProperty({ description: 'Unique identifier', type: Number })",
    '1': 'ApiProperty',
    '2': "({ description: 'Unique identifier', type: Number })",
    index: 1615,
    groups: [Object: null prototype] {
      identifier: 'ApiProperty',
      parameters: "({ description: 'Unique identifier', type: Number })"
    }
  },
  {
    '0': '@Column({\n' +
      '       allowNull: false,\n' +
      '       autoIncrementIdentity: true,\n' +
      "       defaultValue: Sequelize.fn('nextval', DatabaseSequence.USERS),\n" +
      '       primaryKey: true,\n' +
      "       type: 'NUMERIC',\n" +
      '       unique: true,\n' +
      '       validate: { notNull: true }\n' +
      '     })',
    '1': 'Column',
    '2': '({\n' +
      '       allowNull: false,\n' +
      '       autoIncrementIdentity: true,\n' +
      "       defaultValue: Sequelize.fn('nextval', DatabaseSequence.USERS),\n" +
      '       primaryKey: true,\n' +
      "       type: 'NUMERIC',\n" +
      '       unique: true,\n' +
      '       validate: { notNull: true }\n' +
      '     })',
    index: 1685,
    groups: [Object: null prototype] {
      identifier: 'Column',
      parameters: '({\n' +
        '       allowNull: false,\n' +
        '       autoIncrementIdentity: true,\n' +
        "       defaultValue: Sequelize.fn('nextval', DatabaseSequence.USERS),\n" +
        '       primaryKey: true,\n' +
        "       type: 'NUMERIC',\n" +
        '       unique: true,\n' +
        '       validate: { notNull: true }\n' +
        '     })'
    }
  },
  {
    '0': '@ApiProperty({\n' +
      "       description: 'Authentication provider',\n" +
      '       enum: OAuthProvider,\n' +
      "       enumName: 'OAuthProvider',\n" +
      '       nullable: true\n' +
      '     })',
    '1': 'ApiProperty',
    '2': '({\n' +
      "       description: 'Authentication provider',\n" +
      '       enum: OAuthProvider,\n' +
      "       enumName: 'OAuthProvider',\n" +
      '       nullable: true\n' +
      '     })',
    index: 1974,
    groups: [Object: null prototype] {
      identifier: 'ApiProperty',
      parameters: '({\n' +
        "       description: 'Authentication provider',\n" +
        '       enum: OAuthProvider,\n' +
        "       enumName: 'OAuthProvider',\n" +
        '       nullable: true\n' +
        '     })'
    }
  },
  {
    '0': '@Column({\n' +
      '       allowNull: true,\n' +
      '       defaultValue: null,\n' +
      '       type: DataType.ENUM(...User.AUTH_PROVIDERS)\n' +
      '     })',
    '1': 'Column',
    '2': '({\n' +
      '       allowNull: true,\n' +
      '       defaultValue: null,\n' +
      '       type: DataType.ENUM(...User.AUTH_PROVIDERS)\n' +
      '     })',
    index: 2133,
    groups: [Object: null prototype] {
      identifier: 'Column',
      parameters: '({\n' +
        '       allowNull: true,\n' +
        '       defaultValue: null,\n' +
        '       type: DataType.ENUM(...User.AUTH_PROVIDERS)\n' +
        '     })'
    }
  },
  {
    '0': '@HasMany(() => Token)',
    '1': 'HasMany',
    '2': '(() => Token)',
    index: 2300,
    groups: [Object: null prototype] {
      identifier: 'HasMany',
      parameters: '(() => Token)'
    }
  }
]

API

This package exports the identifier DECORATOR_REGEX.

There is no default export.

DECORATOR_REGEX

Regular expression matching multi and single-line decorators.

Ignores matches in comments.

Required flags:

  • s: dot all
  • u: unicode

Source: src/decorator-regex.ts

Types

This package is fully typed with TypeScript.

Related

Contribute

See CONTRIBUTING.md.