node_modules ignore

This commit is contained in:
2025-05-08 23:43:47 +02:00
parent e19d52f172
commit 4574544c9f
65041 changed files with 10593536 additions and 0 deletions

21
server/node_modules/umzug/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014-2017 Sequelize contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

849
server/node_modules/umzug/README.md generated vendored Normal file
View File

@@ -0,0 +1,849 @@
# Umzug
[![Build Status](https://github.com/sequelize/umzug/actions/workflows/ci.yml/badge.svg)](https://github.com/sequelize/umzug/actions/workflows/ci.yml/badge.svg)
[![npm](https://badgen.net/npm/v/umzug)](https://www.npmjs.com/package/umzug)
[![npm (downloads)](https://badgen.net/npm/dm/umzug)](https://npmjs.com/package/umzug)
Umzug is a framework-agnostic migration tool for Node. It provides a clean API for running and rolling back tasks.
## Highlights
* Written in TypeScript
* Built-in typings
* Auto-completion right in your IDE
* Documentation right in your IDE
* Programmatic API for migrations
* Built-in [CLI](#cli)
* Database agnostic
* Supports logging of migration process
* Supports multiple storages for migration data
* [Usage examples](./examples)
## Documentation
_Note: these are the docs for the latest version of umzug, which has several breaking changes from v2.x. See [the upgrading section](#upgrading-from-v2x) for a migration guide. For the previous stable version, please refer to the [v2.x branch](https://github.com/sequelize/umzug/tree/v2.x)._
### Minimal Example
The following example uses a Sqlite database through sequelize and persists the migration data in the database itself through the sequelize storage. There are several more involved examples covering a few different scenarios in the [examples folder](./examples). Note that although this uses Sequelize, Umzug isn't coupled to Sequelize, it's just one of the (most commonly-used) supported storages.
```js
// index.js
const {Sequelize} = require('sequelize')
const {Umzug, SequelizeStorage} = require('umzug')
const sequelize = new Sequelize({dialect: 'sqlite', storage: './db.sqlite'})
const umzug = new Umzug({
migrations: {glob: 'migrations/*.js'},
context: sequelize.getQueryInterface(),
storage: new SequelizeStorage({sequelize}),
logger: console,
})
// Checks migrations and run them if they are not already applied. To keep
// track of the executed migrations, a table (and sequelize model) called SequelizeMeta
// will be automatically created (if it doesn't exist already) and parsed.
await umzug.up()
```
```js
// migrations/00_initial.js
const {Sequelize} = require('sequelize')
async function up({context: queryInterface}) {
await queryInterface.createTable('users', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
},
name: {
type: Sequelize.STRING,
allowNull: false,
},
createdAt: {
type: Sequelize.DATE,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false,
},
})
}
async function down({context: queryInterface}) {
await queryInterface.dropTable('users')
}
module.exports = {up, down}
```
Note that we renamed the `context` argument to `queryInterface` for clarity. The `context` is whatever we specified when creating the Umzug instance in `index.js`.
<details>
<summary>You can also write your migrations in typescript by using `ts-node` in the entrypoint:</summary>
```typescript
// index.ts
require('ts-node/register')
import { Sequelize } from 'sequelize';
import { Umzug, SequelizeStorage } from 'umzug';
const sequelize = new Sequelize({ dialect: 'sqlite', storage: './db.sqlite' });
const umzug = new Umzug({
migrations: { glob: 'migrations/*.ts' },
context: sequelize.getQueryInterface(),
storage: new SequelizeStorage({ sequelize }),
logger: console,
});
// export the type helper exposed by umzug, which will have the `context` argument typed correctly
export type Migration = typeof umzug._types.migration;
(async () => {
await umzug.up();
})();
```
```typescript
// migrations/00_initial.ts
import type { Migration } from '..';
// types will now be available for `queryInterface`
export const up: Migration = ({ context: queryInterface }) => queryInterface.createTable(...)
export const down: Migration = ({ context: queryInterface }) => queryInterface.dropTable(...)
```
</details>
See [these tests](./test/umzug.test.ts) for more examples of Umzug usage, including:
- passing `ignore` and `cwd` parameters to the glob instructions
- customising migrations ordering
- finding migrations from multiple different directories
- using non-js file extensions via a custom resolver, e.g. `.sql`
### Usage
#### Installation
Umzug is available on npm by specifying the correct tag:
```bash
npm install umzug
```
#### Umzug instance
It is possible to configure an Umzug instance by passing an object to the constructor.
```js
const {Umzug} = require('umzug')
const umzug = new Umzug({
/* ... options ... */
})
```
Detailed documentation for these options are in the `UmzugOptions` TypeScript interface, which can be found in [src/types.ts](./src/types.ts).
#### Getting all pending migrations
You can get a list of pending (i.e. not yet executed) migrations with the `pending()` method:
```js
const migrations = await umzug.pending()
// returns an array of all pending migrations.
```
#### Getting all executed migrations
You can get a list of already executed migrations with the `executed()` method:
```js
const migrations = await umzug.executed()
// returns an array of all already executed migrations
```
#### Executing pending migrations
The `up` method can be used to execute all pending migrations.
```js
const migrations = await umzug.up()
// returns an array of all executed migrations
```
It is also possible to pass the name of a migration in order to just run the migrations from the current state to the passed migration name (inclusive).
```js
await umzug.up({to: '20141101203500-task'})
```
To limit the number of migrations that are run, `step` can be used:
```js
// This will run the next two migrations
await umzug.up({step: 2})
```
Running specific migrations while ignoring the right order, can be done like this:
```js
await umzug.up({migrations: ['20141101203500-task', '20141101203501-task-2']})
```
#### Reverting executed migration
The `down` method can be used to revert the last executed migration.
```js
const migration = await umzug.down()
// reverts the last migration and returns it.
```
To revert more than one migration, you can use `step`:
```js
// This will revert the last two migrations
await umzug.down({step: 2})
```
It is possible to pass the name of a migration until which (inclusive) the migrations should be reverted. This allows the reverting of multiple migrations at once.
```js
const migrations = await umzug.down({to: '20141031080000-task'})
// returns an array of all reverted migrations.
```
To revert all migrations, you can pass 0 as the `to` parameter:
```js
await umzug.down({to: 0})
```
Reverting specific migrations while ignoring the right order, can be done like this:
```js
await umzug.down({migrations: ['20141101203500-task', '20141101203501-task-2']})
```
### Migrations
There are two ways to specify migrations: via files or directly via an array of migrations.
#### Migration files
A migration file ideally exposes an `up` and a `down` async functions. They will perform the task of upgrading or downgrading the database.
```js
module.exports = {
async up() {
/* ... */
},
async down() {
/* ... */
},
}
```
Migration files can be located anywhere - they will typically be loaded according to a glob pattern provided to the `Umzug` constructor.
#### Direct migrations list
You can also specify directly a list of migrations to the `Umzug` constructor:
```js
const {Umzug} = require('umzug')
const umzug = new Umzug({
migrations: [
{
// the name of the migration is mandatory
name: '00-first-migration',
async up({context}) {
/* ... */
},
async down({context}) {
/* ... */
},
},
{
name: '01-foo-bar-migration',
async up({context}) {
/* ... */
},
async down({context}) {
/* ... */
},
},
],
context: sequelize.getQueryInterface(),
logger: console,
})
```
#### Modifying the parameters passed to your migration methods
Sometimes it's necessary to modify the parameters `umzug` will pass to your migration methods when the library calls the `up` and `down` methods for each migration. This is the case when using migrations currently generated using `sequelize-cli`. In this case you can use the `resolve` fuction during migration configuration to determine which parameters will be passed to the relevant method
```js
import {Sequelize} from 'sequelize'
import {Umzug, SequelizeStorage} from 'umzug'
const sequelize = new Sequelize(/* ... */)
const umzug = new Umzug({
migrations: {
glob: 'migrations/*.js',
resolve: ({name, path, context}) => {
const migration = require(path)
return {
// adjust the parameters Umzug will
// pass to migration methods when called
name,
up: async () => migration.up(context, Sequelize),
down: async () => migration.down(context, Sequelize),
}
},
},
context: sequelize.getQueryInterface(),
storage: new SequelizeStorage({sequelize}),
logger: console,
})
```
#### Additional migration configuration options
To load migrations in another format, you can use the `resolve` function:
```js
const fs = require('fs')
const {Sequelize} = require('sequelize')
const {Umzug} = require('umzug')
const umzug = new Umzug({
migrations: {
glob: 'migrations/*.up.sql',
resolve: ({name, path, context: sequelize}) => ({
name,
up: async () => {
const sql = fs.readFileSync(path).toString()
return sequelize.query(sql)
},
down: async () => {
// Get the corresponding `.down.sql` file to undo this migration
const sql = fs
.readFileSync(path.replace('.up.sql', '.down.sql'))
.toString()
return sequelize.query(sql)
},
}),
},
context: new Sequelize(/* ... */),
logger: console,
})
```
You can support mixed migration file types, and use umzug's default resolver for javascript/typescript:
```js
const fs = require('fs')
const {Sequelize} = require('sequelize')
const {Umzug} = require('umzug')
const umzug = new Umzug({
migrations: {
glob: 'migrations/*.{js,ts,up.sql}',
resolve: params => {
if (!params.path.endsWith('.sql')) {
return Umzug.defaultResolver(params)
}
const {context: sequelize} = params
return {
name: params.name,
up: async () => {
const sql = fs.readFileSync(params.path).toString()
return sequelize.query(sql)
},
down: async () => {
// Get the corresponding `.down.sql` file to undo this migration
const sql = fs
.readFileSync(params.path.replace('.up.sql', '.down.sql'))
.toString()
return sequelize.query(sql)
},
}
},
},
logger: console,
context: new Sequelize(/* ... */),
})
```
The glob syntax allows loading migrations from multiple locations:
```js
const {Sequelize} = require('sequelize')
const {Umzug} = require('umzug')
const umzug = new Umzug({
migrations: {
glob: '{first-folder/*.js,second-folder-with-different-naming-convention/*.js}',
},
context: new Sequelize(/* ... */),
logger: console,
})
```
Note on migration file sorting:
- file matches, found using [fast-glob](https://npmjs.com/package/fast-glob), will be lexicographically sorted based on their paths
- so if your migrations are `one/m1.js`, `two/m2.js`, `three/m3.js`, the resultant order will be `one/m1.js`, `three/m3.js`, `two/m2.js`
- similarly, if your migrations are called `m1.js`, `m2.js`, ... `m10.js`, `m11.js`, the resultant ordering will be `m1.js`, `m10.js`, `m11.js`, ... `m2.js`
- The easiest way to deal with this is to ensure your migrations appear in a single folder, and their paths match lexicographically with the order they should run in
- If this isn't possible, the ordering can be customised using a new instance (previously, in the beta release for v3, this could be done with `.extend(...)` - see below for example using a new instance)
### Upgrading from v2.x
The Umzug class should be imported as a named import, i.e. `import { Umzug } from 'umzug'`.
The `MigrationMeta` type, which is returned by `umzug.executed()` and `umzug.pending()`, no longer has a `file` property - it has a `name` and *optional* `path` - since migrations are not necessarily bound to files on the file system.
The `migrations.glob` parameter replaces `path`, `pattern` and `traverseDirectories`. It can be used, in combination with `cwd` and `ignore` to do much more flexible file lookups. See https://npmjs.com/package/fast-glob for more information on the syntax.
The `migrations.resolve` parameter replaces `customResolver`. Explicit support for `wrap` and `nameFormatter` has been removed - these can be easily implemented in a `resolve` function.
The constructor option `logging` is replaced by `logger` to allow for `warn` and `error` messages in future. NodeJS's global `console` object can be passed to this. To disable logging, replace `logging: false` with `logger: undefined`.
Events have moved from the default nodejs `EventEmitter` to [emittery](https://www.npmjs.com/package/emittery). It has better design for async code, a less bloated API surface and strong types. But, it doesn't allow passing multiple arguments to callbacks, so listeners have to change slightly, as well as `.addListener(...)` and `.removeListener(...)` no longer being supported (`.on(...)` and `.off(...)` should now be used):
Before:
```js
umzug.on('migrating', (name, m) => console.log({name, path: m.path}))
```
After:
```js
umzug.on('migrating', ev => console.log({name: ev.name, path: ev.path}))
```
The `Umzug#execute` method is removed. Use `Umzug#up` or `Umzug#down`.
The options for `Umguz#up` and `Umzug#down` have changed:
- `umzug.up({ to: 'some-name' })` and `umzug.down({ to: 'some-name' })` are still valid.
- `umzug.up({ from: '...' })` and `umzug.down({ from: '...' })` are no longer supported. To run migrations out-of-order (which is not generally recommended), you can explicitly use `umzug.up({ migrations: ['...'] })` and `umzug.down({ migrations: ['...'] })`.
- name matches must be exact. `umzug.up({ to: 'some-n' })` will no longer match a migration called `some-name`.
- `umzug.down({ to: 0 })` is still valid but `umzug.up({ to: 0 })` is not.
- `umzug.up({ migrations: ['m1', 'm2'] })` is still valid but the shorthand `umzug.up(['m1', 'm2'])` has been removed.
- `umzug.down({ migrations: ['m1', 'm2'] })` is still valid but the shorthand `umzug.down(['m1', 'm2'])` has been removed.
- `umzug.up({ migrations: ['m1', 'already-run'] })` will throw an error, if `already-run` is not found in the list of pending migrations.
- `umzug.down({ migrations: ['m1', 'has-not-been-run'] })` will throw an error, if `has-not-been-run` is not found in the list of executed migrations.
- `umzug.up({ migrations: ['m1', 'm2'], rerun: 'ALLOW' })` will re-apply migrations `m1` and `m2` even if they've already been run.
- `umzug.up({ migrations: ['m1', 'm2'], rerun: 'SKIP' })` will skip migrations `m1` and `m2` if they've already been run.
- `umzug.down({ migrations: ['m1', 'm2'], rerun: 'ALLOW' })` will "revert" migrations `m1` and `m2` even if they've never been run.
- `umzug.down({ migrations: ['m1', 'm2'], rerun: 'SKIP' })` will skip reverting migrations `m1` and `m2` if they haven't been run or are already reverted.
- `umzug.up({ migrations: ['m1', 'does-not-exist', 'm2'] })` will throw an error if the migration name is not found. Note that the error will be thrown and no migrations run unless _all_ migration names are found - whether or not `rerun: 'ALLOW'` is added.
The `context` parameter replaces `params`, and is passed in as a property to migration functions as an options object, alongs side `name` and `path`. This means the signature for migrations, which in v2 was `(context) => Promise<void>`, has changed slightly in v3, to `({ name, path, context }) => Promise<void>`.
#### Handling existing v2-format migrations
The `resolve` function can also be used to upgrade your umzug version to v3 when you have existing v2-compatible migrations:
```js
const {Umzug} = require('umzug')
const umzug = new Umzug({
migrations: {
glob: 'migrations/umzug-v2-format/*.js',
resolve: ({name, path, context}) => {
// Adjust the migration from the new signature to the v2 signature, making easier to upgrade to v3
const migration = require(path)
return {
name,
up: async () => migration.up(context),
down: async () => migration.down(context),
}
},
},
context: sequelize.getQueryInterface(),
logger: console,
})
```
Similarly, you no longer need `migrationSorting`, you can instantiate a new `Umzug` instance to manipulate migration lists directly:
```js
const {Umzug} = require('umzug')
const parent = new Umzug({
migrations: {glob: 'migrations/**/*.js'},
context: sequelize.getQueryInterface(),
})
const umzug = new Umzug({
...parent.options,
migrations: async ctx =>
(await parent.migrations()).sort((a, b) => b.path.localeCompare(a.path)),
})
```
### Storages
Storages define where the migration data is stored.
#### JSON Storage
Using `JSONStorage` will create a JSON file which will contain an array with all the executed migrations. You can specify the path to the file. The default for that is `umzug.json` in the working directory of the process.
Detailed documentation for the options it can take are in the `JSONStorageConstructorOptions` TypeScript interface, which can be found in [src/storage/json.ts](./src/storage/json.ts).
#### Memory Storage
Using `memoryStorage` will store migrations with an in-memory array. This can be useful for proof-of-concepts or tests, since it doesn't interact with databases or filesystems.
It doesn't take any options, just import the `memoryStorage` function and call it to return a storage instance:
```typescript
import { Umzug, memoryStorage } from 'umzug'
const umzug = new Umzug({
migrations: ...,
storage: memoryStorage(),
logger: console,
})
```
#### Sequelize Storage
Using `SequelizeStorage` will create a table in your SQL database called `SequelizeMeta` containing an entry for each executed migration. You will have to pass a configured instance of Sequelize or an existing Sequelize model. Optionally you can specify the model name, table name, or column name. All major Sequelize versions are supported.
Detailed documentation for the options it can take are in the `_SequelizeStorageConstructorOptions` TypeScript interface, which can be found in [src/storage/sequelize.ts](./src/storage/sequelize.ts).
This library has been tested with sequelize v6. It may or may not work with lower versions - use at your own risk.
#### MongoDB Storage
Using `MongoDBStorage` will create a collection in your MongoDB database called `migrations` containing an entry for each executed migration. You will have either to pass a MongoDB Driver Collection as `collection` property. Alternatively you can pass a established MongoDB Driver connection and a collection name.
Detailed documentation for the options it can take are in the `MongoDBStorageConstructorOptions` TypeScript interface, which can be found in [src/storage/mongodb.ts](./src/storage/mongodb.ts).
#### Custom
In order to use a custom storage, you can pass your storage instance to Umzug constructor.
```js
class CustomStorage {
constructor() {}
logMigration() {}
unlogMigration() {}
executed() {}
}
const umzug = new Umzug({
storage: new CustomStorage(/* ... */),
logger: console,
})
```
Your instance must adhere to the [UmzugStorage](./src/storage/contract.ts) interface. If you're using TypeScript you can ensure this at compile time, and get IDE type hints by importing it:
```typescript
import { UmzugStorage } from 'umzug'
class CustomStorage implements UmzugStorage {
/* ... */
}
```
### Events
Umzug is an [emittery event emitter](https://www.npmjs.com/package/emittery). Each of the following events will be called with migration parameters as its payload (with `context`, `name`, and nullable `path` properties). Events are a convenient place to implement application-specific logic that must run around each migration:
* `migrating` - A migration is about to be executed.
* `migrated` - A migration has successfully been executed.
* `reverting` - A migration is about to be reverted.
* `reverted` - A migration has successfully been reverted.
These events run at the beginning and end of `up` and `down` calls. They'll receive an object containing a `context` property:
- `beforeCommand` - Before any command (`'up' | 'down' | 'executed' | 'pending'`) is run.
- `afterCommand` - After any command (`'up' | 'down' | 'executed' | 'pending'`) is run. Note: this will always run, even if the command throws an error.
The [`FileLocker` class](./src/file-locker.ts) uses `beforeAll` and `afterAll` to implement a simple filesystem-based locking mechanism.
All events are type-safe, so IDEs will prevent typos and supply strong types for the event payloads.
### Errors
When a migration throws an error, it will be wrapped in a `MigrationError` which captures the migration metadata (name, path etc.) as well as the original error message, and _will be rethrown_. In most cases, this is expected behaviour, and doesn't require any special handling beyond standard error logging setups.
If you expect failures and want to try to recover from them, you will need to try-catch the call to `umzug.up()`. You can access the original error from the `.cause` property if necessary:
```js
try {
await umzug.up()
} catch (e) {
if (e instanceof MigrationError) {
const original = e.cause
// do something with the original error here
}
throw e
}
```
Under the hood, [verror](https://npmjs.com/package/verror) is used to wrap errors.
### CLI
🚧🚧🚧 The CLI is new to Umzug v3. Feedback on it is welcome in [discussions](https://github.com/sequelize/umzug/discussions) 🚧🚧🚧
Umzug instances provide a `.runAsCLI()` method. When called, this method will automatically cause your program to become a complete CLI, with help text and such:
```js
// migrator.js
const {Umzug} = require('umzug')
const umzug = new Umzug({
/* ... */
})
exports.umzug = umzug
if (require.main === module) {
umzug.runAsCLI()
}
```
Note that this uses the [@rushstack/ts-command-line](https://www.npmjs.com/package/@rushstack/ts-command-line) package, which shows only the top-level message of any errors throw by default. See [here](https://github.com/sequelize/umzug/issues/619#issuecomment-1793297576) for how you can see a full stack trace.
#### CLI Usage
A script like the one above is now a runnable CLI program. You can run `node migrator.js --help` to see how to use it. It will print something like:
<!-- codegen:start {preset: custom, source: ./codegen.js, export: cliHelp} -->
```
usage: <script> [-h] <command> ...
Umzug migrator
Positional arguments:
<command>
up Applies pending migrations
down Revert migrations
pending Lists pending migrations
executed Lists executed migrations
create Create a migration file
Optional arguments:
-h, --help Show this help message and exit.
For detailed help about a specific command, use: <script> <command> -h
```
<!-- codegen:end -->
#### Running migrations
`node migrator up` and `node migrator down` apply and revert migrations respectively. They're the equivalent of the `.up()` and `.down()` methods.
Use `node migrator up --help` and `node migrator down --help` for options (running "to" a specific migration, passing migration names to be run explicitly, and specifying the rerun behavior):
Up:
<!-- codegen:start {preset: custom, source: ./codegen.js, export: cliHelp, action: up} -->
```
usage: <script> up [-h] [--to NAME] [--step COUNT] [--name MIGRATION]
[--rerun {THROW,SKIP,ALLOW}]
Performs all migrations. See --help for more options
Optional arguments:
-h, --help Show this help message and exit.
--to NAME All migrations up to and including this one should be
applied
--step COUNT Apply this many migrations. If not specified, all
will be applied.
--name MIGRATION Explicity declare migration name(s) to be applied.
Only these migrations will be applied.
--rerun {THROW,SKIP,ALLOW}
Specify what action should be taken when a migration
that has already been applied is passed to --name.
The default value is "THROW".
```
<!-- codegen:end -->
Down:
<!-- codegen:start {preset: custom, source: ./codegen.js, export: cliHelp, action: down} -->
```
usage: <script> down [-h] [--to NAME] [--step COUNT] [--name MIGRATION]
[--rerun {THROW,SKIP,ALLOW}]
Undoes previously-applied migrations. By default, undoes the most recent
migration only. Use --help for more options. Useful in development to start
from a clean slate. Use with care in production!
Optional arguments:
-h, --help Show this help message and exit.
--to NAME All migrations up to and including this one should be
reverted. Pass '0' to revert all.
--step COUNT Revert this many migrations. If not specified, only
the most recent migration will be reverted.
--name MIGRATION Explicity declare migration name(s) to be reverted.
Only these migrations will be reverted.
--rerun {THROW,SKIP,ALLOW}
Specify what action should be taken when a migration
that has already been applied is passed to --name.
The default value is "THROW".
```
<!-- codegen:end -->
#### Listing migrations
```bash
node migrator pending # list migrations yet to be run
node migrator executed # list migrations that have already run
node migrator pending --json # list pending migrations including names and paths, in a json array format
node migrator executed --json # list executed migrations including names and paths, in a json array format
node migrator pending --help # show help/options
node migrator executed --help # show help/options
```
<!-- codegen:start {preset: custom, source: ./codegen.js, export: cliHelp, action: pending} -->
```
usage: <script> pending [-h] [--json]
Prints migrations returned by `umzug.pending()`. By default, prints migration
names one per line.
Optional arguments:
-h, --help Show this help message and exit.
--json Print pending migrations in a json format including names and
paths. This allows piping output to tools like jq. Without this
flag, the migration names will be printed one per line.
```
<!-- codegen:end -->
<!-- codegen:start {preset: custom, source: ./codegen.js, export: cliHelp, action: executed} -->
```
usage: <script> executed [-h] [--json]
Prints migrations returned by `umzug.executed()`. By default, prints
migration names one per line.
Optional arguments:
-h, --help Show this help message and exit.
--json Print executed migrations in a json format including names and
paths. This allows piping output to tools like jq. Without this
flag, the migration names will be printed one per line.
```
<!-- codegen:end -->
#### Creating migrations - CLI
Usually, migrations correspond to files on the filesystem. The CLI exposes a way to create migration files easily:
```bash
node migrator create --name my-migration.js
```
This will create a file with a name like `2000.12.25T12.34.56.my-migration.js` in the same directory as the most recent migration file. If it's the very first migration file, you need to specify the folder explicitly:
```bash
node migrator create --name my-migration.js --folder path/to/directory
```
The timestamp prefix can be customized to be date-only or omitted, but be aware that it's strongly recommended to ensure your migrations are lexicographically sortable so it's easy for humans and tools to determine what order they should run in - so the default prefix is recommended.
This will generate a migration file called `<<timestamp>>.my-migration.js` with the default migration template for `.js` files that ships with Umzug.
Umzug also ships with default templates for [`.ts`, `.cjs`, `.mjs` and `.sql` files](./src/templates.ts). Umzug will choose the template based on the extension you provide in `name`.
You can specify a custom template for your project when constructing an umzug instance via the `template` option. It should be a function which receives a filepath string, and returns an array of `[filepath, content]` pairs. Usually, just one pair is needed, but a second could be used to include a "down" migration in a separate file:
```js
const umzug = new Umzug({
migrations: {
/*...*/
},
create: {
template: filepath => [
[filepath, fs.readFileSync('path/to/your/template/file').toString()],
],
},
})
```
The create command includes some safety checks to make sure migrations aren't created with ambiguous ordering, and that they will be picked up by umzug when applying migrations. The first pair is expected to be the "up" migration file, and to be picked up by the `pending` command.
Use `node migrator create --help` for more options:
<!-- codegen:start {preset: custom, source: ./codegen.js, export: cliHelp, action: create} -->
```
usage: <script> create [-h] --name NAME [--prefix {TIMESTAMP,DATE,NONE}]
[--folder PATH] [--allow-extension EXTENSION]
[--skip-verify] [--allow-confusing-ordering]
Generates a placeholder migration file using a timestamp as a prefix. By
default, mimics the last existing migration, or guesses where to generate the
file if no migration exists yet.
Optional arguments:
-h, --help Show this help message and exit.
--name NAME The name of the migration file. e.g. my-migration.js,
my-migration.ts or my-migration.sql. Note - a prefix
will be added to this name, usually based on a
timestamp. See --prefix
--prefix {TIMESTAMP,DATE,NONE}
The prefix format for generated files. TIMESTAMP uses
a second-resolution timestamp, DATE uses a
day-resolution timestamp, and NONE removes the prefix
completely. The default value is "TIMESTAMP".
--folder PATH Path on the filesystem where the file should be
created. The new migration will be created as a
sibling of the last existing one if this is omitted.
--allow-extension EXTENSION
Allowable extension for created files. By default .js,
.ts and .sql files can be created. To create txt
file migrations, for example, you could use '--name
my-migration.txt --allow-extension .txt' This
parameter may alternatively be specified via the
UMZUG_ALLOW_EXTENSION environment variable.
--skip-verify By default, the generated file will be checked after
creation to make sure it is detected as a pending
migration. This catches problems like creation in the
wrong folder, or invalid naming conventions. This
flag bypasses that verification step.
--allow-confusing-ordering
By default, an error will be thrown if you try to
create a migration that will run before a migration
that already exists. This catches errors which can
cause problems if you change file naming conventions.
If you use a custom ordering system, you can disable
this behavior, but it's strongly recommended that you
don't! If you're unsure, just ignore this option.
```
<!-- codegen:end -->
### Creating migrations - API
Umzug includes an optional helper for generating migration files. It's often most convenient to create files using the [CLI helper](#creating-migrations---cli), but the equivalent API also exists on an umzug instance:
```js
await umzug.create({name: 'my-new-migration.js'})
```
## License
See the [LICENSE file](./LICENSE)

44
server/node_modules/umzug/lib/cli.d.ts generated vendored Normal file
View File

@@ -0,0 +1,44 @@
import * as cli from '@rushstack/ts-command-line';
import type { Umzug } from './umzug';
export declare class UpAction extends cli.CommandLineAction {
protected umzug: Umzug;
private _params;
constructor(umzug: Umzug);
private static _defineParameters;
onDefineParameters(): void;
onExecute(): Promise<void>;
}
export declare class DownAction extends cli.CommandLineAction {
protected umzug: Umzug;
private _params;
constructor(umzug: Umzug);
private static _defineParameters;
onDefineParameters(): void;
onExecute(): Promise<void>;
}
export declare class ListAction extends cli.CommandLineAction {
private readonly action;
private readonly umzug;
private _params;
constructor(action: 'pending' | 'executed', umzug: Umzug);
private static _defineParameters;
onDefineParameters(): void;
onExecute(): Promise<void>;
}
export declare class CreateAction extends cli.CommandLineAction {
readonly umzug: Umzug;
private _params;
constructor(umzug: Umzug);
private static _defineParameters;
onDefineParameters(): void;
onExecute(): Promise<void>;
}
export type CommandLineParserOptions = {
toolFileName?: string;
toolDescription?: string;
};
export declare class UmzugCLI extends cli.CommandLineParser {
readonly umzug: Umzug;
constructor(umzug: Umzug, commandLineParserOptions?: CommandLineParserOptions);
onDefineParameters(): void;
}

275
server/node_modules/umzug/lib/cli.js generated vendored Normal file
View File

@@ -0,0 +1,275 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UmzugCLI = exports.CreateAction = exports.ListAction = exports.DownAction = exports.UpAction = void 0;
const cli = __importStar(require("@rushstack/ts-command-line"));
class UpAction extends cli.CommandLineAction {
constructor(umzug) {
super({
actionName: 'up',
summary: 'Applies pending migrations',
documentation: 'Performs all migrations. See --help for more options',
});
this.umzug = umzug;
}
static _defineParameters(action) {
return {
to: action.defineStringParameter({
parameterLongName: '--to',
argumentName: 'NAME',
description: `All migrations up to and including this one should be applied`,
}),
step: action.defineIntegerParameter({
parameterLongName: '--step',
argumentName: 'COUNT',
description: `Apply this many migrations. If not specified, all will be applied.`,
}),
name: action.defineStringListParameter({
parameterLongName: '--name',
argumentName: 'MIGRATION',
description: `Explicity declare migration name(s) to be applied. Only these migrations will be applied.`,
}),
rerun: action.defineChoiceParameter({
parameterLongName: '--rerun',
description: `Specify what action should be taken when a migration that has already been applied is passed to --name.`,
alternatives: ['THROW', 'SKIP', 'ALLOW'],
defaultValue: 'THROW',
}),
};
}
onDefineParameters() {
this._params = UpAction._defineParameters(this);
}
async onExecute() {
var _a;
const { to: { value: to }, step: { value: step }, name: { values: nameArray }, rerun: { value: rerun }, } = this._params;
// string list parameters are always defined. When they're empty it means nothing was passed.
const migrations = nameArray.length > 0 ? nameArray : undefined;
if (to && migrations) {
throw new Error(`Can't specify 'to' and 'name' together`);
}
if (to && typeof step === 'number') {
throw new Error(`Can't specify 'to' and 'step' together`);
}
if (typeof step === 'number' && migrations) {
throw new Error(`Can't specify 'step' and 'name' together`);
}
if (rerun !== 'THROW' && !migrations) {
throw new Error(`Can't specify 'rerun' without 'name'`);
}
const result = await this.umzug.up({ to, step, migrations, rerun });
(_a = this.umzug.options.logger) === null || _a === void 0 ? void 0 : _a.info({ event: this.actionName, message: `applied ${result.length} migrations.` });
}
}
exports.UpAction = UpAction;
class DownAction extends cli.CommandLineAction {
constructor(umzug) {
super({
actionName: 'down',
summary: 'Revert migrations',
documentation: 'Undoes previously-applied migrations. By default, undoes the most recent migration only. Use --help for more options. Useful in development to start from a clean slate. Use with care in production!',
});
this.umzug = umzug;
}
static _defineParameters(action) {
return {
to: action.defineStringParameter({
parameterLongName: '--to',
argumentName: 'NAME',
description: `All migrations up to and including this one should be reverted. Pass '0' to revert all.`,
}),
step: action.defineIntegerParameter({
parameterLongName: '--step',
argumentName: 'COUNT',
description: `Revert this many migrations. If not specified, only the most recent migration will be reverted.`,
}),
name: action.defineStringListParameter({
parameterLongName: '--name',
argumentName: 'MIGRATION',
description: `Explicity declare migration name(s) to be reverted. Only these migrations will be reverted.`,
}),
// todo: come up with a better word for this
rerun: action.defineChoiceParameter({
parameterLongName: '--rerun',
description: `Specify what action should be taken when a migration that has already been applied is passed to --name.`,
alternatives: ['THROW', 'SKIP', 'ALLOW'],
defaultValue: 'THROW',
}),
};
}
onDefineParameters() {
this._params = DownAction._defineParameters(this);
}
async onExecute() {
var _a;
const { to: { value: to }, step: { value: step }, name: { values: nameArray }, rerun: { value: rerun }, } = this._params;
// string list parameters are always defined. When they're empty it means nothing was passed.
const migrations = nameArray.length > 0 ? nameArray : undefined;
if (to && migrations) {
throw new Error(`Can't specify 'to' and 'name' together`);
}
if (to && typeof step === 'number') {
throw new Error(`Can't specify 'to' and 'step' together`);
}
if (typeof step === 'number' && migrations) {
throw new Error(`Can't specify 'step' and 'name' together`);
}
if (rerun !== 'THROW' && !migrations) {
throw new Error(`Can't specify 'rerun' without 'name'`);
}
const result = await this.umzug.down({
to: to === '0' ? 0 : to,
step,
migrations,
rerun,
});
(_a = this.umzug.options.logger) === null || _a === void 0 ? void 0 : _a.info({ event: this.actionName, message: `reverted ${result.length} migrations.` });
}
}
exports.DownAction = DownAction;
class ListAction extends cli.CommandLineAction {
constructor(action, umzug) {
super({
actionName: action,
summary: `Lists ${action} migrations`,
documentation: `Prints migrations returned by \`umzug.${action}()\`. By default, prints migration names one per line.`,
});
this.action = action;
this.umzug = umzug;
}
static _defineParameters(action) {
return {
json: action.defineFlagParameter({
parameterLongName: '--json',
description: `Print ${action.actionName} migrations in a json format including names and paths. This allows piping output to tools like jq. ` +
`Without this flag, the migration names will be printed one per line.`,
}),
};
}
onDefineParameters() {
this._params = ListAction._defineParameters(this);
}
async onExecute() {
const migrations = await this.umzug[this.action]();
const formatted = this._params.json.value
? JSON.stringify(migrations, null, 2)
: migrations.map(m => m.name).join('\n');
// eslint-disable-next-line no-console
console.log(formatted);
}
}
exports.ListAction = ListAction;
class CreateAction extends cli.CommandLineAction {
constructor(umzug) {
super({
actionName: 'create',
summary: 'Create a migration file',
documentation: 'Generates a placeholder migration file using a timestamp as a prefix. By default, mimics the last existing migration, or guesses where to generate the file if no migration exists yet.',
});
this.umzug = umzug;
}
static _defineParameters(action) {
return {
name: action.defineStringParameter({
parameterLongName: '--name',
argumentName: 'NAME',
description: `The name of the migration file. e.g. my-migration.js, my-migration.ts or my-migration.sql. Note - a prefix will be added to this name, usually based on a timestamp. See --prefix`,
required: true,
}),
prefix: action.defineChoiceParameter({
parameterLongName: '--prefix',
description: 'The prefix format for generated files. TIMESTAMP uses a second-resolution timestamp, DATE uses a day-resolution timestamp, and NONE removes the prefix completely',
alternatives: ['TIMESTAMP', 'DATE', 'NONE'],
defaultValue: 'TIMESTAMP',
}),
folder: action.defineStringParameter({
parameterLongName: '--folder',
argumentName: 'PATH',
description: `Path on the filesystem where the file should be created. The new migration will be created as a sibling of the last existing one if this is omitted.`,
}),
allowExtension: action.defineStringListParameter({
parameterLongName: '--allow-extension',
argumentName: 'EXTENSION',
environmentVariable: 'UMZUG_ALLOW_EXTENSION',
description: `Allowable extension for created files. By default .js, .ts and .sql files can be created. To create txt file migrations, for example, you could use '--name my-migration.txt --allow-extension .txt'`,
}),
skipVerify: action.defineFlagParameter({
parameterLongName: '--skip-verify',
description: `By default, the generated file will be checked after creation to make sure it is detected as a pending migration. This catches problems like creation in the wrong folder, or invalid naming conventions. ` +
`This flag bypasses that verification step.`,
}),
allowConfusingOrdering: action.defineFlagParameter({
parameterLongName: '--allow-confusing-ordering',
description: `By default, an error will be thrown if you try to create a migration that will run before a migration that already exists. ` +
`This catches errors which can cause problems if you change file naming conventions. ` +
`If you use a custom ordering system, you can disable this behavior, but it's strongly recommended that you don't! ` +
`If you're unsure, just ignore this option.`,
}),
};
}
onDefineParameters() {
this._params = CreateAction._defineParameters(this);
}
async onExecute() {
await this.umzug
.create({
name: this._params.name.value,
prefix: this._params.prefix.value,
folder: this._params.folder.value,
allowExtension: this._params.allowExtension.values.length > 0 ? this._params.allowExtension.values[0] : undefined,
allowConfusingOrdering: this._params.allowConfusingOrdering.value,
skipVerify: this._params.skipVerify.value,
})
.catch((e) => {
Object.entries(this._params)
.filter(entry => entry[0] !== 'name')
.forEach(([name, param]) => {
var _a;
// replace `skipVerify` in error messages with `--skip-verify`, etc.
e.message = (_a = e.message) === null || _a === void 0 ? void 0 : _a.split(name).join(param.longName);
});
throw e;
});
}
}
exports.CreateAction = CreateAction;
class UmzugCLI extends cli.CommandLineParser {
constructor(umzug, commandLineParserOptions = {}) {
var _a, _b;
super({
toolFilename: (_a = commandLineParserOptions.toolFileName) !== null && _a !== void 0 ? _a : '<script>',
toolDescription: (_b = commandLineParserOptions.toolDescription) !== null && _b !== void 0 ? _b : 'Umzug migrator',
});
this.umzug = umzug;
this.addAction(new UpAction(umzug));
this.addAction(new DownAction(umzug));
this.addAction(new ListAction('pending', umzug));
this.addAction(new ListAction('executed', umzug));
this.addAction(new CreateAction(umzug));
}
onDefineParameters() { }
}
exports.UmzugCLI = UmzugCLI;
//# sourceMappingURL=cli.js.map

1
server/node_modules/umzug/lib/cli.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

46
server/node_modules/umzug/lib/file-locker.d.ts generated vendored Normal file
View File

@@ -0,0 +1,46 @@
/// <reference types="node" />
import * as fs from 'fs';
import type { Umzug } from './umzug';
export type FileLockerOptions = {
path: string;
fs?: typeof fs;
};
/**
* Simple locker using the filesystem. Only one lock can be held per file. An error will be thrown if the
* lock file already exists.
*
* @example
* const umzug = new Umzug({ ... })
* FileLocker.attach(umzug, { path: 'path/to/lockfile' })
*
* @docs
* To wait for the lock to be free instead of throwing, you could extend it (the below example uses `setInterval`,
* but depending on your use-case, you may want to use a library with retry/backoff):
*
* @example
* class WaitingFileLocker extends FileLocker {
* async getLock() {
* return new Promise(resolve => setInterval(
* () => super.getLock().then(resolve).catch(),
* 500,
* )
* }
* }
*
* const locker = new WaitingFileLocker({ path: 'path/to/lockfile' })
* locker.attachTo(umzug)
*/
export declare class FileLocker {
private readonly lockFile;
private readonly fs;
constructor(params: FileLockerOptions);
/** Attach `beforeAll` and `afterAll` events to an umzug instance which use the specified filepath */
static attach(umzug: Umzug, params: FileLockerOptions): void;
/** Attach lock handlers to `beforeCommand` and `afterCommand` events on an umzug instance */
attachTo(umzug: Umzug): void;
private readFile;
private writeFile;
private removeFile;
getLock(): Promise<void>;
releaseLock(): Promise<void>;
}

96
server/node_modules/umzug/lib/file-locker.js generated vendored Normal file
View File

@@ -0,0 +1,96 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileLocker = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
/**
* Simple locker using the filesystem. Only one lock can be held per file. An error will be thrown if the
* lock file already exists.
*
* @example
* const umzug = new Umzug({ ... })
* FileLocker.attach(umzug, { path: 'path/to/lockfile' })
*
* @docs
* To wait for the lock to be free instead of throwing, you could extend it (the below example uses `setInterval`,
* but depending on your use-case, you may want to use a library with retry/backoff):
*
* @example
* class WaitingFileLocker extends FileLocker {
* async getLock() {
* return new Promise(resolve => setInterval(
* () => super.getLock().then(resolve).catch(),
* 500,
* )
* }
* }
*
* const locker = new WaitingFileLocker({ path: 'path/to/lockfile' })
* locker.attachTo(umzug)
*/
class FileLocker {
constructor(params) {
var _a;
this.lockFile = params.path;
this.fs = (_a = params.fs) !== null && _a !== void 0 ? _a : fs;
}
/** Attach `beforeAll` and `afterAll` events to an umzug instance which use the specified filepath */
static attach(umzug, params) {
const locker = new FileLocker(params);
locker.attachTo(umzug);
}
/** Attach lock handlers to `beforeCommand` and `afterCommand` events on an umzug instance */
attachTo(umzug) {
umzug.on('beforeCommand', async () => this.getLock());
umzug.on('afterCommand', async () => this.releaseLock());
}
async readFile(filepath) {
return this.fs.promises.readFile(filepath).then(buf => buf.toString(), () => undefined);
}
async writeFile(filepath, content) {
await this.fs.promises.mkdir(path.dirname(filepath), { recursive: true });
await this.fs.promises.writeFile(filepath, content);
}
async removeFile(filepath) {
await this.fs.promises.unlink(filepath);
}
async getLock() {
const existing = await this.readFile(this.lockFile);
if (existing) {
throw new Error(`Can't acquire lock. ${this.lockFile} exists`);
}
await this.writeFile(this.lockFile, 'lock');
}
async releaseLock() {
const existing = await this.readFile(this.lockFile);
if (!existing) {
throw new Error(`Nothing to unlock`);
}
await this.removeFile(this.lockFile);
}
}
exports.FileLocker = FileLocker;
//# sourceMappingURL=file-locker.js.map

1
server/node_modules/umzug/lib/file-locker.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"file-locker.js","sourceRoot":"","sources":["../src/file-locker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAwB;AACxB,2CAA4B;AAQ5B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAa,UAAU;IAIrB,YAAY,MAAyB;;QACnC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAA;QAC3B,IAAI,CAAC,EAAE,GAAG,MAAA,MAAM,CAAC,EAAE,mCAAI,EAAE,CAAA;IAC3B,CAAC;IAED,qGAAqG;IACrG,MAAM,CAAC,MAAM,CAAC,KAAY,EAAE,MAAyB;QACnD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAA;QACrC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IACxB,CAAC;IAED,6FAA6F;IAC7F,QAAQ,CAAC,KAAY;QACnB,KAAK,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;QACrD,KAAK,CAAC,EAAE,CAAC,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;IAC1D,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,QAAgB;QACrC,OAAO,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAC7C,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,EACrB,GAAG,EAAE,CAAC,SAAS,CAChB,CAAA;IACH,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,OAAe;QACvD,MAAM,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC,CAAA;QACvE,MAAM,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IACrD,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,QAAgB;QACvC,MAAM,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IACzC,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACnD,IAAI,QAAQ,EAAE;YACZ,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,CAAC,QAAQ,SAAS,CAAC,CAAA;SAC/D;QAED,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IAC7C,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACnD,IAAI,CAAC,QAAQ,EAAE;YACb,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAA;SACrC;QAED,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACtC,CAAC;CACF;AAtDD,gCAsDC"}

5
server/node_modules/umzug/lib/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
export * from './umzug';
export * from './storage';
export * from './file-locker';
export * from './types';
export * from './cli';

22
server/node_modules/umzug/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,22 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./umzug"), exports);
__exportStar(require("./storage"), exports);
__exportStar(require("./file-locker"), exports);
__exportStar(require("./types"), exports);
__exportStar(require("./cli"), exports);
//# sourceMappingURL=index.js.map

1
server/node_modules/umzug/lib/index.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAuB;AACvB,4CAAyB;AACzB,gDAA6B;AAC7B,0CAAuB;AACvB,wCAAqB"}

17
server/node_modules/umzug/lib/storage/contract.d.ts generated vendored Normal file
View File

@@ -0,0 +1,17 @@
import type { MigrationParams } from '../types';
export type UmzugStorage<Ctx = unknown> = {
/**
* Logs migration to be considered as executed.
*/
logMigration: (params: MigrationParams<Ctx>) => Promise<void>;
/**
* Unlogs migration (makes it to be considered as pending).
*/
unlogMigration: (params: MigrationParams<Ctx>) => Promise<void>;
/**
* Gets list of executed migrations.
*/
executed: (meta: Pick<MigrationParams<Ctx>, 'context'>) => Promise<string[]>;
};
export declare function isUmzugStorage(arg: Partial<UmzugStorage>): arg is UmzugStorage;
export declare const verifyUmzugStorage: (arg: Partial<UmzugStorage>) => UmzugStorage;

18
server/node_modules/umzug/lib/storage/contract.js generated vendored Normal file
View File

@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyUmzugStorage = exports.isUmzugStorage = void 0;
function isUmzugStorage(arg) {
return (arg &&
typeof arg.logMigration === 'function' &&
typeof arg.unlogMigration === 'function' &&
typeof arg.executed === 'function');
}
exports.isUmzugStorage = isUmzugStorage;
const verifyUmzugStorage = (arg) => {
if (!isUmzugStorage(arg)) {
throw new Error(`Invalid umzug storage`);
}
return arg;
};
exports.verifyUmzugStorage = verifyUmzugStorage;
//# sourceMappingURL=contract.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/storage/contract.ts"],"names":[],"mappings":";;;AAmBA,SAAgB,cAAc,CAAC,GAA0B;IACvD,OAAO,CACL,GAAG;QACH,OAAO,GAAG,CAAC,YAAY,KAAK,UAAU;QACtC,OAAO,GAAG,CAAC,cAAc,KAAK,UAAU;QACxC,OAAO,GAAG,CAAC,QAAQ,KAAK,UAAU,CACnC,CAAA;AACH,CAAC;AAPD,wCAOC;AAEM,MAAM,kBAAkB,GAAG,CAAC,GAA0B,EAAgB,EAAE;IAC7E,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAA;KACzC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AANY,QAAA,kBAAkB,sBAM9B"}

5
server/node_modules/umzug/lib/storage/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
export * from './contract';
export * from './json';
export * from './memory';
export * from './mongodb';
export * from './sequelize';

24
server/node_modules/umzug/lib/storage/index.js generated vendored Normal file
View File

@@ -0,0 +1,24 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
// codegen:start {preset: barrel}
__exportStar(require("./contract"), exports);
__exportStar(require("./json"), exports);
__exportStar(require("./memory"), exports);
__exportStar(require("./mongodb"), exports);
__exportStar(require("./sequelize"), exports);
// codegen:end
//# sourceMappingURL=index.js.map

1
server/node_modules/umzug/lib/storage/index.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iCAAiC;AACjC,6CAA0B;AAC1B,yCAAsB;AACtB,2CAAwB;AACxB,4CAAyB;AACzB,8CAA2B;AAC3B,cAAc"}

20
server/node_modules/umzug/lib/storage/json.d.ts generated vendored Normal file
View File

@@ -0,0 +1,20 @@
import type { UmzugStorage } from './contract';
export type JSONStorageConstructorOptions = {
/**
Path to JSON file where the log is stored.
@default './umzug.json'
*/
readonly path?: string;
};
export declare class JSONStorage implements UmzugStorage {
readonly path: string;
constructor(options?: JSONStorageConstructorOptions);
logMigration({ name: migrationName }: {
name: string;
}): Promise<void>;
unlogMigration({ name: migrationName }: {
name: string;
}): Promise<void>;
executed(): Promise<string[]>;
}

61
server/node_modules/umzug/lib/storage/json.js generated vendored Normal file
View File

@@ -0,0 +1,61 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JSONStorage = void 0;
const fs_1 = require("fs");
const path = __importStar(require("path"));
const filesystem = {
/** reads a file as a string or returns null if file doesn't exist */
async readAsync(filepath) {
return fs_1.promises.readFile(filepath).then(c => c.toString(), () => null);
},
/** writes a string as file contents, creating its parent directory if necessary */
async writeAsync(filepath, content) {
await fs_1.promises.mkdir(path.dirname(filepath), { recursive: true });
await fs_1.promises.writeFile(filepath, content);
},
};
class JSONStorage {
constructor(options) {
var _a;
this.path = (_a = options === null || options === void 0 ? void 0 : options.path) !== null && _a !== void 0 ? _a : path.join(process.cwd(), 'umzug.json');
}
async logMigration({ name: migrationName }) {
const loggedMigrations = await this.executed();
loggedMigrations.push(migrationName);
await filesystem.writeAsync(this.path, JSON.stringify(loggedMigrations, null, 2));
}
async unlogMigration({ name: migrationName }) {
const loggedMigrations = await this.executed();
const updatedMigrations = loggedMigrations.filter(name => name !== migrationName);
await filesystem.writeAsync(this.path, JSON.stringify(updatedMigrations, null, 2));
}
async executed() {
const content = await filesystem.readAsync(this.path);
return content ? JSON.parse(content) : [];
}
}
exports.JSONStorage = JSONStorage;
//# sourceMappingURL=json.js.map

1
server/node_modules/umzug/lib/storage/json.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/storage/json.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2BAAiC;AACjC,2CAA4B;AAG5B,MAAM,UAAU,GAAG;IACjB,qEAAqE;IACrE,KAAK,CAAC,SAAS,CAAC,QAAgB;QAC9B,OAAO,aAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAC/B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,EACjB,GAAG,EAAE,CAAC,IAAI,CACX,CAAA;IACH,CAAC;IACD,mFAAmF;IACnF,KAAK,CAAC,UAAU,CAAC,QAAgB,EAAE,OAAe;QAChD,MAAM,aAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAC,SAAS,EAAE,IAAI,EAAC,CAAC,CAAA;QACzD,MAAM,aAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IACvC,CAAC;CACF,CAAA;AAWD,MAAa,WAAW;IAGtB,YAAY,OAAuC;;QACjD,IAAI,CAAC,IAAI,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,IAAI,mCAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,YAAY,CAAC,CAAA;IACrE,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAC,IAAI,EAAE,aAAa,EAAiB;QACtD,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAA;QAC9C,gBAAgB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QAEpC,MAAM,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IACnF,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,EAAC,IAAI,EAAE,aAAa,EAAiB;QACxD,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAA;QAC9C,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,aAAa,CAAC,CAAA;QAEjF,MAAM,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IACpF,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrD,OAAO,OAAO,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAc,CAAC,CAAC,CAAC,EAAE,CAAA;IACzD,CAAC;CACF;AAzBD,kCAyBC"}

2
server/node_modules/umzug/lib/storage/memory.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
import type { UmzugStorage } from './contract';
export declare const memoryStorage: () => UmzugStorage;

17
server/node_modules/umzug/lib/storage/memory.js generated vendored Normal file
View File

@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.memoryStorage = void 0;
const memoryStorage = () => {
let executed = [];
return {
async logMigration({ name }) {
executed.push(name);
},
async unlogMigration({ name }) {
executed = executed.filter(n => n !== name);
},
executed: async () => [...executed],
};
};
exports.memoryStorage = memoryStorage;
//# sourceMappingURL=memory.js.map

1
server/node_modules/umzug/lib/storage/memory.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/storage/memory.ts"],"names":[],"mappings":";;;AAEO,MAAM,aAAa,GAAG,GAAiB,EAAE;IAC9C,IAAI,QAAQ,GAAa,EAAE,CAAA;IAC3B,OAAO;QACL,KAAK,CAAC,YAAY,CAAC,EAAC,IAAI,EAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrB,CAAC;QACD,KAAK,CAAC,cAAc,CAAC,EAAC,IAAI,EAAC;YACzB,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAA;QAC7C,CAAC;QACD,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC;KACpC,CAAA;AACH,CAAC,CAAA;AAXY,QAAA,aAAa,iBAWzB"}

35
server/node_modules/umzug/lib/storage/mongodb.d.ts generated vendored Normal file
View File

@@ -0,0 +1,35 @@
import type { UmzugStorage } from './contract';
type AnyObject = Record<string, any>;
export type MongoDBConnectionOptions = {
/**
A connection to target database established with MongoDB Driver
*/
readonly connection: AnyObject;
/**
The name of the migration collection in MongoDB
@default 'migrations'
*/
readonly collectionName?: string;
};
export type MongoDBCollectionOptions = {
/**
A reference to a MongoDB Driver collection
*/
readonly collection: AnyObject;
};
export type MongoDBStorageConstructorOptions = MongoDBConnectionOptions | MongoDBCollectionOptions;
export declare class MongoDBStorage implements UmzugStorage {
readonly collection: AnyObject;
readonly connection: any;
readonly collectionName: string;
constructor(options: MongoDBStorageConstructorOptions);
logMigration({ name: migrationName }: {
name: string;
}): Promise<void>;
unlogMigration({ name: migrationName }: {
name: string;
}): Promise<void>;
executed(): Promise<string[]>;
}
export {};

31
server/node_modules/umzug/lib/storage/mongodb.js generated vendored Normal file
View File

@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MongoDBStorage = void 0;
function isMongoDBCollectionOptions(arg) {
return Boolean(arg.collection);
}
class MongoDBStorage {
constructor(options) {
var _a, _b;
if (!options || (!options.collection && !options.connection)) {
throw new Error('MongoDB Connection or Collection required');
}
this.collection = isMongoDBCollectionOptions(options)
? options.collection
: options.connection.collection((_a = options.collectionName) !== null && _a !== void 0 ? _a : 'migrations');
this.connection = options.connection; // TODO remove this
this.collectionName = (_b = options.collectionName) !== null && _b !== void 0 ? _b : 'migrations'; // TODO remove this
}
async logMigration({ name: migrationName }) {
await this.collection.insertOne({ migrationName });
}
async unlogMigration({ name: migrationName }) {
await this.collection.deleteOne({ migrationName });
}
async executed() {
const records = await this.collection.find({}).sort({ migrationName: 1 }).toArray();
return records.map(r => r.migrationName);
}
}
exports.MongoDBStorage = MongoDBStorage;
//# sourceMappingURL=mongodb.js.map

1
server/node_modules/umzug/lib/storage/mongodb.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"mongodb.js","sourceRoot":"","sources":["../../src/storage/mongodb.ts"],"names":[],"mappings":";;;AA6BA,SAAS,0BAA0B,CAAC,GAAQ;IAC1C,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;AAChC,CAAC;AAED,MAAa,cAAc;IAKzB,YAAY,OAAyC;;QACnD,IAAI,CAAC,OAAO,IAAI,CAAC,CAAE,OAAe,CAAC,UAAU,IAAI,CAAE,OAAe,CAAC,UAAU,CAAC,EAAE;YAC9E,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;SAC7D;QAED,IAAI,CAAC,UAAU,GAAG,0BAA0B,CAAC,OAAO,CAAC;YACnD,CAAC,CAAC,OAAO,CAAC,UAAU;YACpB,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,MAAA,OAAO,CAAC,cAAc,mCAAI,YAAY,CAAC,CAAA;QAEzE,IAAI,CAAC,UAAU,GAAI,OAAe,CAAC,UAAU,CAAA,CAAC,mBAAmB;QACjE,IAAI,CAAC,cAAc,GAAG,MAAC,OAAe,CAAC,cAAc,mCAAI,YAAY,CAAA,CAAC,mBAAmB;IAC3F,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAC,IAAI,EAAE,aAAa,EAAiB;QACtD,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAC,aAAa,EAAC,CAAC,CAAA;IAClD,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,EAAC,IAAI,EAAE,aAAa,EAAiB;QACxD,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAC,aAAa,EAAC,CAAC,CAAA;IAClD,CAAC;IAED,KAAK,CAAC,QAAQ;QAEZ,MAAM,OAAO,GAAa,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAC,aAAa,EAAE,CAAC,EAAC,CAAC,CAAC,OAAO,EAAE,CAAA;QAC3F,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAA;IAC1C,CAAC;CACF;AA/BD,wCA+BC"}

106
server/node_modules/umzug/lib/storage/sequelize.d.ts generated vendored Normal file
View File

@@ -0,0 +1,106 @@
import type { SetRequired } from 'type-fest';
import type { UmzugStorage } from './contract';
type ModelTempInterface = {} & ModelClass & Record<string, any>;
/**
* Minimal structure of a sequelize model, defined here to avoid a hard dependency.
* The type expected is `import { Model } from 'sequelize'`
*/
export type ModelClass = {
tableName: string;
sequelize?: SequelizeType;
getTableName(): string;
sync(): Promise<void>;
findAll(options?: {}): Promise<any[]>;
create(options: {}): Promise<void>;
destroy(options: {}): Promise<void>;
};
/**
* Minimal structure of a sequelize model, defined here to avoid a hard dependency.
* The type expected is `import { Sequelize } from 'sequelize'`
*/
export type SequelizeType = {
getQueryInterface(): any;
isDefined(modelName: string): boolean;
model(modelName: string): any;
define(modelName: string, columns: {}, options: {}): {};
dialect?: {
name?: string;
};
};
type ModelClassType = ModelClass & (new (values?: object, options?: any) => ModelTempInterface);
type _SequelizeStorageConstructorOptions = {
/**
The configured instance of Sequelize. If omitted, it is inferred from the `model` option.
*/
readonly sequelize?: SequelizeType;
/**
The model representing the SequelizeMeta table. Must have a column that matches the `columnName` option. If omitted, it is created automatically.
*/
readonly model?: any;
/**
The name of the model.
@default 'SequelizeMeta'
*/
readonly modelName?: string;
/**
The name of the table. If omitted, defaults to the model name.
*/
readonly tableName?: string;
/**
Name of the schema under which the table is to be created.
@default undefined
*/
readonly schema?: any;
/**
Name of the table column holding the executed migration names.
@default 'name'
*/
readonly columnName?: string;
/**
The type of the column holding the executed migration names.
For `utf8mb4` charsets under InnoDB, you may need to set this to less than 190
@default Sequelize.DataTypes.STRING
*/
readonly columnType?: any;
/**
Option to add timestamps to the table
@default false
*/
readonly timestamps?: boolean;
};
export type SequelizeStorageConstructorOptions = SetRequired<_SequelizeStorageConstructorOptions, 'sequelize'> | SetRequired<_SequelizeStorageConstructorOptions, 'model'>;
export declare class SequelizeStorage implements UmzugStorage {
readonly sequelize: SequelizeType;
readonly columnType: string;
readonly columnName: string;
readonly timestamps: boolean;
readonly modelName: string;
readonly tableName?: string;
readonly schema: any;
readonly model: ModelClassType;
/**
Constructs Sequelize based storage. Migrations will be stored in a SequelizeMeta table using the given instance of Sequelize.
If a model is given, it will be used directly as the model for the SequelizeMeta table. Otherwise, it will be created automatically according to the given options.
If the table does not exist it will be created automatically upon the logging of the first migration.
*/
constructor(options: SequelizeStorageConstructorOptions);
getModel(): ModelClassType;
protected syncModel(): Promise<void>;
logMigration({ name: migrationName }: {
name: string;
}): Promise<void>;
unlogMigration({ name: migrationName }: {
name: string;
}): Promise<void>;
executed(): Promise<string[]>;
_model(): ModelClassType;
}
export {};

85
server/node_modules/umzug/lib/storage/sequelize.js generated vendored Normal file
View File

@@ -0,0 +1,85 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SequelizeStorage = void 0;
const DIALECTS_WITH_CHARSET_AND_COLLATE = new Set(['mysql', 'mariadb']);
class SequelizeStorage {
/**
Constructs Sequelize based storage. Migrations will be stored in a SequelizeMeta table using the given instance of Sequelize.
If a model is given, it will be used directly as the model for the SequelizeMeta table. Otherwise, it will be created automatically according to the given options.
If the table does not exist it will be created automatically upon the logging of the first migration.
*/
constructor(options) {
var _a, _b, _c, _d, _e, _f;
if (!options || (!options.model && !options.sequelize)) {
throw new Error('One of "sequelize" or "model" storage option is required');
}
this.sequelize = (_a = options.sequelize) !== null && _a !== void 0 ? _a : options.model.sequelize;
this.columnType = (_b = options.columnType) !== null && _b !== void 0 ? _b : this.sequelize.constructor.DataTypes.STRING;
this.columnName = (_c = options.columnName) !== null && _c !== void 0 ? _c : 'name';
this.timestamps = (_d = options.timestamps) !== null && _d !== void 0 ? _d : false;
this.modelName = (_e = options.modelName) !== null && _e !== void 0 ? _e : 'SequelizeMeta';
this.tableName = options.tableName;
this.schema = options.schema;
this.model = (_f = options.model) !== null && _f !== void 0 ? _f : this.getModel();
}
getModel() {
var _a;
if (this.sequelize.isDefined(this.modelName)) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return this.sequelize.model(this.modelName);
}
const dialectName = (_a = this.sequelize.dialect) === null || _a === void 0 ? void 0 : _a.name;
const hasCharsetAndCollate = dialectName && DIALECTS_WITH_CHARSET_AND_COLLATE.has(dialectName);
return this.sequelize.define(this.modelName, {
[this.columnName]: {
type: this.columnType,
allowNull: false,
unique: true,
primaryKey: true,
autoIncrement: false,
},
}, {
tableName: this.tableName,
schema: this.schema,
timestamps: this.timestamps,
charset: hasCharsetAndCollate ? 'utf8' : undefined,
collate: hasCharsetAndCollate ? 'utf8_unicode_ci' : undefined,
});
}
async syncModel() {
await this.model.sync();
}
async logMigration({ name: migrationName }) {
await this.syncModel();
await this.model.create({
[this.columnName]: migrationName,
});
}
async unlogMigration({ name: migrationName }) {
await this.syncModel();
await this.model.destroy({
where: {
[this.columnName]: migrationName,
},
});
}
async executed() {
await this.syncModel();
const migrations = await this.model.findAll({ order: [[this.columnName, 'ASC']] });
return migrations.map(migration => {
const name = migration[this.columnName];
if (typeof name !== 'string') {
throw new TypeError(`Unexpected migration name type: expected string, got ${typeof name}`);
}
return name;
});
}
// TODO remove this
_model() {
return this.model;
}
}
exports.SequelizeStorage = SequelizeStorage;
//# sourceMappingURL=sequelize.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"sequelize.js","sourceRoot":"","sources":["../../src/storage/sequelize.ts"],"names":[],"mappings":";;;AAmCA,MAAM,iCAAiC,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAA;AA8DvE,MAAa,gBAAgB;IAU3B;;;;;;QAMC;IACD,YAAY,OAA2C;;QACrD,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;YACtD,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAA;SAC5E;QAED,IAAI,CAAC,SAAS,GAAG,MAAA,OAAO,CAAC,SAAS,mCAAI,OAAO,CAAC,KAAK,CAAC,SAAS,CAAA;QAC7D,IAAI,CAAC,UAAU,GAAG,MAAA,OAAO,CAAC,UAAU,mCAAK,IAAI,CAAC,SAAS,CAAC,WAAmB,CAAC,SAAS,CAAC,MAAM,CAAA;QAC5F,IAAI,CAAC,UAAU,GAAG,MAAA,OAAO,CAAC,UAAU,mCAAI,MAAM,CAAA;QAC9C,IAAI,CAAC,UAAU,GAAG,MAAA,OAAO,CAAC,UAAU,mCAAI,KAAK,CAAA;QAC7C,IAAI,CAAC,SAAS,GAAG,MAAA,OAAO,CAAC,SAAS,mCAAI,eAAe,CAAA;QACrD,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAA;QAClC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC5B,IAAI,CAAC,KAAK,GAAG,MAAA,OAAO,CAAC,KAAK,mCAAI,IAAI,CAAC,QAAQ,EAAE,CAAA;IAC/C,CAAC;IAED,QAAQ;;QACN,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;YAC5C,+DAA+D;YAC/D,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;SAC5C;QAED,MAAM,WAAW,GAAG,MAAA,IAAI,CAAC,SAAS,CAAC,OAAO,0CAAE,IAAI,CAAA;QAChD,MAAM,oBAAoB,GAAG,WAAW,IAAI,iCAAiC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QAE9F,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAC1B,IAAI,CAAC,SAAS,EACd;YACE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;gBACjB,IAAI,EAAE,IAAI,CAAC,UAAU;gBACrB,SAAS,EAAE,KAAK;gBAChB,MAAM,EAAE,IAAI;gBACZ,UAAU,EAAE,IAAI;gBAChB,aAAa,EAAE,KAAK;aACrB;SACF,EACD;YACE,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;YAClD,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS;SAC9D,CACgB,CAAA;IACrB,CAAC;IAES,KAAK,CAAC,SAAS;QACvB,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAC,IAAI,EAAE,aAAa,EAAiB;QACtD,MAAM,IAAI,CAAC,SAAS,EAAE,CAAA;QACtB,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YACtB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,aAAa;SACjC,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,EAAC,IAAI,EAAE,aAAa,EAAiB;QACxD,MAAM,IAAI,CAAC,SAAS,EAAE,CAAA;QACtB,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;YACvB,KAAK,EAAE;gBACL,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,aAAa;aACjC;SACF,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,IAAI,CAAC,SAAS,EAAE,CAAA;QACtB,MAAM,UAAU,GAAU,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,EAAC,CAAC,CAAA;QACvF,OAAO,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;YAChC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YACvC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;gBAC5B,MAAM,IAAI,SAAS,CAAC,wDAAwD,OAAO,IAAI,EAAE,CAAC,CAAA;aAC3F;YAED,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,mBAAmB;IACnB,MAAM;QACJ,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;CACF;AAnGD,4CAmGC"}

5
server/node_modules/umzug/lib/templates.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
export declare const js: string;
export declare const ts: string;
export declare const mjs: string;
export declare const sqlUp: string;
export declare const sqlDown: string;

32
server/node_modules/umzug/lib/templates.js generated vendored Normal file
View File

@@ -0,0 +1,32 @@
"use strict";
/* eslint-disable unicorn/template-indent */
// templates for migration file creation
Object.defineProperty(exports, "__esModule", { value: true });
exports.sqlDown = exports.sqlUp = exports.mjs = exports.ts = exports.js = void 0;
exports.js = `
/** @type {import('umzug').MigrationFn<any>} */
exports.up = async params => {};
/** @type {import('umzug').MigrationFn<any>} */
exports.down = async params => {};
`.trimStart();
exports.ts = `
import type { MigrationFn } from 'umzug';
export const up: MigrationFn = async params => {};
export const down: MigrationFn = async params => {};
`.trimStart();
exports.mjs = `
/** @type {import('umzug').MigrationFn<any>} */
export const up = async params => {};
/** @type {import('umzug').MigrationFn<any>} */
export const down = async params => {};
`.trimStart();
exports.sqlUp = `
-- up migration
`.trimStart();
exports.sqlDown = `
-- down migration
`.trimStart();
//# sourceMappingURL=templates.js.map

1
server/node_modules/umzug/lib/templates.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":";AAAA,4CAA4C;AAC5C,wCAAwC;;;AAE3B,QAAA,EAAE,GAAG;;;;;;CAMjB,CAAC,SAAS,EAAE,CAAA;AAEA,QAAA,EAAE,GAAG;;;;;CAKjB,CAAC,SAAS,EAAE,CAAA;AAEA,QAAA,GAAG,GAAG;;;;;;CAMlB,CAAC,SAAS,EAAE,CAAA;AAEA,QAAA,KAAK,GAAG;;CAEpB,CAAC,SAAS,EAAE,CAAA;AAEA,QAAA,OAAO,GAAG;;CAEtB,CAAC,SAAS,EAAE,CAAA"}

129
server/node_modules/umzug/lib/types.d.ts generated vendored Normal file
View File

@@ -0,0 +1,129 @@
import type * as typeFest from 'type-fest';
import type { UmzugStorage } from './storage';
/**
* Create a type that has mutually exclusive keys.
* Wrapper for @see `import('type-fest').MergeExclusive` that works for three types
*/
export type MergeExclusive<A, B, C> = typeFest.MergeExclusive<A, typeFest.MergeExclusive<B, C>>;
export type Promisable<T> = T | PromiseLike<T>;
export type LogFn = (message: Record<string, unknown>) => void;
/** Constructor options for the Umzug class */
export type UmzugOptions<Ctx extends {} = Record<string, unknown>> = {
/** The migrations that the Umzug instance should perform */
migrations: InputMigrations<Ctx>;
/** A logging function. Pass `console` to use stdout, or pass in your own logger. Pass `undefined` explicitly to disable logging. */
logger: Record<'info' | 'warn' | 'error' | 'debug', LogFn> | undefined;
/** The storage implementation. By default, `JSONStorage` will be used */
storage?: UmzugStorage<Ctx>;
/** An optional context object, which will be passed to each migration function, if defined */
context?: Ctx | (() => Promise<Ctx> | Ctx);
/** Options for file creation */
create?: {
/**
* A function for generating placeholder migration files. Specify to make sure files generated via CLI or using `.create` follow team conventions.
* Should return an array of [filepath, content] pairs. Usually, only one pair is needed, but to put `down` migrations in a separate
* file, more than one can be returned.
*/
template?: (filepath: string) => Promisable<Array<[string, string]>>;
/**
* The default folder that new migration files should be generated in. If this is not specified, the new migration file will be created
* in the same folder as the last existing migration. The value here can be overriden by passing `folder` when calling `create`.
*/
folder?: string;
};
};
/** Serializeable metadata for a migration. The structure returned by the external-facing `pending()` and `executed()` methods. */
export type MigrationMeta = {
/** Name - this is used as the migration unique identifier within storage */
name: string;
/** An optional filepath for the migration. Note: this may be undefined, since not all migrations correspond to files on the filesystem */
path?: string;
};
export type MigrationParams<T> = {
name: string;
path?: string;
context: T;
};
/** A callable function for applying or reverting a migration */
export type MigrationFn<T = unknown> = (params: MigrationParams<T>) => Promise<unknown>;
/**
* A runnable migration. Represents a migration object with an `up` function which can be called directly, with no arguments, and an optional `down` function to revert it.
*/
export type RunnableMigration<T> = {
/** The effect of applying the migration */
up: MigrationFn<T>;
/** The effect of reverting the migration */
down?: MigrationFn<T>;
} & MigrationMeta;
/** Glob instructions for migration files */
export type GlobInputMigrations<T> = {
/**
* A glob string for migration files. Can also be in the format `[path/to/migrations/*.js', {cwd: 'some/base/dir', ignore: '**ignoreme.js' }]`
* See https://npmjs.com/package/glob for more details on the glob format - this package is used internally.
*/
glob: string | [string, {
cwd?: string;
ignore?: string | string[];
}];
/** Will be supplied to every migration function. Can be a database client, for example */
/** A function which takes a migration name, path and context, and returns an object with `up` and `down` functions. */
resolve?: Resolver<T>;
};
/**
* Allowable inputs for migrations. Can be either glob instructions for migration files, a list of runnable migrations, or a
* function which receives a context and returns a list of migrations.
*/
export type InputMigrations<T> = GlobInputMigrations<T> | Array<RunnableMigration<T>> | ((context: T) => Promisable<InputMigrations<T>>);
/** A function which takes a migration name, path and context, and returns an object with `up` and `down` functions. */
export type Resolver<T> = (params: MigrationParams<T>) => RunnableMigration<T>;
export declare const RerunBehavior: {
/** Hard error if an up migration that has already been run, or a down migration that hasn't, is encountered */
readonly THROW: "THROW";
/** Silently skip up migrations that have already been run, or down migrations that haven't */
readonly SKIP: "SKIP";
/** Re-run up migrations that have already been run, or down migrations that haven't */
readonly ALLOW: "ALLOW";
};
export type RerunBehavior = keyof typeof RerunBehavior;
export type MigrateUpOptions = MergeExclusive<{
/** If specified, migrations up to and including this name will be run. Otherwise, all pending migrations will be run */
to?: string;
}, {
/** Only run this many migrations. If not specified, all pending migrations will be run */
step: number;
}, {
/** If specified, only the migrations with these names migrations will be run. An error will be thrown if any of the names are not found in the list of available migrations */
migrations: string[];
/** What to do if a migration that has already been run is explicitly specified. Default is `THROW`. */
rerun?: RerunBehavior;
}>;
export type MigrateDownOptions = MergeExclusive<{
/** If specified, migrations down to and including this name will be revert. Otherwise, only the last executed will be reverted */
to?: string | 0;
}, {
/** Revert this many migrations. If not specified, only the most recent migration will be reverted */
step: number;
}, {
/**
* If specified, only the migrations with these names migrations will be reverted. An error will be thrown if any of the names are not found in the list of executed migrations.
* Note, migrations will be run in the order specified.
*/
migrations: string[];
/** What to do if a migration that has not been run is explicitly specified. Default is `THROW`. */
rerun?: RerunBehavior;
}>;
/** Map of eventName -> eventData type, where the keys are the string events that are emitted by an umzug instances, and the values are the payload emitted with the corresponding event. */
export type UmzugEvents<Ctx> = {
migrating: MigrationParams<Ctx>;
migrated: MigrationParams<Ctx>;
reverting: MigrationParams<Ctx>;
reverted: MigrationParams<Ctx>;
beforeCommand: {
command: string;
context: Ctx;
};
afterCommand: {
command: string;
context: Ctx;
};
};

12
server/node_modules/umzug/lib/types.js generated vendored Normal file
View File

@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RerunBehavior = void 0;
exports.RerunBehavior = {
/** Hard error if an up migration that has already been run, or a down migration that hasn't, is encountered */
THROW: 'THROW',
/** Silently skip up migrations that have already been run, or down migrations that haven't */
SKIP: 'SKIP',
/** Re-run up migrations that have already been run, or down migrations that haven't */
ALLOW: 'ALLOW',
};
//# sourceMappingURL=types.js.map

1
server/node_modules/umzug/lib/types.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AA0Fa,QAAA,aAAa,GAAG;IAC3B,+GAA+G;IAC/G,KAAK,EAAE,OAAO;IACd,8FAA8F;IAC9F,IAAI,EAAE,MAAM;IACZ,uFAAuF;IACvF,KAAK,EAAE,OAAO;CACN,CAAA"}

105
server/node_modules/umzug/lib/umzug.d.ts generated vendored Normal file
View File

@@ -0,0 +1,105 @@
import emittery from 'emittery';
import * as errorCause from 'pony-cause';
import type { CommandLineParserOptions } from './cli';
import { UmzugCLI } from './cli';
import type { MigrateDownOptions, MigrateUpOptions, MigrationMeta, MigrationParams, Resolver, RunnableMigration, UmzugEvents, UmzugOptions } from './types';
type MigrationErrorParams = {
direction: 'up' | 'down';
} & MigrationParams<unknown>;
export declare class MigrationError extends errorCause.ErrorWithCause<unknown> {
name: string;
migration: MigrationErrorParams;
jse_cause: unknown;
constructor(migration: MigrationErrorParams, original: unknown);
get info(): MigrationErrorParams;
private static errorString;
}
export declare class Umzug<Ctx extends object = object> extends emittery<UmzugEvents<Ctx>> {
readonly options: UmzugOptions<Ctx>;
private readonly storage;
readonly migrations: (ctx: Ctx) => Promise<ReadonlyArray<RunnableMigration<Ctx>>>;
/**
* Compile-time only property for type inference. After creating an Umzug instance, it can be used as type alias for
* a user-defined migration. The function receives a migration name, path and the context for an umzug instance
* @example
* ```
* // migrator.ts
* import { Umzug } from 'umzug'
*
* const umzug = new Umzug({...})
* export type Migration = typeof umzug._types.migration;
*
* umzug.up();
* ```
* ___
*
* ```
* // migration-1.ts
* import type { Migration } from '../migrator'
*
* // name and context will now be strongly-typed
* export const up: Migration = ({name, context}) => context.query(...)
* export const down: Migration = ({name, context}) => context.query(...)
* ```
*/
readonly _types: {
migration: (params: MigrationParams<Ctx>) => Promise<unknown>;
context: Ctx;
};
/** creates a new Umzug instance */
constructor(options: UmzugOptions<Ctx>);
private logging;
static defaultResolver: Resolver<unknown>;
/**
* Get an UmzugCLI instance. This can be overriden in a subclass to add/remove commands - only use if you really know you need this,
* and are OK to learn about/interact with the API of @rushstack/ts-command-line.
*/
protected getCli(options?: CommandLineParserOptions): UmzugCLI;
/**
* 'Run' an umzug instance as a CLI. This will read `process.argv`, execute commands based on that, and call
* `process.exit` after running. If that isn't what you want, stick to the programmatic API.
* You probably want to run only if a file is executed as the process's 'main' module with something like:
* @example
* if (require.main === module) {
* myUmzugInstance.runAsCLI()
* }
*/
runAsCLI(argv?: string[]): Promise<boolean>;
/** Get the list of migrations which have already been applied */
executed(): Promise<MigrationMeta[]>;
/** Get the list of migrations which have already been applied */
private _executed;
/** Get the list of migrations which are yet to be applied */
pending(): Promise<MigrationMeta[]>;
private _pending;
protected runCommand<T>(command: string, cb: (commandParams: {
context: Ctx;
}) => Promise<T>): Promise<T>;
/**
* Apply migrations. By default, runs all pending migrations.
* @see MigrateUpOptions for other use cases using `to`, `migrations` and `rerun`.
*/
up(options?: MigrateUpOptions): Promise<MigrationMeta[]>;
/**
* Revert migrations. By default, the last executed migration is reverted.
* @see MigrateDownOptions for other use cases using `to`, `migrations` and `rerun`.
*/
down(options?: MigrateDownOptions): Promise<MigrationMeta[]>;
create(options: {
name: string;
folder?: string;
prefix?: 'TIMESTAMP' | 'DATE' | 'NONE';
allowExtension?: string;
allowConfusingOrdering?: boolean;
skipVerify?: boolean;
/** Optionally define the content for the new file. If not set, the configured template will be used. */
content?: string;
}): Promise<void>;
private static defaultCreationTemplate;
private findNameIndex;
private findMigrations;
private getContext;
/** helper for parsing input migrations into a callback returning a list of ready-to-run migrations */
private getMigrationsResolver;
}
export {};

412
server/node_modules/umzug/lib/umzug.js generated vendored Normal file
View File

@@ -0,0 +1,412 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Umzug = exports.MigrationError = void 0;
const emittery_1 = __importDefault(require("emittery"));
const fast_glob_1 = require("fast-glob");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const errorCause = __importStar(require("pony-cause"));
const cli_1 = require("./cli");
const storage_1 = require("./storage");
const templates = __importStar(require("./templates"));
const types_1 = require("./types");
class MigrationError extends errorCause.ErrorWithCause {
// TODO [>=4.0.0] Take a `{ cause: ... }` options bag like the default `Error`, it looks like this because of verror backwards-compatibility.
constructor(migration, original) {
super(`Migration ${migration.name} (${migration.direction}) failed: ${MigrationError.errorString(original)}`, {
cause: original,
});
this.name = 'MigrationError';
this.jse_cause = original;
this.migration = migration;
}
// TODO [>=4.0.0] Remove this backwards-compatibility alias
get info() {
return this.migration;
}
static errorString(cause) {
return cause instanceof Error
? `Original error: ${cause.message}`
: `Non-error value thrown. See info for full props: ${cause}`;
}
}
exports.MigrationError = MigrationError;
class Umzug extends emittery_1.default {
/** creates a new Umzug instance */
constructor(options) {
var _b;
super();
this.options = options;
this.storage = (0, storage_1.verifyUmzugStorage)((_b = options.storage) !== null && _b !== void 0 ? _b : new storage_1.JSONStorage());
this.migrations = this.getMigrationsResolver(this.options.migrations);
}
logging(message) {
var _b;
(_b = this.options.logger) === null || _b === void 0 ? void 0 : _b.info(message);
}
/**
* Get an UmzugCLI instance. This can be overriden in a subclass to add/remove commands - only use if you really know you need this,
* and are OK to learn about/interact with the API of @rushstack/ts-command-line.
*/
getCli(options) {
return new cli_1.UmzugCLI(this, options);
}
/**
* 'Run' an umzug instance as a CLI. This will read `process.argv`, execute commands based on that, and call
* `process.exit` after running. If that isn't what you want, stick to the programmatic API.
* You probably want to run only if a file is executed as the process's 'main' module with something like:
* @example
* if (require.main === module) {
* myUmzugInstance.runAsCLI()
* }
*/
async runAsCLI(argv) {
const cli = this.getCli();
return cli.execute(argv);
}
/** Get the list of migrations which have already been applied */
async executed() {
return this.runCommand('executed', async ({ context }) => {
const list = await this._executed(context);
// We do the following to not expose the `up` and `down` functions to the user
return list.map(m => ({ name: m.name, path: m.path }));
});
}
/** Get the list of migrations which have already been applied */
async _executed(context) {
const [migrations, executedNames] = await Promise.all([this.migrations(context), this.storage.executed({ context })]);
const executedSet = new Set(executedNames);
return migrations.filter(m => executedSet.has(m.name));
}
/** Get the list of migrations which are yet to be applied */
async pending() {
return this.runCommand('pending', async ({ context }) => {
const list = await this._pending(context);
// We do the following to not expose the `up` and `down` functions to the user
return list.map(m => ({ name: m.name, path: m.path }));
});
}
async _pending(context) {
const [migrations, executedNames] = await Promise.all([this.migrations(context), this.storage.executed({ context })]);
const executedSet = new Set(executedNames);
return migrations.filter(m => !executedSet.has(m.name));
}
async runCommand(command, cb) {
const context = await this.getContext();
await this.emit('beforeCommand', { command, context });
try {
return await cb({ context });
}
finally {
await this.emit('afterCommand', { command, context });
}
}
/**
* Apply migrations. By default, runs all pending migrations.
* @see MigrateUpOptions for other use cases using `to`, `migrations` and `rerun`.
*/
async up(options = {}) {
const eligibleMigrations = async (context) => {
var _b;
if (options.migrations && options.rerun === types_1.RerunBehavior.ALLOW) {
// Allow rerun means the specified migrations should be run even if they've run before - so get all migrations, not just pending
const list = await this.migrations(context);
return this.findMigrations(list, options.migrations);
}
if (options.migrations && options.rerun === types_1.RerunBehavior.SKIP) {
const executedNames = new Set((await this._executed(context)).map(m => m.name));
const filteredMigrations = options.migrations.filter(m => !executedNames.has(m));
return this.findMigrations(await this.migrations(context), filteredMigrations);
}
if (options.migrations) {
return this.findMigrations(await this._pending(context), options.migrations);
}
const allPending = await this._pending(context);
let sliceIndex = (_b = options.step) !== null && _b !== void 0 ? _b : allPending.length;
if (options.to) {
sliceIndex = this.findNameIndex(allPending, options.to) + 1;
}
return allPending.slice(0, sliceIndex);
};
return this.runCommand('up', async ({ context }) => {
const toBeApplied = await eligibleMigrations(context);
for (const m of toBeApplied) {
const start = Date.now();
const params = { name: m.name, path: m.path, context };
this.logging({ event: 'migrating', name: m.name });
await this.emit('migrating', params);
try {
await m.up(params);
}
catch (e) {
throw new MigrationError({ direction: 'up', ...params }, e);
}
await this.storage.logMigration(params);
const duration = (Date.now() - start) / 1000;
this.logging({ event: 'migrated', name: m.name, durationSeconds: duration });
await this.emit('migrated', params);
}
return toBeApplied.map(m => ({ name: m.name, path: m.path }));
});
}
/**
* Revert migrations. By default, the last executed migration is reverted.
* @see MigrateDownOptions for other use cases using `to`, `migrations` and `rerun`.
*/
async down(options = {}) {
const eligibleMigrations = async (context) => {
var _b;
if (options.migrations && options.rerun === types_1.RerunBehavior.ALLOW) {
const list = await this.migrations(context);
return this.findMigrations(list, options.migrations);
}
if (options.migrations && options.rerun === types_1.RerunBehavior.SKIP) {
const pendingNames = new Set((await this._pending(context)).map(m => m.name));
const filteredMigrations = options.migrations.filter(m => !pendingNames.has(m));
return this.findMigrations(await this.migrations(context), filteredMigrations);
}
if (options.migrations) {
return this.findMigrations(await this._executed(context), options.migrations);
}
const executedReversed = (await this._executed(context)).slice().reverse();
let sliceIndex = (_b = options.step) !== null && _b !== void 0 ? _b : 1;
if (options.to === 0 || options.migrations) {
sliceIndex = executedReversed.length;
}
else if (options.to) {
sliceIndex = this.findNameIndex(executedReversed, options.to) + 1;
}
return executedReversed.slice(0, sliceIndex);
};
return this.runCommand('down', async ({ context }) => {
var _b;
const toBeReverted = await eligibleMigrations(context);
for (const m of toBeReverted) {
const start = Date.now();
const params = { name: m.name, path: m.path, context };
this.logging({ event: 'reverting', name: m.name });
await this.emit('reverting', params);
try {
await ((_b = m.down) === null || _b === void 0 ? void 0 : _b.call(m, params));
}
catch (e) {
throw new MigrationError({ direction: 'down', ...params }, e);
}
await this.storage.unlogMigration(params);
const duration = Number.parseFloat(((Date.now() - start) / 1000).toFixed(3));
this.logging({ event: 'reverted', name: m.name, durationSeconds: duration });
await this.emit('reverted', params);
}
return toBeReverted.map(m => ({ name: m.name, path: m.path }));
});
}
async create(options) {
await this.runCommand('create', async ({ context }) => {
var _b, _c, _d, _e;
const isoDate = new Date().toISOString();
const prefixes = {
TIMESTAMP: isoDate.replace(/\.\d{3}Z$/, '').replace(/\W/g, '.'),
DATE: isoDate.split('T')[0].replace(/\W/g, '.'),
NONE: '',
};
const prefixType = (_b = options.prefix) !== null && _b !== void 0 ? _b : 'TIMESTAMP';
const fileBasename = [prefixes[prefixType], options.name].filter(Boolean).join('.');
const allowedExtensions = options.allowExtension
? [options.allowExtension]
: ['.js', '.cjs', '.mjs', '.ts', '.cts', '.mts', '.sql'];
const existing = await this.migrations(context);
const last = existing.slice(-1)[0];
const folder = options.folder || ((_c = this.options.create) === null || _c === void 0 ? void 0 : _c.folder) || ((last === null || last === void 0 ? void 0 : last.path) && path.dirname(last.path));
if (!folder) {
throw new Error(`Couldn't infer a directory to generate migration file in. Pass folder explicitly`);
}
const filepath = path.join(folder, fileBasename);
if (!options.allowConfusingOrdering) {
const confusinglyOrdered = existing.find(e => e.path && e.path >= filepath);
if (confusinglyOrdered) {
throw new Error(`Can't create ${fileBasename}, since it's unclear if it should run before or after existing migration ${confusinglyOrdered.name}. Use allowConfusingOrdering to bypass this error.`);
}
}
const template = typeof options.content === 'string'
? async () => [[filepath, options.content]]
: // eslint-disable-next-line @typescript-eslint/unbound-method
(_e = (_d = this.options.create) === null || _d === void 0 ? void 0 : _d.template) !== null && _e !== void 0 ? _e : Umzug.defaultCreationTemplate;
const toWrite = await template(filepath);
if (toWrite.length === 0) {
toWrite.push([filepath, '']);
}
toWrite.forEach(pair => {
if (!Array.isArray(pair) || pair.length !== 2) {
throw new Error(`Expected [filepath, content] pair. Check that the file template function returns an array of pairs.`);
}
const ext = path.extname(pair[0]);
if (!allowedExtensions.includes(ext)) {
const allowStr = allowedExtensions.join(', ');
const message = `Extension ${ext} not allowed. Allowed extensions are ${allowStr}. See help for allowExtension to avoid this error.`;
throw new Error(message);
}
fs.mkdirSync(path.dirname(pair[0]), { recursive: true });
fs.writeFileSync(pair[0], pair[1]);
this.logging({ event: 'created', path: pair[0] });
});
if (!options.skipVerify) {
const [firstFilePath] = toWrite[0];
const pending = await this._pending(context);
if (!pending.some(p => p.path && path.resolve(p.path) === path.resolve(firstFilePath))) {
const paths = pending.map(p => p.path).join(', ');
throw new Error(`Expected ${firstFilePath} to be a pending migration but it wasn't! Pending migration paths: ${paths}. You should investigate this. Use skipVerify to bypass this error.`);
}
}
});
}
static defaultCreationTemplate(filepath) {
const ext = path.extname(filepath);
if ((ext === '.js' && typeof require.main === 'object') || ext === '.cjs') {
return [[filepath, templates.js]];
}
if (ext === '.ts' || ext === '.mts' || ext === '.cts') {
return [[filepath, templates.ts]];
}
if ((ext === '.js' && require.main === undefined) || ext === '.mjs') {
return [[filepath, templates.mjs]];
}
if (ext === '.sql') {
const downFilepath = path.join(path.dirname(filepath), 'down', path.basename(filepath));
return [
[filepath, templates.sqlUp],
[downFilepath, templates.sqlDown],
];
}
return [];
}
findNameIndex(migrations, name) {
const index = migrations.findIndex(m => m.name === name);
if (index === -1) {
throw new Error(`Couldn't find migration to apply with name ${JSON.stringify(name)}`);
}
return index;
}
findMigrations(migrations, names) {
const map = new Map(migrations.map(m => [m.name, m]));
return names.map(name => {
const migration = map.get(name);
if (!migration) {
throw new Error(`Couldn't find migration to apply with name ${JSON.stringify(name)}`);
}
return migration;
});
}
async getContext() {
const { context = {} } = this.options;
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return typeof context === 'function' ? context() : context;
}
/** helper for parsing input migrations into a callback returning a list of ready-to-run migrations */
getMigrationsResolver(inputMigrations) {
var _b;
if (Array.isArray(inputMigrations)) {
return async () => inputMigrations;
}
if (typeof inputMigrations === 'function') {
// Lazy migrations definition, recurse.
return async (ctx) => {
const resolved = await inputMigrations(ctx);
return this.getMigrationsResolver(resolved)(ctx);
};
}
const fileGlob = inputMigrations.glob;
const [globString, globOptions] = Array.isArray(fileGlob) ? fileGlob : [fileGlob];
const ignore = typeof (globOptions === null || globOptions === void 0 ? void 0 : globOptions.ignore) === 'string' ? [globOptions.ignore] : globOptions === null || globOptions === void 0 ? void 0 : globOptions.ignore;
const resolver = (_b = inputMigrations.resolve) !== null && _b !== void 0 ? _b : Umzug.defaultResolver;
return async (context) => {
const paths = await (0, fast_glob_1.glob)(globString, { ...globOptions, ignore, absolute: true });
paths.sort(); // glob returns results in reverse alphabetical order these days, but it has never guaranteed not to do that https://github.com/isaacs/node-glob/issues/570
return paths.map(unresolvedPath => {
const filepath = path.resolve(unresolvedPath);
const name = path.basename(filepath);
return {
path: filepath,
...resolver({ name, path: filepath, context }),
};
});
};
}
}
exports.Umzug = Umzug;
_a = Umzug;
Umzug.defaultResolver = ({ name, path: filepath }) => {
if (!filepath) {
throw new Error(`Can't use default resolver for non-filesystem migrations`);
}
const ext = path.extname(filepath);
const languageSpecificHelp = {
'.ts': "TypeScript files can be required by adding `ts-node` as a dependency and calling `require('ts-node/register')` at the program entrypoint before running migrations.",
'.sql': 'Try writing a resolver which reads file content and executes it as a sql query.',
};
languageSpecificHelp['.cts'] = languageSpecificHelp['.ts'];
languageSpecificHelp['.mts'] = languageSpecificHelp['.ts'];
let loadModule;
const jsExt = ext.replace(/\.([cm]?)ts$/, '.$1js');
const getModule = async () => {
try {
return await loadModule();
}
catch (e) {
if ((e instanceof SyntaxError || e instanceof MissingResolverError) && ext in languageSpecificHelp) {
e.message += '\n\n' + languageSpecificHelp[ext];
}
throw e;
}
};
if ((jsExt === '.js' && typeof require.main === 'object') || jsExt === '.cjs') {
// eslint-disable-next-line @typescript-eslint/no-var-requires
loadModule = async () => require(filepath);
}
else if (jsExt === '.js' || jsExt === '.mjs') {
loadModule = async () => import(filepath);
}
else {
loadModule = async () => {
throw new MissingResolverError(filepath);
};
}
return {
name,
path: filepath,
up: async ({ context }) => (await getModule()).up({ path: filepath, name, context }),
down: async ({ context }) => { var _b, _c; return (_c = (_b = (await getModule())).down) === null || _c === void 0 ? void 0 : _c.call(_b, { path: filepath, name, context }); },
};
};
class MissingResolverError extends Error {
constructor(filepath) {
super(`No resolver specified for file ${filepath}. See docs for guidance on how to write a custom resolver.`);
}
}
//# sourceMappingURL=umzug.js.map

1
server/node_modules/umzug/lib/umzug.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,178 @@
// Basic
export * from './source/primitive';
export * from './source/typed-array';
export * from './source/basic';
export * from './source/observable-like';
// Utilities
export type {KeysOfUnion} from './source/keys-of-union';
export type {DistributedOmit} from './source/distributed-omit';
export type {DistributedPick} from './source/distributed-pick';
export type {EmptyObject, IsEmptyObject} from './source/empty-object';
export type {IfEmptyObject} from './source/if-empty-object';
export type {NonEmptyObject} from './source/non-empty-object';
export type {NonEmptyString} from './source/non-empty-string';
export type {UnknownRecord} from './source/unknown-record';
export type {UnknownArray} from './source/unknown-array';
export type {UnknownSet} from './source/unknown-set';
export type {UnknownMap} from './source/unknown-map';
export type {Except} from './source/except';
export type {TaggedUnion} from './source/tagged-union';
export type {Writable} from './source/writable';
export type {WritableDeep} from './source/writable-deep';
export type {Merge} from './source/merge';
export type {MergeDeep, MergeDeepOptions} from './source/merge-deep';
export type {MergeExclusive} from './source/merge-exclusive';
export type {RequireAtLeastOne} from './source/require-at-least-one';
export type {RequireExactlyOne} from './source/require-exactly-one';
export type {RequireAllOrNone} from './source/require-all-or-none';
export type {RequireOneOrNone} from './source/require-one-or-none';
export type {SingleKeyObject} from './source/single-key-object';
export type {OmitIndexSignature} from './source/omit-index-signature';
export type {PickIndexSignature} from './source/pick-index-signature';
export type {PartialDeep, PartialDeepOptions} from './source/partial-deep';
export type {RequiredDeep} from './source/required-deep';
export type {PickDeep} from './source/pick-deep';
export type {OmitDeep} from './source/omit-deep';
export type {PartialOnUndefinedDeep, PartialOnUndefinedDeepOptions} from './source/partial-on-undefined-deep';
export type {UndefinedOnPartialDeep} from './source/undefined-on-partial-deep';
export type {ReadonlyDeep} from './source/readonly-deep';
export type {LiteralUnion} from './source/literal-union';
export type {Promisable} from './source/promisable';
export type {Arrayable} from './source/arrayable';
export type {Opaque, UnwrapOpaque, Tagged, GetTagMetadata, UnwrapTagged} from './source/tagged';
export type {InvariantOf} from './source/invariant-of';
export type {SetOptional} from './source/set-optional';
export type {SetReadonly} from './source/set-readonly';
export type {SetRequired} from './source/set-required';
export type {SetRequiredDeep} from './source/set-required-deep';
export type {SetNonNullable} from './source/set-non-nullable';
export type {SetNonNullableDeep} from './source/set-non-nullable-deep';
export type {ValueOf} from './source/value-of';
export type {AsyncReturnType} from './source/async-return-type';
export type {ConditionalExcept} from './source/conditional-except';
export type {ConditionalKeys} from './source/conditional-keys';
export type {ConditionalPick} from './source/conditional-pick';
export type {ConditionalPickDeep, ConditionalPickDeepOptions} from './source/conditional-pick-deep';
export type {UnionToIntersection} from './source/union-to-intersection';
export type {Stringified} from './source/stringified';
export type {StringSlice} from './source/string-slice';
export type {FixedLengthArray} from './source/fixed-length-array';
export type {MultidimensionalArray} from './source/multidimensional-array';
export type {MultidimensionalReadonlyArray} from './source/multidimensional-readonly-array';
export type {IterableElement} from './source/iterable-element';
export type {Entry} from './source/entry';
export type {Entries} from './source/entries';
export type {SetReturnType} from './source/set-return-type';
export type {SetParameterType} from './source/set-parameter-type';
export type {Asyncify} from './source/asyncify';
export type {Simplify} from './source/simplify';
export type {SimplifyDeep} from './source/simplify-deep';
export type {Jsonify} from './source/jsonify';
export type {Jsonifiable} from './source/jsonifiable';
export type {StructuredCloneable} from './source/structured-cloneable';
export type {Schema, SchemaOptions} from './source/schema';
export type {LiteralToPrimitive} from './source/literal-to-primitive';
export type {LiteralToPrimitiveDeep} from './source/literal-to-primitive-deep';
export type {
PositiveInfinity,
NegativeInfinity,
Finite,
Integer,
Float,
NegativeFloat,
Negative,
NonNegative,
NegativeInteger,
NonNegativeInteger,
IsNegative,
} from './source/numeric';
export type {GreaterThan} from './source/greater-than';
export type {GreaterThanOrEqual} from './source/greater-than-or-equal';
export type {LessThan} from './source/less-than';
export type {LessThanOrEqual} from './source/less-than-or-equal';
export type {Sum} from './source/sum';
export type {Subtract} from './source/subtract';
export type {StringKeyOf} from './source/string-key-of';
export type {Exact} from './source/exact';
export type {ReadonlyTuple} from './source/readonly-tuple';
export type {OptionalKeysOf} from './source/optional-keys-of';
export type {OverrideProperties} from './source/override-properties';
export type {HasOptionalKeys} from './source/has-optional-keys';
export type {RequiredKeysOf} from './source/required-keys-of';
export type {HasRequiredKeys} from './source/has-required-keys';
export type {ReadonlyKeysOf} from './source/readonly-keys-of';
export type {HasReadonlyKeys} from './source/has-readonly-keys';
export type {WritableKeysOf} from './source/writable-keys-of';
export type {HasWritableKeys} from './source/has-writable-keys';
export type {Spread} from './source/spread';
export type {IsInteger} from './source/is-integer';
export type {IsFloat} from './source/is-float';
export type {TupleToObject} from './source/tuple-to-object';
export type {TupleToUnion} from './source/tuple-to-union';
export type {UnionToTuple} from './source/union-to-tuple';
export type {IntRange} from './source/int-range';
export type {IntClosedRange} from './source/int-closed-range';
export type {IsEqual} from './source/is-equal';
export type {
IsLiteral,
IsStringLiteral,
IsNumericLiteral,
IsBooleanLiteral,
IsSymbolLiteral,
} from './source/is-literal';
export type {IsAny} from './source/is-any';
export type {IfAny} from './source/if-any';
export type {IsNever} from './source/is-never';
export type {IfNever} from './source/if-never';
export type {IsUnknown} from './source/is-unknown';
export type {IfUnknown} from './source/if-unknown';
export type {IsTuple} from './source/is-tuple';
export type {ArrayIndices} from './source/array-indices';
export type {ArrayValues} from './source/array-values';
export type {ArraySlice} from './source/array-slice';
export type {ArraySplice} from './source/array-splice';
export type {ArrayTail} from './source/array-tail';
export type {SetFieldType} from './source/set-field-type';
export type {Paths} from './source/paths';
export type {AllUnionFields} from './source/all-union-fields';
export type {SharedUnionFields} from './source/shared-union-fields';
export type {SharedUnionFieldsDeep} from './source/shared-union-fields-deep';
export type {IsNull} from './source/is-null';
export type {IfNull} from './source/if-null';
export type {And} from './source/and';
export type {Or} from './source/or';
export type {NonEmptyTuple} from './source/non-empty-tuple';
export type {FindGlobalInstanceType, FindGlobalType} from './source/find-global-type';
// Template literal types
export type {CamelCase} from './source/camel-case';
export type {CamelCasedProperties} from './source/camel-cased-properties';
export type {CamelCasedPropertiesDeep} from './source/camel-cased-properties-deep';
export type {KebabCase} from './source/kebab-case';
export type {KebabCasedProperties} from './source/kebab-cased-properties';
export type {KebabCasedPropertiesDeep} from './source/kebab-cased-properties-deep';
export type {PascalCase} from './source/pascal-case';
export type {PascalCasedProperties} from './source/pascal-cased-properties';
export type {PascalCasedPropertiesDeep} from './source/pascal-cased-properties-deep';
export type {SnakeCase} from './source/snake-case';
export type {SnakeCasedProperties} from './source/snake-cased-properties';
export type {SnakeCasedPropertiesDeep} from './source/snake-cased-properties-deep';
export type {ScreamingSnakeCase} from './source/screaming-snake-case';
export type {DelimiterCase} from './source/delimiter-case';
export type {DelimiterCasedProperties} from './source/delimiter-cased-properties';
export type {DelimiterCasedPropertiesDeep} from './source/delimiter-cased-properties-deep';
export type {Join} from './source/join';
export type {Split} from './source/split';
export type {Words} from './source/words';
export type {Trim} from './source/trim';
export type {Replace} from './source/replace';
export type {StringRepeat} from './source/string-repeat';
export type {Includes} from './source/includes';
export type {Get} from './source/get';
export type {LastArrayElement} from './source/last-array-element';
// Miscellaneous
export type {GlobalThis} from './source/global-this';
export type {PackageJson} from './source/package-json';
export type {TsConfigJson} from './source/tsconfig-json';

View File

@@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,91 @@
{
"name": "type-fest",
"version": "4.41.0",
"description": "A collection of essential TypeScript types",
"license": "(MIT OR CC0-1.0)",
"repository": "sindresorhus/type-fest",
"funding": "https://github.com/sponsors/sindresorhus",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com"
},
"types": "./index.d.ts",
"sideEffects": false,
"engines": {
"node": ">=16"
},
"scripts": {
"test:source-files-extension": "node script/test/source-files-extension.js",
"test:tsc": "tsc",
"test:tsd": "tsd",
"test:xo": "xo",
"test": "run-p test:*"
},
"files": [
"index.d.ts",
"source",
"license-mit",
"license-cc0"
],
"keywords": [
"typescript",
"ts",
"types",
"utility",
"util",
"utilities",
"omit",
"merge",
"json",
"generics"
],
"devDependencies": {
"expect-type": "^1.1.0",
"npm-run-all2": "^7.0.1",
"tsd": "^0.32.0",
"typescript": "~5.8.3",
"xo": "^0.60.0"
},
"xo": {
"rules": {
"@typescript-eslint/no-extraneous-class": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/naming-convention": "off",
"import/extensions": "off",
"@typescript-eslint/no-redeclare": "off",
"@typescript-eslint/no-confusing-void-expression": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"n/file-extension-in-import": "off",
"object-curly-newline": [
"error",
{
"multiline": true,
"consistent": true
}
],
"import/consistent-type-specifier-style": [
"error",
"prefer-top-level"
]
},
"overrides": [
{
"files": "**/*.d.ts",
"rules": {
"no-restricted-imports": [
"error",
"tsd",
"expect-type"
]
}
}
]
},
"tsd": {
"compilerOptions": {
"noUnusedLocals": false
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
import type {NonRecursiveType, ReadonlyKeysOfUnion, ValueOfUnion} from './internal';
import type {KeysOfUnion} from './keys-of-union';
import type {SharedUnionFields} from './shared-union-fields';
import type {Simplify} from './simplify';
import type {UnknownArray} from './unknown-array';
/**
Create a type with all fields from a union of object types.
Use-cases:
- You want a safe object type where each key exists in the union object.
@example
```
import type {AllUnionFields} from 'type-fest';
type Cat = {
name: string;
type: 'cat';
catType: string;
};
type Dog = {
name: string;
type: 'dog';
dogType: string;
};
function displayPetInfo(petInfo: Cat | Dog) {
// typeof petInfo =>
// {
// name: string;
// type: 'cat';
// catType: string;
// } | {
// name: string;
// type: 'dog';
// dogType: string;
// }
console.log('name: ', petInfo.name);
console.log('type: ', petInfo.type);
// TypeScript complains about `catType` and `dogType` not existing on type `Cat | Dog`.
console.log('animal type: ', petInfo.catType ?? petInfo.dogType);
}
function displayPetInfo(petInfo: AllUnionFields<Cat | Dog>) {
// typeof petInfo =>
// {
// name: string;
// type: 'cat' | 'dog';
// catType?: string;
// dogType?: string;
// }
console.log('name: ', petInfo.name);
console.log('type: ', petInfo.type);
// No TypeScript error.
console.log('animal type: ', petInfo.catType ?? petInfo.dogType);
}
```
@see SharedUnionFields
@category Object
@category Union
*/
export type AllUnionFields<Union> =
Extract<Union, NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown> | UnknownArray> extends infer SkippedMembers
? Exclude<Union, SkippedMembers> extends infer RelevantMembers
?
| SkippedMembers
| Simplify<
// Include fields that are common in all union members
SharedUnionFields<RelevantMembers> &
// Include readonly fields present in any union member
{
readonly [P in ReadonlyKeysOfUnion<RelevantMembers>]?: ValueOfUnion<RelevantMembers, P & KeysOfUnion<RelevantMembers>>
} &
// Include remaining fields that are neither common nor readonly
{
[P in Exclude<KeysOfUnion<RelevantMembers>, ReadonlyKeysOfUnion<RelevantMembers> | keyof RelevantMembers>]?: ValueOfUnion<RelevantMembers, P>
}
>
: never
: never;

View File

@@ -0,0 +1,25 @@
import type {IsEqual} from './is-equal';
/**
Returns a boolean for whether two given types are both true.
Use-case: Constructing complex conditional types where multiple conditions must be satisfied.
@example
```
import type {And} from 'type-fest';
And<true, true>;
//=> true
And<true, false>;
//=> false
```
@see {@link Or}
*/
export type And<A extends boolean, B extends boolean> = [A, B][number] extends true
? true
: true extends [IsEqual<A, false>, IsEqual<B, false>][number]
? false
: never;

View File

@@ -0,0 +1,23 @@
/**
Provides valid indices for a constant array or tuple.
Use-case: This type is useful when working with constant arrays or tuples and you want to enforce type-safety for accessing elements by their indices.
@example
```
import type {ArrayIndices, ArrayValues} from 'type-fest';
const weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] as const;
type Weekday = ArrayIndices<typeof weekdays>;
type WeekdayName = ArrayValues<typeof weekdays>;
const getWeekdayName = (day: Weekday): WeekdayName => weekdays[day];
```
@see {@link ArrayValues}
@category Array
*/
export type ArrayIndices<Element extends readonly unknown[]> =
Exclude<Partial<Element>['length'], Element['length']>;

View File

@@ -0,0 +1,109 @@
import type {Sum} from './sum';
import type {LessThanOrEqual} from './less-than-or-equal';
import type {GreaterThanOrEqual} from './greater-than-or-equal';
import type {GreaterThan} from './greater-than';
import type {IsNegative} from './numeric';
import type {Not, TupleMin} from './internal';
import type {IsEqual} from './is-equal';
import type {And} from './and';
import type {ArraySplice} from './array-splice';
/**
Returns an array slice of a given range, just like `Array#slice()`.
@example
```
import type {ArraySlice} from 'type-fest';
type T0 = ArraySlice<[0, 1, 2, 3, 4]>;
//=> [0, 1, 2, 3, 4]
type T1 = ArraySlice<[0, 1, 2, 3, 4], 0, -1>;
//=> [0, 1, 2, 3]
type T2 = ArraySlice<[0, 1, 2, 3, 4], 1, -2>;
//=> [1, 2]
type T3 = ArraySlice<[0, 1, 2, 3, 4], -2, 4>;
//=> [3]
type T4 = ArraySlice<[0, 1, 2, 3, 4], -2, -1>;
//=> [3]
type T5 = ArraySlice<[0, 1, 2, 3, 4], 0, -999>;
//=> []
function arraySlice<
const Array_ extends readonly unknown[],
Start extends number = 0,
End extends number = Array_['length'],
>(array: Array_, start?: Start, end?: End) {
return array.slice(start, end) as ArraySlice<Array_, Start, End>;
}
const slice = arraySlice([1, '2', {a: 3}, [4, 5]], 0, -1);
typeof slice;
//=> [1, '2', { readonly a: 3; }]
slice[2].a;
//=> 3
// @ts-expect-error -- TS2493: Tuple type '[1, "2", {readonly a: 3}]' of length '3' has no element at index '3'.
slice[3];
```
@category Array
*/
export type ArraySlice<
Array_ extends readonly unknown[],
Start extends number = never,
End extends number = never,
> = Array_ extends unknown // To distributive type
? And<IsEqual<Start, never>, IsEqual<End, never>> extends true
? Array_
: number extends Array_['length']
? VariableLengthArraySliceHelper<Array_, Start, End>
: ArraySliceHelper<Array_, IsEqual<Start, never> extends true ? 0 : Start, IsEqual<End, never> extends true ? Array_['length'] : End>
: never; // Never happens
type VariableLengthArraySliceHelper<
Array_ extends readonly unknown[],
Start extends number,
End extends number,
> = And<Not<IsNegative<Start>>, IsEqual<End, never>> extends true
? ArraySplice<Array_, 0, Start>
: And<
And<Not<IsNegative<Start>>, Not<IsNegative<End>>>,
IsEqual<GreaterThan<End, Start>, true>
> extends true
? ArraySliceByPositiveIndex<Array_, Start, End>
: [];
type ArraySliceHelper<
Array_ extends readonly unknown[],
Start extends number = 0,
End extends number = Array_['length'],
TraversedElement extends Array<Array_[number]> = [],
Result extends Array<Array_[number]> = [],
ArrayLength extends number = Array_['length'],
PositiveS extends number = IsNegative<Start> extends true
? Sum<ArrayLength, Start> extends infer AddResult extends number
? number extends AddResult // (ArrayLength + Start) < 0
? 0
: GreaterThan<AddResult, 0> extends true ? AddResult : 0
: never
: Start,
PositiveE extends number = IsNegative<End> extends true ? Sum<ArrayLength, End> : End,
> = true extends [IsNegative<PositiveS>, LessThanOrEqual<PositiveE, PositiveS>, GreaterThanOrEqual<PositiveS, ArrayLength>][number]
? []
: ArraySliceByPositiveIndex<Array_, TupleMin<[PositiveS, ArrayLength]>, TupleMin<[PositiveE, ArrayLength]>>;
type ArraySliceByPositiveIndex<
Array_ extends readonly unknown[],
Start extends number,
End extends number,
Result extends Array<Array_[number]> = [],
> = Start extends End
? Result
: ArraySliceByPositiveIndex<Array_, Sum<Start, 1>, End, [...Result, Array_[Start]]>;

View File

@@ -0,0 +1,99 @@
import type {BuildTuple, StaticPartOfArray, VariablePartOfArray} from './internal';
import type {GreaterThanOrEqual} from './greater-than-or-equal';
import type {Subtract} from './subtract';
import type {UnknownArray} from './unknown-array';
/**
The implementation of `SplitArrayByIndex` for fixed length arrays.
*/
type SplitFixedArrayByIndex<T extends UnknownArray, SplitIndex extends number> =
SplitIndex extends 0
? [[], T]
: T extends readonly [...BuildTuple<SplitIndex>, ...infer V]
? T extends readonly [...infer U, ...V]
? [U, V]
: [never, never]
: [never, never];
/**
The implementation of `SplitArrayByIndex` for variable length arrays.
*/
type SplitVariableArrayByIndex<T extends UnknownArray,
SplitIndex extends number,
T1 = Subtract<SplitIndex, StaticPartOfArray<T>['length']>,
T2 = T1 extends number
? BuildTuple<GreaterThanOrEqual<T1, 0> extends true ? T1 : number, VariablePartOfArray<T>[number]>
: [],
> =
SplitIndex extends 0
? [[], T]
: GreaterThanOrEqual<StaticPartOfArray<T>['length'], SplitIndex> extends true
? [
SplitFixedArrayByIndex<StaticPartOfArray<T>, SplitIndex>[0],
[
...SplitFixedArrayByIndex<StaticPartOfArray<T>, SplitIndex>[1],
...VariablePartOfArray<T>,
],
]
: [
[
...StaticPartOfArray<T>,
...(T2 extends UnknownArray ? T2 : []),
],
VariablePartOfArray<T>,
];
/**
Split the given array `T` by the given `SplitIndex`.
@example
```
type A = SplitArrayByIndex<[1, 2, 3, 4], 2>;
// type A = [[1, 2], [3, 4]];
type B = SplitArrayByIndex<[1, 2, 3, 4], 0>;
// type B = [[], [1, 2, 3, 4]];
```
*/
type SplitArrayByIndex<T extends UnknownArray, SplitIndex extends number> =
SplitIndex extends 0
? [[], T]
: number extends T['length']
? SplitVariableArrayByIndex<T, SplitIndex>
: SplitFixedArrayByIndex<T, SplitIndex>;
/**
Creates a new array type by adding or removing elements at a specified index range in the original array.
Use-case: Replace or insert items in an array type.
Like [`Array#splice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) but for types.
@example
```
type SomeMonths0 = ['January', 'April', 'June'];
type Mouths0 = ArraySplice<SomeMonths0, 1, 0, ['Feb', 'March']>;
//=> type Mouths0 = ['January', 'Feb', 'March', 'April', 'June'];
type SomeMonths1 = ['January', 'April', 'June'];
type Mouths1 = ArraySplice<SomeMonths1, 1, 1>;
//=> type Mouths1 = ['January', 'June'];
type SomeMonths2 = ['January', 'Foo', 'April'];
type Mouths2 = ArraySplice<SomeMonths2, 1, 1, ['Feb', 'March']>;
//=> type Mouths2 = ['January', 'Feb', 'March', 'April'];
```
@category Array
*/
export type ArraySplice<
T extends UnknownArray,
Start extends number,
DeleteCount extends number,
Items extends UnknownArray = [],
> =
SplitArrayByIndex<T, Start> extends [infer U extends UnknownArray, infer V extends UnknownArray]
? SplitArrayByIndex<V, DeleteCount> extends [infer _Deleted extends UnknownArray, infer X extends UnknownArray]
? [...U, ...Items, ...X]
: never // Should never happen
: never; // Should never happen

View File

@@ -0,0 +1,76 @@
import type {ApplyDefaultOptions, IfArrayReadonly} from './internal';
import type {UnknownArray} from './unknown-array';
/**
@see {@link ArrayTail}
*/
type ArrayTailOptions = {
/**
Return a readonly array if the input array is readonly.
@default false
@example
```
import type {ArrayTail} from 'type-fest';
type Example1 = ArrayTail<readonly [string, number, boolean], {preserveReadonly: true}>;
//=> readonly [number, boolean]
type Example2 = ArrayTail<[string, number, boolean], {preserveReadonly: true}>;
//=> [number, boolean]
type Example3 = ArrayTail<readonly [string, number, boolean], {preserveReadonly: false}>;
//=> [number, boolean]
type Example4 = ArrayTail<[string, number, boolean], {preserveReadonly: false}>;
//=> [number, boolean]
```
*/
preserveReadonly?: boolean;
};
type DefaultArrayTailOptions = {
preserveReadonly: false;
};
/**
Extracts the type of an array or tuple minus the first element.
@example
```
import type {ArrayTail} from 'type-fest';
declare const curry: <Arguments extends unknown[], Return>(
function_: (...arguments_: Arguments) => Return,
...arguments_: ArrayTail<Arguments>
) => (...arguments_: ArrayTail<Arguments>) => Return;
const add = (a: number, b: number) => a + b;
const add3 = curry(add, 3);
add3(4);
//=> 7
```
@see {@link ArrayTailOptions}
@category Array
*/
export type ArrayTail<TArray extends UnknownArray, Options extends ArrayTailOptions = {}> =
ApplyDefaultOptions<ArrayTailOptions, DefaultArrayTailOptions, Options> extends infer ResolvedOptions extends Required<ArrayTailOptions>
? TArray extends UnknownArray // For distributing `TArray`
? _ArrayTail<TArray> extends infer Result
? ResolvedOptions['preserveReadonly'] extends true
? IfArrayReadonly<TArray, Readonly<Result>, Result>
: Result
: never // Should never happen
: never // Should never happen
: never; // Should never happen
type _ArrayTail<TArray extends UnknownArray> = TArray extends readonly [unknown?, ...infer Tail]
? keyof TArray & `${number}` extends never
? []
: Tail
: [];

View File

@@ -0,0 +1,22 @@
/**
Provides all values for a constant array or tuple.
Use-case: This type is useful when working with constant arrays or tuples and you want to enforce type-safety with their values.
@example
```
import type {ArrayValues, ArrayIndices} from 'type-fest';
const weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] as const;
type WeekdayName = ArrayValues<typeof weekdays>;
type Weekday = ArrayIndices<typeof weekdays>;
const getWeekdayName = (day: Weekday): WeekdayName => weekdays[day];
```
@see {@link ArrayIndices}
@category Array
*/
export type ArrayValues<T extends readonly unknown[]> = T[number];

View File

@@ -0,0 +1,29 @@
/**
Create a type that represents either the value or an array of the value.
@see Promisable
@example
```
import type {Arrayable} from 'type-fest';
function bundle(input: string, output: Arrayable<string>) {
const outputList = Array.isArray(output) ? output : [output];
// …
for (const output of outputList) {
console.log(`write to: ${output}`);
}
}
bundle('src/index.js', 'dist/index.js');
bundle('src/index.js', ['dist/index.cjs', 'dist/index.mjs']);
```
@category Array
*/
export type Arrayable<T> =
T
// TODO: Use `readonly T[]` when this issue is resolved: https://github.com/microsoft/TypeScript/issues/17002
| T[];

View File

@@ -0,0 +1,23 @@
type AsyncFunction = (...arguments_: any[]) => PromiseLike<unknown>;
/**
Unwrap the return type of a function that returns a `Promise`.
There has been [discussion](https://github.com/microsoft/TypeScript/pull/35998) about implementing this type in TypeScript.
@example
```ts
import type {AsyncReturnType} from 'type-fest';
import {asyncFunction} from 'api';
// This type resolves to the unwrapped return type of `asyncFunction`.
type Value = AsyncReturnType<typeof asyncFunction>;
async function doSomething(value: Value) {}
asyncFunction().then(value => doSomething(value));
```
@category Async
*/
export type AsyncReturnType<Target extends AsyncFunction> = Awaited<ReturnType<Target>>;

View File

@@ -0,0 +1,32 @@
import type {SetReturnType} from './set-return-type';
/**
Create an async version of the given function type, by boxing the return type in `Promise` while keeping the same parameter types.
Use-case: You have two functions, one synchronous and one asynchronous that do the same thing. Instead of having to duplicate the type definition, you can use `Asyncify` to reuse the synchronous type.
@example
```
import type {Asyncify} from 'type-fest';
// Synchronous function.
function getFooSync(someArg: SomeType): Foo {
// …
}
type AsyncifiedFooGetter = Asyncify<typeof getFooSync>;
//=> type AsyncifiedFooGetter = (someArg: SomeType) => Promise<Foo>;
// Same as `getFooSync` but asynchronous.
const getFooAsync: AsyncifiedFooGetter = (someArg) => {
// TypeScript now knows that `someArg` is `SomeType` automatically.
// It also knows that this function must return `Promise<Foo>`.
// If you have `@typescript-eslint/promise-function-async` linter rule enabled, it will even report that "Functions that return promises must be async.".
// …
}
```
@category Async
*/
export type Asyncify<Function_ extends (...arguments_: any[]) => any> = SetReturnType<Function_, Promise<Awaited<ReturnType<Function_>>>>;

View File

@@ -0,0 +1,68 @@
/**
Matches a [`class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes).
@category Class
*/
export type Class<T, Arguments extends unknown[] = any[]> = {
prototype: Pick<T, keyof T>;
new(...arguments_: Arguments): T;
};
/**
Matches a [`class` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes).
@category Class
*/
export type Constructor<T, Arguments extends unknown[] = any[]> = new(...arguments_: Arguments) => T;
/**
Matches an [`abstract class`](https://www.typescriptlang.org/docs/handbook/classes.html#abstract-classes).
@category Class
@privateRemarks
We cannot use a `type` here because TypeScript throws: 'abstract' modifier cannot appear on a type member. (1070)
*/
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export interface AbstractClass<T, Arguments extends unknown[] = any[]> extends AbstractConstructor<T, Arguments> {
prototype: Pick<T, keyof T>;
}
/**
Matches an [`abstract class`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-2.html#abstract-construct-signatures) constructor.
@category Class
*/
export type AbstractConstructor<T, Arguments extends unknown[] = any[]> = abstract new(...arguments_: Arguments) => T;
/**
Matches a JSON object.
This type can be useful to enforce some input to be JSON-compatible or as a super-type to be extended from. Don't use this as a direct return type as the user would have to double-cast it: `jsonObject as unknown as CustomResponse`. Instead, you could extend your CustomResponse type from it to ensure your type only uses JSON-compatible types: `interface CustomResponse extends JsonObject { … }`.
@category JSON
*/
export type JsonObject = {[Key in string]: JsonValue} & {[Key in string]?: JsonValue | undefined};
/**
Matches a JSON array.
@category JSON
*/
export type JsonArray = JsonValue[] | readonly JsonValue[];
/**
Matches any valid JSON primitive value.
@category JSON
*/
export type JsonPrimitive = string | number | boolean | null;
/**
Matches any valid JSON value.
@see `Jsonify` if you need to transform a type to one that is assignable to `JsonValue`.
@category JSON
*/
export type JsonValue = JsonPrimitive | JsonObject | JsonArray;

View File

@@ -0,0 +1,89 @@
import type {ApplyDefaultOptions} from './internal';
import type {Words} from './words';
/**
CamelCase options.
@see {@link CamelCase}
*/
export type CamelCaseOptions = {
/**
Whether to preserved consecutive uppercase letter.
@default true
*/
preserveConsecutiveUppercase?: boolean;
};
export type DefaultCamelCaseOptions = {
preserveConsecutiveUppercase: true;
};
/**
Convert an array of words to camel-case.
*/
type CamelCaseFromArray<
Words extends string[],
Options extends Required<CamelCaseOptions>,
OutputString extends string = '',
> = Words extends [
infer FirstWord extends string,
...infer RemainingWords extends string[],
]
? Options['preserveConsecutiveUppercase'] extends true
? `${Capitalize<FirstWord>}${CamelCaseFromArray<RemainingWords, Options>}`
: `${Capitalize<Lowercase<FirstWord>>}${CamelCaseFromArray<RemainingWords, Options>}`
: OutputString;
/**
Convert a string literal to camel-case.
This can be useful when, for example, converting some kebab-cased command-line flags or a snake-cased database result.
By default, consecutive uppercase letter are preserved. See {@link CamelCaseOptions.preserveConsecutiveUppercase preserveConsecutiveUppercase} option to change this behaviour.
@example
```
import type {CamelCase} from 'type-fest';
// Simple
const someVariable: CamelCase<'foo-bar'> = 'fooBar';
const preserveConsecutiveUppercase: CamelCase<'foo-BAR-baz', {preserveConsecutiveUppercase: true}> = 'fooBARBaz';
// Advanced
type CamelCasedProperties<T> = {
[K in keyof T as CamelCase<K>]: T[K]
};
interface RawOptions {
'dry-run': boolean;
'full_family_name': string;
foo: number;
BAR: string;
QUZ_QUX: number;
'OTHER-FIELD': boolean;
}
const dbResult: CamelCasedProperties<RawOptions> = {
dryRun: true,
fullFamilyName: 'bar.js',
foo: 123,
bar: 'foo',
quzQux: 6,
otherField: false
};
```
@category Change case
@category Template literal
*/
export type CamelCase<Type, Options extends CamelCaseOptions = {}> = Type extends string
? string extends Type
? Type
: Uncapitalize<CamelCaseFromArray<
Words<Type extends Uppercase<Type> ? Lowercase<Type> : Type>,
ApplyDefaultOptions<CamelCaseOptions, DefaultCamelCaseOptions, Options>
>>
: Type;

View File

@@ -0,0 +1,97 @@
import type {CamelCase, CamelCaseOptions, DefaultCamelCaseOptions} from './camel-case';
import type {ApplyDefaultOptions, NonRecursiveType} from './internal';
import type {UnknownArray} from './unknown-array';
/**
Convert object properties to camel case recursively.
This can be useful when, for example, converting some API types from a different style.
@see CamelCasedProperties
@see CamelCase
@example
```
import type {CamelCasedPropertiesDeep} from 'type-fest';
interface User {
UserId: number;
UserName: string;
}
interface UserWithFriends {
UserInfo: User;
UserFriends: User[];
}
const result: CamelCasedPropertiesDeep<UserWithFriends> = {
userInfo: {
userId: 1,
userName: 'Tom',
},
userFriends: [
{
userId: 2,
userName: 'Jerry',
},
{
userId: 3,
userName: 'Spike',
},
],
};
const preserveConsecutiveUppercase: CamelCasedPropertiesDeep<{fooBAR: { fooBARBiz: [{ fooBARBaz: string }] }}, {preserveConsecutiveUppercase: false}> = {
fooBar: {
fooBarBiz: [{
fooBarBaz: 'string',
}],
},
};
```
@category Change case
@category Template literal
@category Object
*/
export type CamelCasedPropertiesDeep<
Value,
Options extends CamelCaseOptions = {},
> = _CamelCasedPropertiesDeep<Value, ApplyDefaultOptions<CamelCaseOptions, DefaultCamelCaseOptions, Options>>;
type _CamelCasedPropertiesDeep<
Value,
Options extends Required<CamelCaseOptions>,
> = Value extends NonRecursiveType
? Value
: Value extends UnknownArray
? CamelCasedPropertiesArrayDeep<Value, Options>
: Value extends Set<infer U>
? Set<_CamelCasedPropertiesDeep<U, Options>>
: Value extends object
? {
[K in keyof Value as CamelCase<K, Options>]: _CamelCasedPropertiesDeep<Value[K], Options>;
}
: Value;
// This is a copy of DelimiterCasedPropertiesArrayDeep (see: delimiter-cased-properties-deep.d.ts).
// These types should be kept in sync.
type CamelCasedPropertiesArrayDeep<
Value extends UnknownArray,
Options extends Required<CamelCaseOptions>,
> = Value extends []
? []
// Trailing spread array
: Value extends [infer U, ...infer V]
? [_CamelCasedPropertiesDeep<U, Options>, ..._CamelCasedPropertiesDeep<V, Options>]
: Value extends readonly [infer U, ...infer V]
? readonly [_CamelCasedPropertiesDeep<U, Options>, ..._CamelCasedPropertiesDeep<V, Options>]
: // Leading spread array
Value extends readonly [...infer U, infer V]
? [..._CamelCasedPropertiesDeep<U, Options>, _CamelCasedPropertiesDeep<V, Options>]
: // Array
Value extends Array<infer U>
? Array<_CamelCasedPropertiesDeep<U, Options>>
: Value extends ReadonlyArray<infer U>
? ReadonlyArray<_CamelCasedPropertiesDeep<U, Options>>
: never;

View File

@@ -0,0 +1,43 @@
import type {CamelCase, CamelCaseOptions, DefaultCamelCaseOptions} from './camel-case';
import type {ApplyDefaultOptions} from './internal';
/**
Convert object properties to camel case but not recursively.
This can be useful when, for example, converting some API types from a different style.
@see CamelCasedPropertiesDeep
@see CamelCase
@example
```
import type {CamelCasedProperties} from 'type-fest';
interface User {
UserId: number;
UserName: string;
}
const result: CamelCasedProperties<User> = {
userId: 1,
userName: 'Tom',
};
const preserveConsecutiveUppercase: CamelCasedProperties<{fooBAR: string}, {preserveConsecutiveUppercase: false}> = {
fooBar: 'string',
};
```
@category Change case
@category Template literal
@category Object
*/
export type CamelCasedProperties<Value, Options extends CamelCaseOptions = {}> = Value extends Function
? Value
: Value extends Array<infer U>
? Value
: {
[K in keyof Value as
CamelCase<K, ApplyDefaultOptions<CamelCaseOptions, DefaultCamelCaseOptions, Options>>
]: Value[K];
};

View File

@@ -0,0 +1,45 @@
import type {Except} from './except';
import type {ConditionalKeys} from './conditional-keys';
/**
Exclude keys from a shape that matches the given `Condition`.
This is useful when you want to create a new type with a specific set of keys from a shape. For example, you might want to exclude all the primitive properties from a class and form a new shape containing everything but the primitive properties.
@example
```
import type {Primitive, ConditionalExcept} from 'type-fest';
class Awesome {
name: string;
successes: number;
failures: bigint;
run() {}
}
type ExceptPrimitivesFromAwesome = ConditionalExcept<Awesome, Primitive>;
//=> {run: () => void}
```
@example
```
import type {ConditionalExcept} from 'type-fest';
interface Example {
a: string;
b: string | number;
c: () => void;
d: {};
}
type NonStringKeysOnly = ConditionalExcept<Example, string>;
//=> {b: string | number; c: () => void; d: {}}
```
@category Object
*/
export type ConditionalExcept<Base, Condition> = Except<
Base,
ConditionalKeys<Base, Condition>
>;

View File

@@ -0,0 +1,47 @@
import type {IfNever} from './if-never';
/**
Extract the keys from a type where the value type of the key extends the given `Condition`.
Internally this is used for the `ConditionalPick` and `ConditionalExcept` types.
@example
```
import type {ConditionalKeys} from 'type-fest';
interface Example {
a: string;
b: string | number;
c?: string;
d: {};
}
type StringKeysOnly = ConditionalKeys<Example, string>;
//=> 'a'
```
To support partial types, make sure your `Condition` is a union of undefined (for example, `string | undefined`) as demonstrated below.
@example
```
import type {ConditionalKeys} from 'type-fest';
type StringKeysAndUndefined = ConditionalKeys<Example, string | undefined>;
//=> 'a' | 'c'
```
@category Object
*/
export type ConditionalKeys<Base, Condition> =
{
// Map through all the keys of the given base type.
[Key in keyof Base]-?:
// Pick only keys with types extending the given `Condition` type.
Base[Key] extends Condition
// Retain this key
// If the value for the key extends never, only include it if `Condition` also extends never
? IfNever<Base[Key], IfNever<Condition, Key, never>, Key>
// Discard this key since the condition fails.
: never;
// Convert the produced object into a union type of the keys which passed the conditional test.
}[keyof Base];

View File

@@ -0,0 +1,118 @@
import type {IsEqual} from './is-equal';
import type {ConditionalExcept} from './conditional-except';
import type {ConditionalSimplifyDeep} from './conditional-simplify';
import type {UnknownRecord} from './unknown-record';
import type {EmptyObject} from './empty-object';
import type {ApplyDefaultOptions, IsPlainObject} from './internal';
/**
Used to mark properties that should be excluded.
*/
declare const conditionalPickDeepSymbol: unique symbol;
/**
Assert the condition according to the {@link ConditionalPickDeepOptions.condition|condition} option.
*/
type AssertCondition<Type, Condition, Options extends ConditionalPickDeepOptions> = Options['condition'] extends 'equality'
? IsEqual<Type, Condition>
: Type extends Condition
? true
: false;
/**
ConditionalPickDeep options.
@see ConditionalPickDeep
*/
export type ConditionalPickDeepOptions = {
/**
The condition assertion mode.
@default 'extends'
*/
condition?: 'extends' | 'equality';
};
type DefaultConditionalPickDeepOptions = {
condition: 'extends';
};
/**
Pick keys recursively from the shape that matches the given condition.
@see ConditionalPick
@example
```
import type {ConditionalPickDeep} from 'type-fest';
interface Example {
a: string;
b: string | boolean;
c: {
d: string;
e: {
f?: string;
g?: boolean;
h: string | boolean;
i: boolean | bigint;
};
j: boolean;
};
}
type StringPick = ConditionalPickDeep<Example, string>;
//=> {a: string; c: {d: string}}
type StringPickOptional = ConditionalPickDeep<Example, string | undefined>;
//=> {a: string; c: {d: string; e: {f?: string}}}
type StringPickOptionalOnly = ConditionalPickDeep<Example, string | undefined, {condition: 'equality'}>;
//=> {c: {e: {f?: string}}}
type BooleanPick = ConditionalPickDeep<Example, boolean | undefined>;
//=> {c: {e: {g?: boolean}; j: boolean}}
type NumberPick = ConditionalPickDeep<Example, number>;
//=> {}
type StringOrBooleanPick = ConditionalPickDeep<Example, string | boolean>;
//=> {
// a: string;
// b: string | boolean;
// c: {
// d: string;
// e: {
// h: string | boolean
// };
// j: boolean;
// };
// }
type StringOrBooleanPickOnly = ConditionalPickDeep<Example, string | boolean, {condition: 'equality'}>;
//=> {b: string | boolean; c: {e: {h: string | boolean}}}
```
@category Object
*/
export type ConditionalPickDeep<
Type,
Condition,
Options extends ConditionalPickDeepOptions = {},
> = _ConditionalPickDeep<
Type,
Condition,
ApplyDefaultOptions<ConditionalPickDeepOptions, DefaultConditionalPickDeepOptions, Options>
>;
type _ConditionalPickDeep<
Type,
Condition,
Options extends Required<ConditionalPickDeepOptions>,
> = ConditionalSimplifyDeep<ConditionalExcept<{
[Key in keyof Type]: AssertCondition<Type[Key], Condition, Options> extends true
? Type[Key]
: IsPlainObject<Type[Key]> extends true
? _ConditionalPickDeep<Type[Key], Condition, Options>
: typeof conditionalPickDeepSymbol;
}, (typeof conditionalPickDeepSymbol | undefined) | EmptyObject>, never, UnknownRecord>;

View File

@@ -0,0 +1,44 @@
import type {ConditionalKeys} from './conditional-keys';
/**
Pick keys from the shape that matches the given `Condition`.
This is useful when you want to create a new type from a specific subset of an existing type. For example, you might want to pick all the primitive properties from a class and form a new automatically derived type.
@example
```
import type {Primitive, ConditionalPick} from 'type-fest';
class Awesome {
name: string;
successes: number;
failures: bigint;
run() {}
}
type PickPrimitivesFromAwesome = ConditionalPick<Awesome, Primitive>;
//=> {name: string; successes: number; failures: bigint}
```
@example
```
import type {ConditionalPick} from 'type-fest';
interface Example {
a: string;
b: string | number;
c: () => void;
d: {};
}
type StringKeysOnly = ConditionalPick<Example, string>;
//=> {a: string}
```
@category Object
*/
export type ConditionalPick<Base, Condition> = Pick<
Base,
ConditionalKeys<Base, Condition>
>;

View File

@@ -0,0 +1,32 @@
/**
Simplifies a type while including and/or excluding certain types from being simplified. Useful to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.
This type is **experimental** and was introduced as a result of this {@link https://github.com/sindresorhus/type-fest/issues/436 issue}. It should be used with caution.
@internal
@experimental
@see Simplify
@category Object
*/
export type ConditionalSimplify<Type, ExcludeType = never, IncludeType = unknown> = Type extends ExcludeType
? Type
: Type extends IncludeType
? {[TypeKey in keyof Type]: Type[TypeKey]}
: Type;
/**
Recursively simplifies a type while including and/or excluding certain types from being simplified.
This type is **experimental** and was introduced as a result of this {@link https://github.com/sindresorhus/type-fest/issues/436 issue}. It should be used with caution.
See {@link ConditionalSimplify} for usages and examples.
@internal
@experimental
@category Object
*/
export type ConditionalSimplifyDeep<Type, ExcludeType = never, IncludeType = unknown> = Type extends ExcludeType
? Type
: Type extends IncludeType
? {[TypeKey in keyof Type]: ConditionalSimplifyDeep<Type[TypeKey], ExcludeType, IncludeType>}
: Type;

View File

@@ -0,0 +1,78 @@
import type {ApplyDefaultOptions, AsciiPunctuation, StartsWith} from './internal';
import type {IsStringLiteral} from './is-literal';
import type {Merge} from './merge';
import type {DefaultWordsOptions, Words, WordsOptions} from './words';
export type DefaultDelimiterCaseOptions = Merge<DefaultWordsOptions, {splitOnNumbers: false}>;
/**
Convert an array of words to delimiter case starting with a delimiter with input capitalization.
*/
type DelimiterCaseFromArray<
Words extends string[],
Delimiter extends string,
OutputString extends string = '',
> = Words extends [
infer FirstWord extends string,
...infer RemainingWords extends string[],
]
? DelimiterCaseFromArray<RemainingWords, Delimiter, `${OutputString}${
StartsWith<FirstWord, AsciiPunctuation> extends true ? '' : Delimiter
}${FirstWord}`>
: OutputString;
type RemoveFirstLetter<S extends string> = S extends `${infer _}${infer Rest}`
? Rest
: '';
/**
Convert a string literal to a custom string delimiter casing.
This can be useful when, for example, converting a camel-cased object property to an oddly cased one.
@see KebabCase
@see SnakeCase
@example
```
import type {DelimiterCase} from 'type-fest';
// Simple
const someVariable: DelimiterCase<'fooBar', '#'> = 'foo#bar';
const someVariableNoSplitOnNumbers: DelimiterCase<'p2pNetwork', '#', {splitOnNumbers: false}> = 'p2p#network';
// Advanced
type OddlyCasedProperties<T> = {
[K in keyof T as DelimiterCase<K, '#'>]: T[K]
};
interface SomeOptions {
dryRun: boolean;
includeFile: string;
foo: number;
}
const rawCliOptions: OddlyCasedProperties<SomeOptions> = {
'dry#run': true,
'include#file': 'bar.js',
foo: 123
};
```
@category Change case
@category Template literal
*/
export type DelimiterCase<
Value,
Delimiter extends string,
Options extends WordsOptions = {},
> = Value extends string
? IsStringLiteral<Value> extends false
? Value
: Lowercase<RemoveFirstLetter<DelimiterCaseFromArray<
Words<Value, ApplyDefaultOptions<WordsOptions, DefaultDelimiterCaseOptions, Options>>,
Delimiter
>>>
: Value;

View File

@@ -0,0 +1,106 @@
import type {DefaultDelimiterCaseOptions, DelimiterCase} from './delimiter-case';
import type {ApplyDefaultOptions, NonRecursiveType} from './internal';
import type {UnknownArray} from './unknown-array';
import type {WordsOptions} from './words';
/**
Convert object properties to delimiter case recursively.
This can be useful when, for example, converting some API types from a different style.
@see DelimiterCase
@see DelimiterCasedProperties
@example
```
import type {DelimiterCasedPropertiesDeep} from 'type-fest';
interface User {
userId: number;
userName: string;
}
interface UserWithFriends {
userInfo: User;
userFriends: User[];
}
const result: DelimiterCasedPropertiesDeep<UserWithFriends, '-'> = {
'user-info': {
'user-id': 1,
'user-name': 'Tom',
},
'user-friends': [
{
'user-id': 2,
'user-name': 'Jerry',
},
{
'user-id': 3,
'user-name': 'Spike',
},
],
};
const splitOnNumbers: DelimiterCasedPropertiesDeep<{line1: { line2: [{ line3: string }] }}, '-', {splitOnNumbers: true}> = {
'line-1': {
'line-2': [
{
'line-3': 'string',
},
],
},
};
```
@category Change case
@category Template literal
@category Object
*/
export type DelimiterCasedPropertiesDeep<
Value,
Delimiter extends string,
Options extends WordsOptions = {},
> = _DelimiterCasedPropertiesDeep<Value, Delimiter, ApplyDefaultOptions<WordsOptions, DefaultDelimiterCaseOptions, Options>>;
type _DelimiterCasedPropertiesDeep<
Value,
Delimiter extends string,
Options extends Required<WordsOptions>,
> = Value extends NonRecursiveType
? Value
: Value extends UnknownArray
? DelimiterCasedPropertiesArrayDeep<Value, Delimiter, Options>
: Value extends Set<infer U>
? Set<_DelimiterCasedPropertiesDeep<U, Delimiter, Options>>
: Value extends object
? {
[K in keyof Value as DelimiterCase<K, Delimiter, Options>]:
_DelimiterCasedPropertiesDeep<Value[K], Delimiter, Options>
}
: Value;
// This is a copy of CamelCasedPropertiesArrayDeep (see: camel-cased-properties-deep.d.ts).
// These types should be kept in sync.
type DelimiterCasedPropertiesArrayDeep<
Value extends UnknownArray,
Delimiter extends string,
Options extends Required<WordsOptions>,
> = Value extends []
? []
// Trailing spread array
: Value extends [infer U, ...infer V]
? [_DelimiterCasedPropertiesDeep<U, Delimiter, Options>, ..._DelimiterCasedPropertiesDeep<V, Delimiter, Options>]
: Value extends readonly [infer U, ...infer V]
? readonly [_DelimiterCasedPropertiesDeep<U, Delimiter, Options>, ..._DelimiterCasedPropertiesDeep<V, Delimiter, Options>]
// Leading spread array
: Value extends [...infer U, infer V]
? [..._DelimiterCasedPropertiesDeep<U, Delimiter, Options>, _DelimiterCasedPropertiesDeep<V, Delimiter, Options>]
: Value extends readonly [...infer U, infer V]
? readonly [..._DelimiterCasedPropertiesDeep<U, Delimiter, Options>, _DelimiterCasedPropertiesDeep<V, Delimiter, Options>]
// Array
: Value extends Array<infer U>
? Array<_DelimiterCasedPropertiesDeep<U, Delimiter, Options>>
: Value extends ReadonlyArray<infer U>
? ReadonlyArray<_DelimiterCasedPropertiesDeep<U, Delimiter, Options>>
: never;

View File

@@ -0,0 +1,46 @@
import type {DefaultDelimiterCaseOptions, DelimiterCase} from './delimiter-case';
import type {ApplyDefaultOptions} from './internal';
import type {WordsOptions} from './words';
/**
Convert object properties to delimiter case but not recursively.
This can be useful when, for example, converting some API types from a different style.
@see DelimiterCase
@see DelimiterCasedPropertiesDeep
@example
```
import type {DelimiterCasedProperties} from 'type-fest';
interface User {
userId: number;
userName: string;
}
const result: DelimiterCasedProperties<User, '-'> = {
'user-id': 1,
'user-name': 'Tom',
};
const splitOnNumbers: DelimiterCasedProperties<{line1: string}, '-', {splitOnNumbers: true}> = {
'line-1': 'string',
};
```
@category Change case
@category Template literal
@category Object
*/
export type DelimiterCasedProperties<
Value,
Delimiter extends string,
Options extends WordsOptions = {},
> = Value extends Function
? Value
: Value extends Array<infer U>
? Value
: {[K in keyof Value as
DelimiterCase<K, Delimiter, ApplyDefaultOptions<WordsOptions, DefaultDelimiterCaseOptions, Options>>
]: Value[K]};

View File

@@ -0,0 +1,89 @@
import type {KeysOfUnion} from './keys-of-union';
/**
Omits keys from a type, distributing the operation over a union.
TypeScript's `Omit` doesn't distribute over unions, leading to the erasure of unique properties from union members when omitting keys. This creates a type that only retains properties common to all union members, making it impossible to access member-specific properties after the Omit. Essentially, using `Omit` on a union type merges the types into a less specific one, hindering type narrowing and property access based on discriminants. This type solves that.
Example:
```
type A = {
discriminant: 'A';
foo: string;
a: number;
};
type B = {
discriminant: 'B';
foo: string;
b: string;
};
type Union = A | B;
type OmittedUnion = Omit<Union, 'foo'>;
//=> {discriminant: 'A' | 'B'}
const omittedUnion: OmittedUnion = createOmittedUnion();
if (omittedUnion.discriminant === 'A') {
// We would like to narrow `omittedUnion`'s type
// to `A` here, but we can't because `Omit`
// doesn't distribute over unions.
omittedUnion.a;
//=> Error: `a` is not a property of `{discriminant: 'A' | 'B'}`
}
```
While `Except` solves this problem, it restricts the keys you can omit to the ones that are present in **ALL** union members, where `DistributedOmit` allows you to omit keys that are present in **ANY** union member.
@example
```
type A = {
discriminant: 'A';
foo: string;
a: number;
};
type B = {
discriminant: 'B';
foo: string;
bar: string;
b: string;
};
type C = {
discriminant: 'C';
bar: string;
c: boolean;
};
// Notice that `foo` exists in `A` and `B`, but not in `C`, and
// `bar` exists in `B` and `C`, but not in `A`.
type Union = A | B | C;
type OmittedUnion = DistributedOmit<Union, 'foo' | 'bar'>;
const omittedUnion: OmittedUnion = createOmittedUnion();
if (omittedUnion.discriminant === 'A') {
omittedUnion.a;
//=> OK
omittedUnion.foo;
//=> Error: `foo` is not a property of `{discriminant: 'A'; a: string}`
omittedUnion.bar;
//=> Error: `bar` is not a property of `{discriminant: 'A'; a: string}`
}
```
@category Object
*/
export type DistributedOmit<ObjectType, KeyType extends KeysOfUnion<ObjectType>> =
ObjectType extends unknown
? Omit<ObjectType, KeyType>
: never;

View File

@@ -0,0 +1,85 @@
import type {KeysOfUnion} from './keys-of-union';
/**
Pick keys from a type, distributing the operation over a union.
TypeScript's `Pick` doesn't distribute over unions, leading to the erasure of unique properties from union members when picking keys. This creates a type that only retains properties common to all union members, making it impossible to access member-specific properties after the Pick. Essentially, using `Pick` on a union type merges the types into a less specific one, hindering type narrowing and property access based on discriminants. This type solves that.
Example:
```
type A = {
discriminant: 'A';
foo: {
bar: string;
};
};
type B = {
discriminant: 'B';
foo: {
baz: string;
};
};
type Union = A | B;
type PickedUnion = Pick<Union, 'discriminant' | 'foo'>;
//=> {discriminant: 'A' | 'B', foo: {bar: string} | {baz: string}}
const pickedUnion: PickedUnion = createPickedUnion();
if (pickedUnion.discriminant === 'A') {
// We would like to narrow `pickedUnion`'s type
// to `A` here, but we can't because `Pick`
// doesn't distribute over unions.
pickedUnion.foo.bar;
//=> Error: Property 'bar' does not exist on type '{bar: string} | {baz: string}'.
}
```
@example
```
type A = {
discriminant: 'A';
foo: {
bar: string;
};
extraneous: boolean;
};
type B = {
discriminant: 'B';
foo: {
baz: string;
};
extraneous: boolean;
};
// Notice that `foo.bar` exists in `A` but not in `B`.
type Union = A | B;
type PickedUnion = DistributedPick<Union, 'discriminant' | 'foo'>;
const pickedUnion: PickedUnion = createPickedUnion();
if (pickedUnion.discriminant === 'A') {
pickedUnion.foo.bar;
//=> OK
pickedUnion.extraneous;
//=> Error: Property `extraneous` does not exist on type `Pick<A, 'discriminant' | 'foo'>`.
pickedUnion.foo.baz;
//=> Error: `bar` is not a property of `{discriminant: 'A'; a: string}`.
}
```
@category Object
*/
export type DistributedPick<ObjectType, KeyType extends KeysOfUnion<ObjectType>> =
ObjectType extends unknown
? Pick<ObjectType, Extract<KeyType, keyof ObjectType>>
: never;

View File

@@ -0,0 +1,46 @@
declare const emptyObjectSymbol: unique symbol;
/**
Represents a strictly empty plain object, the `{}` value.
When you annotate something as the type `{}`, it can be anything except `null` and `undefined`. This means that you cannot use `{}` to represent an empty plain object ([read more](https://stackoverflow.com/questions/47339869/typescript-empty-object-and-any-difference/52193484#52193484)).
@example
```
import type {EmptyObject} from 'type-fest';
// The following illustrates the problem with `{}`.
const foo1: {} = {}; // Pass
const foo2: {} = []; // Pass
const foo3: {} = 42; // Pass
const foo4: {} = {a: 1}; // Pass
// With `EmptyObject` only the first case is valid.
const bar1: EmptyObject = {}; // Pass
const bar2: EmptyObject = 42; // Fail
const bar3: EmptyObject = []; // Fail
const bar4: EmptyObject = {a: 1}; // Fail
```
Unfortunately, `Record<string, never>`, `Record<keyof any, never>` and `Record<never, never>` do not work. See {@link https://github.com/sindresorhus/type-fest/issues/395 #395}.
@category Object
*/
export type EmptyObject = {[emptyObjectSymbol]?: never};
/**
Returns a `boolean` for whether the type is strictly equal to an empty plain object, the `{}` value.
@example
```
import type {IsEmptyObject} from 'type-fest';
type Pass = IsEmptyObject<{}>; //=> true
type Fail = IsEmptyObject<[]>; //=> false
type Fail = IsEmptyObject<null>; //=> false
```
@see EmptyObject
@category Object
*/
export type IsEmptyObject<T> = T extends EmptyObject ? true : false;

View File

@@ -0,0 +1,47 @@
import type {Simplify} from './simplify';
// Returns `never` if the key is optional otherwise return the key type.
type RequiredFilter<Type, Key extends keyof Type> = undefined extends Type[Key]
? Type[Key] extends undefined
? Key
: never
: Key;
// Returns `never` if the key is required otherwise return the key type.
type OptionalFilter<Type, Key extends keyof Type> = undefined extends Type[Key]
? Type[Key] extends undefined
? never
: Key
: never;
/**
Enforce optional keys (by adding the `?` operator) for keys that have a union with `undefined`.
@example
```
import type {EnforceOptional} from 'type-fest';
type Foo = {
a: string;
b?: string;
c: undefined;
d: number | undefined;
};
type FooBar = EnforceOptional<Foo>;
// => {
// a: string;
// b?: string;
// c: undefined;
// d?: number;
// }
```
@internal
@category Object
*/
export type EnforceOptional<ObjectType> = Simplify<{
[Key in keyof ObjectType as RequiredFilter<ObjectType, Key>]: ObjectType[Key]
} & {
[Key in keyof ObjectType as OptionalFilter<ObjectType, Key>]?: Exclude<ObjectType[Key], undefined>
}>;

View File

@@ -0,0 +1,62 @@
import type {ArrayEntry, MapEntry, ObjectEntry, SetEntry} from './entry';
type ArrayEntries<BaseType extends readonly unknown[]> = Array<ArrayEntry<BaseType>>;
type MapEntries<BaseType> = Array<MapEntry<BaseType>>;
type ObjectEntries<BaseType> = Array<ObjectEntry<BaseType>>;
type SetEntries<BaseType extends Set<unknown>> = Array<SetEntry<BaseType>>;
/**
Many collections have an `entries` method which returns an array of a given object's own enumerable string-keyed property [key, value] pairs. The `Entries` type will return the type of that collection's entries.
For example the {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries|`Object`}, {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries|`Map`}, {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries|`Array`}, and {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/entries|`Set`} collections all have this method. Note that `WeakMap` and `WeakSet` do not have this method since their entries are not enumerable.
@see `Entry` if you want to just access the type of a single entry.
@example
```
import type {Entries} from 'type-fest';
interface Example {
someKey: number;
}
const manipulatesEntries = (examples: Entries<Example>) => examples.map(example => [
// Does some arbitrary processing on the key (with type information available)
example[0].toUpperCase(),
// Does some arbitrary processing on the value (with type information available)
example[1].toFixed()
]);
const example: Example = {someKey: 1};
const entries = Object.entries(example) as Entries<Example>;
const output = manipulatesEntries(entries);
// Objects
const objectExample = {a: 1};
const objectEntries: Entries<typeof objectExample> = [['a', 1]];
// Arrays
const arrayExample = ['a', 1];
const arrayEntries: Entries<typeof arrayExample> = [[0, 'a'], [1, 1]];
// Maps
const mapExample = new Map([['a', 1]]);
const mapEntries: Entries<typeof mapExample> = [['a', 1]];
// Sets
const setExample = new Set(['a', 1]);
const setEntries: Entries<typeof setExample> = [['a', 'a'], [1, 1]];
```
@category Object
@category Map
@category Set
@category Array
*/
export type Entries<BaseType> =
BaseType extends Map<unknown, unknown> ? MapEntries<BaseType>
: BaseType extends Set<unknown> ? SetEntries<BaseType>
: BaseType extends readonly unknown[] ? ArrayEntries<BaseType>
: BaseType extends object ? ObjectEntries<BaseType>
: never;

View File

@@ -0,0 +1,65 @@
type MapKey<BaseType> = BaseType extends Map<infer KeyType, unknown> ? KeyType : never;
type MapValue<BaseType> = BaseType extends Map<unknown, infer ValueType> ? ValueType : never;
export type ArrayEntry<BaseType extends readonly unknown[]> = [number, BaseType[number]];
export type MapEntry<BaseType> = [MapKey<BaseType>, MapValue<BaseType>];
export type ObjectEntry<BaseType> = [keyof BaseType, BaseType[keyof BaseType]];
export type SetEntry<BaseType> = BaseType extends Set<infer ItemType> ? [ItemType, ItemType] : never;
/**
Many collections have an `entries` method which returns an array of a given object's own enumerable string-keyed property [key, value] pairs. The `Entry` type will return the type of that collection's entry.
For example the {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries|`Object`}, {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries|`Map`}, {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries|`Array`}, and {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/entries|`Set`} collections all have this method. Note that `WeakMap` and `WeakSet` do not have this method since their entries are not enumerable.
@see `Entries` if you want to just access the type of the array of entries (which is the return of the `.entries()` method).
@example
```
import type {Entry} from 'type-fest';
interface Example {
someKey: number;
}
const manipulatesEntry = (example: Entry<Example>) => [
// Does some arbitrary processing on the key (with type information available)
example[0].toUpperCase(),
// Does some arbitrary processing on the value (with type information available)
example[1].toFixed(),
];
const example: Example = {someKey: 1};
const entry = Object.entries(example)[0] as Entry<Example>;
const output = manipulatesEntry(entry);
// Objects
const objectExample = {a: 1};
const objectEntry: Entry<typeof objectExample> = ['a', 1];
// Arrays
const arrayExample = ['a', 1];
const arrayEntryString: Entry<typeof arrayExample> = [0, 'a'];
const arrayEntryNumber: Entry<typeof arrayExample> = [1, 1];
// Maps
const mapExample = new Map([['a', 1]]);
const mapEntry: Entry<typeof mapExample> = ['a', 1];
// Sets
const setExample = new Set(['a', 1]);
const setEntryString: Entry<typeof setExample> = ['a', 'a'];
const setEntryNumber: Entry<typeof setExample> = [1, 1];
```
@category Object
@category Map
@category Array
@category Set
*/
export type Entry<BaseType> =
BaseType extends Map<unknown, unknown> ? MapEntry<BaseType>
: BaseType extends Set<unknown> ? SetEntry<BaseType>
: BaseType extends readonly unknown[] ? ArrayEntry<BaseType>
: BaseType extends object ? ObjectEntry<BaseType>
: never;

View File

@@ -0,0 +1,68 @@
import type {ArrayElement, ObjectValue} from './internal';
import type {IsEqual} from './is-equal';
import type {KeysOfUnion} from './keys-of-union';
import type {IsUnknown} from './is-unknown';
import type {Primitive} from './primitive';
/**
Create a type from `ParameterType` and `InputType` and change keys exclusive to `InputType` to `never`.
- Generate a list of keys that exists in `InputType` but not in `ParameterType`.
- Mark these excess keys as `never`.
*/
type ExactObject<ParameterType, InputType> = {[Key in keyof ParameterType]: Exact<ParameterType[Key], ObjectValue<InputType, Key>>}
& Record<Exclude<keyof InputType, KeysOfUnion<ParameterType>>, never>;
/**
Create a type that does not allow extra properties, meaning it only allows properties that are explicitly declared.
This is useful for function type-guarding to reject arguments with excess properties. Due to the nature of TypeScript, it does not complain if excess properties are provided unless the provided value is an object literal.
*Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/12936) if you want to have this type as a built-in in TypeScript.*
@example
```
type OnlyAcceptName = {name: string};
function onlyAcceptName(arguments_: OnlyAcceptName) {}
// TypeScript complains about excess properties when an object literal is provided.
onlyAcceptName({name: 'name', id: 1});
//=> `id` is excess
// TypeScript does not complain about excess properties when the provided value is a variable (not an object literal).
const invalidInput = {name: 'name', id: 1};
onlyAcceptName(invalidInput); // No errors
```
Having `Exact` allows TypeScript to reject excess properties.
@example
```
import {Exact} from 'type-fest';
type OnlyAcceptName = {name: string};
function onlyAcceptNameImproved<T extends Exact<OnlyAcceptName, T>>(arguments_: T) {}
const invalidInput = {name: 'name', id: 1};
onlyAcceptNameImproved(invalidInput); // Compilation error
```
[Read more](https://stackoverflow.com/questions/49580725/is-it-possible-to-restrict-typescript-object-to-contain-only-properties-defined)
@category Utilities
*/
export type Exact<ParameterType, InputType> =
// Before distributing, check if the two types are equal and if so, return the parameter type immediately
IsEqual<ParameterType, InputType> extends true ? ParameterType
// If the parameter is a primitive, return it as is immediately to avoid it being converted to a complex type
: ParameterType extends Primitive ? ParameterType
// If the parameter is an unknown, return it as is immediately to avoid it being converted to a complex type
: IsUnknown<ParameterType> extends true ? unknown
// If the parameter is a Function, return it as is because this type is not capable of handling function, leave it to TypeScript
: ParameterType extends Function ? ParameterType
// Convert union of array to array of union: A[] & B[] => (A & B)[]
: ParameterType extends unknown[] ? Array<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>
// In TypeScript, Array is a subtype of ReadonlyArray, so always test Array before ReadonlyArray.
: ParameterType extends readonly unknown[] ? ReadonlyArray<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>
: ExactObject<ParameterType, InputType>;

View File

@@ -0,0 +1,108 @@
import type {ApplyDefaultOptions} from './internal';
import type {IsEqual} from './is-equal';
/**
Filter out keys from an object.
Returns `never` if `Exclude` is strictly equal to `Key`.
Returns `never` if `Key` extends `Exclude`.
Returns `Key` otherwise.
@example
```
type Filtered = Filter<'foo', 'foo'>;
//=> never
```
@example
```
type Filtered = Filter<'bar', string>;
//=> never
```
@example
```
type Filtered = Filter<'bar', 'foo'>;
//=> 'bar'
```
@see {Except}
*/
type Filter<KeyType, ExcludeType> = IsEqual<KeyType, ExcludeType> extends true ? never : (KeyType extends ExcludeType ? never : KeyType);
type ExceptOptions = {
/**
Disallow assigning non-specified properties.
Note that any omitted properties in the resulting type will be present in autocomplete as `undefined`.
@default false
*/
requireExactProps?: boolean;
};
type DefaultExceptOptions = {
requireExactProps: false;
};
/**
Create a type from an object type without certain keys.
We recommend setting the `requireExactProps` option to `true`.
This type is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type). The `Omit` type does not restrict the omitted keys to be keys present on the given type, while `Except` does. The benefits of a stricter type are avoiding typos and allowing the compiler to pick up on rename refactors automatically.
This type was proposed to the TypeScript team, which declined it, saying they prefer that libraries implement stricter versions of the built-in types ([microsoft/TypeScript#30825](https://github.com/microsoft/TypeScript/issues/30825#issuecomment-523668235)).
@example
```
import type {Except} from 'type-fest';
type Foo = {
a: number;
b: string;
};
type FooWithoutA = Except<Foo, 'a'>;
//=> {b: string}
const fooWithoutA: FooWithoutA = {a: 1, b: '2'};
//=> errors: 'a' does not exist in type '{ b: string; }'
type FooWithoutB = Except<Foo, 'b', {requireExactProps: true}>;
//=> {a: number} & Partial<Record<"b", never>>
const fooWithoutB: FooWithoutB = {a: 1, b: '2'};
//=> errors at 'b': Type 'string' is not assignable to type 'undefined'.
// The `Omit` utility type doesn't work when omitting specific keys from objects containing index signatures.
// Consider the following example:
type UserData = {
[metadata: string]: string;
email: string;
name: string;
role: 'admin' | 'user';
};
// `Omit` clearly doesn't behave as expected in this case:
type PostPayload = Omit<UserData, 'email'>;
//=> type PostPayload = { [x: string]: string; [x: number]: string; }
// In situations like this, `Except` works better.
// It simply removes the `email` key while preserving all the other keys.
type PostPayload = Except<UserData, 'email'>;
//=> type PostPayload = { [x: string]: string; name: string; role: 'admin' | 'user'; }
```
@category Object
*/
export type Except<ObjectType, KeysType extends keyof ObjectType, Options extends ExceptOptions = {}> =
_Except<ObjectType, KeysType, ApplyDefaultOptions<ExceptOptions, DefaultExceptOptions, Options>>;
type _Except<ObjectType, KeysType extends keyof ObjectType, Options extends Required<ExceptOptions>> = {
[KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType];
} & (Options['requireExactProps'] extends true
? Partial<Record<KeysType, never>>
: {});

View File

@@ -0,0 +1,64 @@
/**
Tries to find the type of a global with the given name.
Limitations: Due to peculiarities with the behavior of `globalThis`, "globally defined" only includes `var` declarations in `declare global` blocks, not `let` or `const` declarations.
@example
```
import type {FindGlobalType} from 'type-fest';
declare global {
const foo: number; // let and const don't work
var bar: string; // var works
}
type FooType = FindGlobalType<'foo'> //=> never (let/const don't work)
type BarType = FindGlobalType<'bar'> //=> string
type OtherType = FindGlobalType<'other'> //=> never (no global named 'other')
```
@category Utilities
*/
export type FindGlobalType<Name extends string> = typeof globalThis extends Record<Name, infer T> ? T : never;
/**
Tries to find one or more types from their globally-defined constructors.
Use-case: Conditionally referencing DOM types only when the DOM library present.
*Limitations:* Due to peculiarities with the behavior of `globalThis`, "globally defined" has a narrow definition in this case. Declaring a class in a `declare global` block won't work, instead you must declare its type using an interface and declare its constructor as a `var` (*not* `let`/`const`) inside the `declare global` block.
@example
```
import type {FindGlobalInstanceType} from 'type-fest';
class Point {
constructor(public x: number, public y: number) {}
}
type PointLike = Point | FindGlobalInstanceType<'DOMPoint'>;
```
@example
```
import type {FindGlobalInstanceType} from 'type-fest';
declare global {
// Class syntax won't add the key to `globalThis`
class Foo {}
// interface + constructor style works
interface Bar {}
var Bar: new () => Bar; // Not let or const
}
type FindFoo = FindGlobalInstanceType<'Foo'>; // Doesn't work
type FindBar = FindGlobalInstanceType<'Bar'>; // Works
```
@category Utilities
*/
export type FindGlobalInstanceType<Name extends string> =
Name extends string
? typeof globalThis extends Record<Name, abstract new (...arguments: any[]) => infer T> ? T : never
: never;

View File

@@ -0,0 +1,43 @@
/**
Methods to exclude.
*/
type ArrayLengthMutationKeys = 'splice' | 'push' | 'pop' | 'shift' | 'unshift';
/**
Create a type that represents an array of the given type and length. The array's length and the `Array` prototype methods that manipulate its length are excluded in the resulting type.
Please participate in [this issue](https://github.com/microsoft/TypeScript/issues/26223) if you want to have a similar type built into TypeScript.
Use-cases:
- Declaring fixed-length tuples or arrays with a large number of items.
- Creating a range union (for example, `0 | 1 | 2 | 3 | 4` from the keys of such a type) without having to resort to recursive types.
- Creating an array of coordinates with a static length, for example, length of 3 for a 3D vector.
Note: This type does not prevent out-of-bounds access. Prefer `ReadonlyTuple` unless you need mutability.
@example
```
import type {FixedLengthArray} from 'type-fest';
type FencingTeam = FixedLengthArray<string, 3>;
const guestFencingTeam: FencingTeam = ['Josh', 'Michael', 'Robert'];
const homeFencingTeam: FencingTeam = ['George', 'John'];
//=> error TS2322: Type string[] is not assignable to type 'FencingTeam'
guestFencingTeam.push('Sam');
//=> error TS2339: Property 'push' does not exist on type 'FencingTeam'
```
@category Array
@see ReadonlyTuple
*/
export type FixedLengthArray<Element, Length extends number, ArrayPrototype = [Element, ...Element[]]> = Pick<
ArrayPrototype,
Exclude<keyof ArrayPrototype, ArrayLengthMutationKeys>
> & {
[index: number]: Element;
[Symbol.iterator]: () => IterableIterator<Element>;
readonly length: Length;
};

View File

@@ -0,0 +1,219 @@
import type {ApplyDefaultOptions, StringDigit, ToString} from './internal';
import type {LiteralStringUnion} from './literal-union';
import type {Paths} from './paths';
import type {Split} from './split';
import type {StringKeyOf} from './string-key-of';
type GetOptions = {
/**
Include `undefined` in the return type when accessing properties.
Setting this to `false` is not recommended.
@default true
*/
strict?: boolean;
};
type DefaultGetOptions = {
strict: true;
};
/**
Like the `Get` type but receives an array of strings as a path parameter.
*/
type GetWithPath<BaseType, Keys, Options extends Required<GetOptions>> =
Keys extends readonly []
? BaseType
: Keys extends readonly [infer Head, ...infer Tail]
? GetWithPath<
PropertyOf<BaseType, Extract<Head, string>, Options>,
Extract<Tail, string[]>,
Options
>
: never;
/**
Adds `undefined` to `Type` if `strict` is enabled.
*/
type Strictify<Type, Options extends Required<GetOptions>> =
Options['strict'] extends false ? Type : (Type | undefined);
/**
If `Options['strict']` is `true`, includes `undefined` in the returned type when accessing properties on `Record<string, any>`.
Known limitations:
- Does not include `undefined` in the type on object types with an index signature (for example, `{a: string; [key: string]: string}`).
*/
type StrictPropertyOf<BaseType, Key extends keyof BaseType, Options extends Required<GetOptions>> =
Record<string, any> extends BaseType
? string extends keyof BaseType
? Strictify<BaseType[Key], Options> // Record<string, any>
: BaseType[Key] // Record<'a' | 'b', any> (Records with a string union as keys have required properties)
: BaseType[Key];
/**
Splits a dot-prop style path into a tuple comprised of the properties in the path. Handles square-bracket notation.
@example
```
ToPath<'foo.bar.baz'>
//=> ['foo', 'bar', 'baz']
ToPath<'foo[0].bar.baz'>
//=> ['foo', '0', 'bar', 'baz']
```
*/
type ToPath<S extends string> = Split<FixPathSquareBrackets<S>, '.'>;
/**
Replaces square-bracketed dot notation with dots, for example, `foo[0].bar` -> `foo.0.bar`.
*/
type FixPathSquareBrackets<Path extends string> =
Path extends `[${infer Head}]${infer Tail}`
? Tail extends `[${string}`
? `${Head}.${FixPathSquareBrackets<Tail>}`
: `${Head}${FixPathSquareBrackets<Tail>}`
: Path extends `${infer Head}[${infer Middle}]${infer Tail}`
? `${Head}.${FixPathSquareBrackets<`[${Middle}]${Tail}`>}`
: Path;
/**
Returns true if `LongString` is made up out of `Substring` repeated 0 or more times.
@example
```
ConsistsOnlyOf<'aaa', 'a'> //=> true
ConsistsOnlyOf<'ababab', 'ab'> //=> true
ConsistsOnlyOf<'aBa', 'a'> //=> false
ConsistsOnlyOf<'', 'a'> //=> true
```
*/
type ConsistsOnlyOf<LongString extends string, Substring extends string> =
LongString extends ''
? true
: LongString extends `${Substring}${infer Tail}`
? ConsistsOnlyOf<Tail, Substring>
: false;
/**
Convert a type which may have number keys to one with string keys, making it possible to index using strings retrieved from template types.
@example
```
type WithNumbers = {foo: string; 0: boolean};
type WithStrings = WithStringKeys<WithNumbers>;
type WithNumbersKeys = keyof WithNumbers;
//=> 'foo' | 0
type WithStringsKeys = keyof WithStrings;
//=> 'foo' | '0'
```
*/
type WithStringKeys<BaseType> = {
[Key in StringKeyOf<BaseType>]: UncheckedIndex<BaseType, Key>
};
/**
Perform a `T[U]` operation if `T` supports indexing.
*/
type UncheckedIndex<T, U extends string | number> = [T] extends [Record<string | number, any>] ? T[U] : never;
/**
Get a property of an object or array. Works when indexing arrays using number-literal-strings, for example, `PropertyOf<number[], '0'> = number`, and when indexing objects with number keys.
Note:
- Returns `unknown` if `Key` is not a property of `BaseType`, since TypeScript uses structural typing, and it cannot be guaranteed that extra properties unknown to the type system will exist at runtime.
- Returns `undefined` from nullish values, to match the behaviour of most deep-key libraries like `lodash`, `dot-prop`, etc.
*/
type PropertyOf<BaseType, Key extends string, Options extends Required<GetOptions>> =
BaseType extends null | undefined
? undefined
: Key extends keyof BaseType
? StrictPropertyOf<BaseType, Key, Options>
// Handle arrays and tuples
: BaseType extends readonly unknown[]
? Key extends `${number}`
// For arrays with unknown length (regular arrays)
? number extends BaseType['length']
? Strictify<BaseType[number], Options>
// For tuples: check if the index is valid
: Key extends keyof BaseType
? Strictify<BaseType[Key & keyof BaseType], Options>
// Out-of-bounds access for tuples
: unknown
// Non-numeric string key for arrays/tuples
: unknown
// Handle array-like objects
: BaseType extends {
[n: number]: infer Item;
length: number; // Note: This is needed to avoid being too lax with records types using number keys like `{0: string; 1: boolean}`.
}
? (
ConsistsOnlyOf<Key, StringDigit> extends true
? Strictify<Item, Options>
: unknown
)
: Key extends keyof WithStringKeys<BaseType>
? StrictPropertyOf<WithStringKeys<BaseType>, Key, Options>
: unknown;
// This works by first splitting the path based on `.` and `[...]` characters into a tuple of string keys. Then it recursively uses the head key to get the next property of the current object, until there are no keys left. Number keys extract the item type from arrays, or are converted to strings to extract types from tuples and dictionaries with number keys.
/**
Get a deeply-nested property from an object using a key path, like Lodash's `.get()` function.
Use-case: Retrieve a property from deep inside an API response or some other complex object.
@example
```
import type {Get} from 'type-fest';
import * as lodash from 'lodash';
const get = <BaseType, Path extends string | readonly string[]>(object: BaseType, path: Path): Get<BaseType, Path> =>
lodash.get(object, path);
interface ApiResponse {
hits: {
hits: Array<{
_id: string
_source: {
name: Array<{
given: string[]
family: string
}>
birthDate: string
}
}>
}
}
const getName = (apiResponse: ApiResponse) =>
get(apiResponse, 'hits.hits[0]._source.name');
//=> Array<{given: string[]; family: string}> | undefined
// Path also supports a readonly array of strings
const getNameWithPathArray = (apiResponse: ApiResponse) =>
get(apiResponse, ['hits','hits', '0', '_source', 'name'] as const);
//=> Array<{given: string[]; family: string}> | undefined
// Non-strict mode:
Get<string[], '3', {strict: false}> //=> string
Get<Record<string, string>, 'foo', {strict: true}> // => string
```
@category Object
@category Array
@category Template literal
*/
export type Get<
BaseType,
Path extends
| readonly string[]
| LiteralStringUnion<ToString<Paths<BaseType, {bracketNotation: false; maxRecursionDepth: 2}> | Paths<BaseType, {bracketNotation: true; maxRecursionDepth: 2}>>>,
Options extends GetOptions = {},
> =
GetWithPath<
BaseType,
Path extends string ? ToPath<Path> : Path,
ApplyDefaultOptions<GetOptions, DefaultGetOptions, Options>
>;

View File

@@ -0,0 +1,21 @@
/**
Declare locally scoped properties on `globalThis`.
When defining a global variable in a declaration file is inappropriate, it can be helpful to define a `type` or `interface` (say `ExtraGlobals`) with the global variable and then cast `globalThis` via code like `globalThis as unknown as ExtraGlobals`.
Instead of casting through `unknown`, you can update your `type` or `interface` to extend `GlobalThis` and then directly cast `globalThis`.
@example
```
import type {GlobalThis} from 'type-fest';
type ExtraGlobals = GlobalThis & {
readonly GLOBAL_TOKEN: string;
};
(globalThis as ExtraGlobals).GLOBAL_TOKEN;
```
@category Type
*/
export type GlobalThis = typeof globalThis;

View File

@@ -0,0 +1,22 @@
import type {GreaterThan} from './greater-than';
/**
Returns a boolean for whether a given number is greater than or equal to another number.
@example
```
import type {GreaterThanOrEqual} from 'type-fest';
GreaterThanOrEqual<1, -5>;
//=> true
GreaterThanOrEqual<1, 1>;
//=> true
GreaterThanOrEqual<1, 5>;
//=> false
```
*/
export type GreaterThanOrEqual<A extends number, B extends number> = number extends A | B
? never
: A extends B ? true : GreaterThan<A, B>;

View File

@@ -0,0 +1,56 @@
import type {NumberAbsolute, PositiveNumericStringGt} from './internal';
import type {IsEqual} from './is-equal';
import type {PositiveInfinity, NegativeInfinity, IsNegative} from './numeric';
import type {And} from './and';
import type {Or} from './or';
/**
Returns a boolean for whether a given number is greater than another number.
@example
```
import type {GreaterThan} from 'type-fest';
GreaterThan<1, -5>;
//=> true
GreaterThan<1, 1>;
//=> false
GreaterThan<1, 5>;
//=> false
```
*/
export type GreaterThan<A extends number, B extends number> =
A extends number // For distributing `A`
? B extends number // For distributing `B`
? number extends A | B
? never
: [
IsEqual<A, PositiveInfinity>, IsEqual<A, NegativeInfinity>,
IsEqual<B, PositiveInfinity>, IsEqual<B, NegativeInfinity>,
] extends infer R extends [boolean, boolean, boolean, boolean]
? Or<
And<IsEqual<R[0], true>, IsEqual<R[2], false>>,
And<IsEqual<R[3], true>, IsEqual<R[1], false>>
> extends true
? true
: Or<
And<IsEqual<R[1], true>, IsEqual<R[3], false>>,
And<IsEqual<R[2], true>, IsEqual<R[0], false>>
> extends true
? false
: true extends R[number]
? false
: [IsNegative<A>, IsNegative<B>] extends infer R extends [boolean, boolean]
? [true, false] extends R
? false
: [false, true] extends R
? true
: [false, false] extends R
? PositiveNumericStringGt<`${A}`, `${B}`>
: PositiveNumericStringGt<`${NumberAbsolute<B>}`, `${NumberAbsolute<A>}`>
: never
: never
: never // Should never happen
: never; // Should never happen

View File

@@ -0,0 +1,21 @@
import type {OptionalKeysOf} from './optional-keys-of';
/**
Creates a type that represents `true` or `false` depending on whether the given type has any optional fields.
This is useful when you want to create an API whose behavior depends on the presence or absence of optional fields.
@example
```
import type {HasOptionalKeys, OptionalKeysOf} from 'type-fest';
type UpdateService<Entity extends object> = {
removeField: HasOptionalKeys<Entity> extends true
? (field: OptionalKeysOf<Entity>) => Promise<void>
: never
}
```
@category Utilities
*/
export type HasOptionalKeys<BaseType extends object> = OptionalKeysOf<BaseType> extends never ? false : true;

View File

@@ -0,0 +1,21 @@
import type {ReadonlyKeysOf} from './readonly-keys-of';
/**
Creates a type that represents `true` or `false` depending on whether the given type has any readonly fields.
This is useful when you want to create an API whose behavior depends on the presence or absence of readonly fields.
@example
```
import type {HasReadonlyKeys, ReadonlyKeysOf} from 'type-fest';
type UpdateService<Entity extends object> = {
removeField: HasReadonlyKeys<Entity> extends true
? (field: ReadonlyKeysOf<Entity>) => Promise<void>
: never
}
```
@category Utilities
*/
export type HasReadonlyKeys<BaseType extends object> = ReadonlyKeysOf<BaseType> extends never ? false : true;

View File

@@ -0,0 +1,59 @@
import type {RequiredKeysOf} from './required-keys-of';
/**
Creates a type that represents `true` or `false` depending on whether the given type has any required fields.
This is useful when you want to create an API whose behavior depends on the presence or absence of required fields.
@example
```
import type {HasRequiredKeys} from 'type-fest';
type GeneratorOptions<Template extends object> = {
prop1: number;
prop2: string;
} & (HasRequiredKeys<Template> extends true
? {template: Template}
: {template?: Template});
interface Template1 {
optionalSubParam?: string;
}
interface Template2 {
requiredSubParam: string;
}
type Options1 = GeneratorOptions<Template1>;
type Options2 = GeneratorOptions<Template2>;
const optA: Options1 = {
prop1: 0,
prop2: 'hi'
};
const optB: Options1 = {
prop1: 0,
prop2: 'hi',
template: {}
};
const optC: Options1 = {
prop1: 0,
prop2: 'hi',
template: {
optionalSubParam: 'optional value'
}
};
const optD: Options2 = {
prop1: 0,
prop2: 'hi',
template: {
requiredSubParam: 'required value'
}
};
```
@category Utilities
*/
export type HasRequiredKeys<BaseType extends object> = RequiredKeysOf<BaseType> extends never ? false : true;

View File

@@ -0,0 +1,21 @@
import type {WritableKeysOf} from './writable-keys-of';
/**
Creates a type that represents `true` or `false` depending on whether the given type has any writable fields.
This is useful when you want to create an API whose behavior depends on the presence or absence of writable fields.
@example
```
import type {HasWritableKeys, WritableKeysOf} from 'type-fest';
type UpdateService<Entity extends object> = {
removeField: HasWritableKeys<Entity> extends true
? (field: WritableKeysOf<Entity>) => Promise<void>
: never
}
```
@category Utilities
*/
export type HasWritableKeys<BaseType extends object> = WritableKeysOf<BaseType> extends never ? false : true;

View File

@@ -0,0 +1,24 @@
import type {IsAny} from './is-any';
/**
An if-else-like type that resolves depending on whether the given type is `any`.
@see {@link IsAny}
@example
```
import type {IfAny} from 'type-fest';
type ShouldBeTrue = IfAny<any>;
//=> true
type ShouldBeBar = IfAny<'not any', 'foo', 'bar'>;
//=> 'bar'
```
@category Type Guard
@category Utilities
*/
export type IfAny<T, TypeIfAny = true, TypeIfNotAny = false> = (
IsAny<T> extends true ? TypeIfAny : TypeIfNotAny
);

View File

@@ -0,0 +1,26 @@
import type {IsEmptyObject} from './empty-object';
/**
An if-else-like type that resolves depending on whether the given type is `{}`.
@see {@link IsEmptyObject}
@example
```
import type {IfEmptyObject} from 'type-fest';
type ShouldBeTrue = IfEmptyObject<{}>;
//=> true
type ShouldBeBar = IfEmptyObject<{key: any}, 'foo', 'bar'>;
//=> 'bar'
```
@category Type Guard
@category Utilities
*/
export type IfEmptyObject<
T,
TypeIfEmptyObject = true,
TypeIfNotEmptyObject = false,
> = IsEmptyObject<T> extends true ? TypeIfEmptyObject : TypeIfNotEmptyObject;

View File

@@ -0,0 +1,24 @@
import type {IsNever} from './is-never';
/**
An if-else-like type that resolves depending on whether the given type is `never`.
@see {@link IsNever}
@example
```
import type {IfNever} from 'type-fest';
type ShouldBeTrue = IfNever<never>;
//=> true
type ShouldBeBar = IfNever<'not never', 'foo', 'bar'>;
//=> 'bar'
```
@category Type Guard
@category Utilities
*/
export type IfNever<T, TypeIfNever = true, TypeIfNotNever = false> = (
IsNever<T> extends true ? TypeIfNever : TypeIfNotNever
);

View File

@@ -0,0 +1,24 @@
import type {IsNull} from './is-null';
/**
An if-else-like type that resolves depending on whether the given type is `null`.
@see {@link IsNull}
@example
```
import type {IfNull} from 'type-fest';
type ShouldBeTrue = IfNull<null>;
//=> true
type ShouldBeBar = IfNull<'not null', 'foo', 'bar'>;
//=> 'bar'
```
@category Type Guard
@category Utilities
*/
export type IfNull<T, TypeIfNull = true, TypeIfNotNull = false> = (
IsNull<T> extends true ? TypeIfNull : TypeIfNotNull
);

View File

@@ -0,0 +1,24 @@
import type {IsUnknown} from './is-unknown';
/**
An if-else-like type that resolves depending on whether the given type is `unknown`.
@see {@link IsUnknown}
@example
```
import type {IfUnknown} from 'type-fest';
type ShouldBeTrue = IfUnknown<unknown>;
//=> true
type ShouldBeBar = IfUnknown<'not unknown', 'foo', 'bar'>;
//=> 'bar'
```
@category Type Guard
@category Utilities
*/
export type IfUnknown<T, TypeIfUnknown = true, TypeIfNotUnknown = false> = (
IsUnknown<T> extends true ? TypeIfUnknown : TypeIfNotUnknown
);

View File

@@ -0,0 +1,22 @@
import type {IsEqual} from './is-equal';
/**
Returns a boolean for whether the given array includes the given item.
This can be useful if another type wants to make a decision based on whether the array includes that item.
@example
```
import type {Includes} from 'type-fest';
type hasRed<array extends any[]> = Includes<array, 'red'>;
```
@category Array
*/
export type Includes<Value extends readonly any[], Item> =
Value extends readonly [Value[0], ...infer rest]
? IsEqual<Value[0], Item> extends true
? true
: Includes<rest, Item>
: false;

View File

@@ -0,0 +1,35 @@
import type {IntRange} from './int-range';
import type {Sum} from './sum';
/**
Generate a union of numbers.
The numbers are created from the given `Start` (inclusive) parameter to the given `End` (inclusive) parameter.
You skip over numbers using the `Step` parameter (defaults to `1`). For example, `IntClosedRange<0, 10, 2>` will create a union of `0 | 2 | 4 | 6 | 8 | 10`.
Note: `Start` or `End` must be non-negative and smaller than `999`.
Use-cases:
1. This can be used to define a set of valid input/output values. for example:
```
type Age = IntClosedRange<0, 120>; //=> 0 | 1 | 2 | ... | 119 | 120
type FontSize = IntClosedRange<10, 20>; //=> 10 | 11 | ... | 19 | 20
type EvenNumber = IntClosedRange<0, 10, 2>; //=> 0 | 2 | 4 | 6 | 8 | 10
```
2. This can be used to define random numbers in a range. For example, `type RandomNumber = IntClosedRange<0, 100>;`
@example
```
import type {IntClosedRange} from 'type-fest';
// Create union type `0 | 1 | ... | 9`
type ZeroToNine = IntClosedRange<0, 9>;
// Create union type `100 | 200 | 300 | ... | 900`
type Hundreds = IntClosedRange<100, 900, 100>;
```
@see IntRange
*/
export type IntClosedRange<Start extends number, End extends number, Skip extends number = 1> = IntRange<Start, Sum<End, 1>, Skip>;

View File

@@ -0,0 +1,55 @@
import type {BuildTuple} from './internal';
import type {Subtract} from './subtract';
/**
Generate a union of numbers.
The numbers are created from the given `Start` (inclusive) parameter to the given `End` (exclusive) parameter.
You skip over numbers using the `Step` parameter (defaults to `1`). For example, `IntRange<0, 10, 2>` will create a union of `0 | 2 | 4 | 6 | 8`.
Note: `Start` or `End` must be non-negative and smaller than `1000`.
Use-cases:
1. This can be used to define a set of valid input/output values. for example:
```
type Age = IntRange<0, 120>;
type FontSize = IntRange<10, 20>;
type EvenNumber = IntRange<0, 11, 2>; //=> 0 | 2 | 4 | 6 | 8 | 10
```
2. This can be used to define random numbers in a range. For example, `type RandomNumber = IntRange<0, 100>;`
@example
```
import type {IntRange} from 'type-fest';
// Create union type `0 | 1 | ... | 9`
type ZeroToNine = IntRange<0, 10>;
// Create union type `100 | 200 | 300 | ... | 900`
type Hundreds = IntRange<100, 901, 100>;
```
@see IntClosedRange
*/
export type IntRange<Start extends number, End extends number, Step extends number = 1> = PrivateIntRange<Start, End, Step>;
/**
The actual implementation of `IntRange`. It's private because it has some arguments that don't need to be exposed.
*/
type PrivateIntRange<
Start extends number,
End extends number,
Step extends number,
Gap extends number = Subtract<Step, 1>, // The gap between each number, gap = step - 1
List extends unknown[] = BuildTuple<Start, never>, // The final `List` is `[...StartLengthTuple, ...[number, ...GapLengthTuple], ...[number, ...GapLengthTuple], ... ...]`, so can initialize the `List` with `[...StartLengthTuple]`
EndLengthTuple extends unknown[] = BuildTuple<End>,
> = Gap extends 0 ?
// Handle the case that without `Step`
List['length'] extends End // The result of "List[length] === End"
? Exclude<List[number], never> // All unused elements are `never`, so exclude them
: PrivateIntRange<Start, End, Step, Gap, [...List, List['length'] ]>
// Handle the case that with `Step`
: List extends [...(infer U), ...EndLengthTuple] // The result of "List[length] >= End", because the `...BuildTuple<Gap, never>` maybe make `List` too long.
? Exclude<List[number], never>
: PrivateIntRange<Start, End, Step, Gap, [...List, List['length'], ...BuildTuple<Gap, never>]>;

View File

@@ -0,0 +1,126 @@
import type {IfNever} from '../if-never';
import type {UnknownArray} from '../unknown-array';
/**
Infer the length of the given array `<T>`.
@link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
*/
type ArrayLength<T extends readonly unknown[]> = T extends {readonly length: infer L} ? L : never;
/**
Matches any unknown array or tuple.
*/
export type UnknownArrayOrTuple = readonly [...unknown[]];
// TODO: should unknown-array be updated?
/**
Extracts the type of the first element of an array or tuple.
*/
export type FirstArrayElement<TArray extends UnknownArrayOrTuple> = TArray extends readonly [infer THead, ...unknown[]]
? THead
: never;
/**
Extract the element of an array that also works for array union.
Returns `never` if T is not an array.
It creates a type-safe way to access the element type of `unknown` type.
*/
export type ArrayElement<T> = T extends readonly unknown[] ? T[0] : never;
/**
Returns the static, fixed-length portion of the given array, excluding variable-length parts.
@example
```
type A = [string, number, boolean, ...string[]];
type B = StaticPartOfArray<A>;
//=> [string, number, boolean]
```
*/
export type StaticPartOfArray<T extends UnknownArray, Result extends UnknownArray = []> =
T extends unknown
? number extends T['length'] ?
T extends readonly [infer U, ...infer V]
? StaticPartOfArray<V, [...Result, U]>
: Result
: T
: never; // Should never happen
/**
Returns the variable, non-fixed-length portion of the given array, excluding static-length parts.
@example
```
type A = [string, number, boolean, ...string[]];
type B = VariablePartOfArray<A>;
//=> string[]
```
*/
export type VariablePartOfArray<T extends UnknownArray> =
T extends unknown
? T extends readonly [...StaticPartOfArray<T>, ...infer U]
? U
: []
: never; // Should never happen
/**
Set the given array to readonly if `IsReadonly` is `true`, otherwise set the given array to normal, then return the result.
@example
```
type ReadonlyArray = readonly string[];
type NormalArray = string[];
type ReadonlyResult = SetArrayAccess<NormalArray, true>;
//=> readonly string[]
type NormalResult = SetArrayAccess<ReadonlyArray, false>;
//=> string[]
```
*/
export type SetArrayAccess<T extends UnknownArray, IsReadonly extends boolean> =
T extends readonly [...infer U] ?
IsReadonly extends true
? readonly [...U]
: [...U]
: T;
/**
Returns whether the given array `T` is readonly.
*/
export type IsArrayReadonly<T extends UnknownArray> = IfNever<T, false, T extends unknown[] ? false : true>;
/**
An if-else-like type that resolves depending on whether the given array is readonly.
@see {@link IsArrayReadonly}
@example
```
import type {ArrayTail} from 'type-fest';
type ReadonlyPreservingArrayTail<TArray extends readonly unknown[]> =
ArrayTail<TArray> extends infer Tail
? IfArrayReadonly<TArray, Readonly<Tail>, Tail>
: never;
type ReadonlyTail = ReadonlyPreservingArrayTail<readonly [string, number, boolean]>;
//=> readonly [number, boolean]
type NonReadonlyTail = ReadonlyPreservingArrayTail<[string, number, boolean]>;
//=> [number, boolean]
type ShouldBeTrue = IfArrayReadonly<readonly unknown[]>;
//=> true
type ShouldBeBar = IfArrayReadonly<unknown[], 'foo', 'bar'>;
//=> 'bar'
```
*/
export type IfArrayReadonly<T extends UnknownArray, TypeIfArrayReadonly = true, TypeIfNotArrayReadonly = false> =
IsArrayReadonly<T> extends infer Result
? Result extends true ? TypeIfArrayReadonly : TypeIfNotArrayReadonly
: never; // Should never happen

View File

@@ -0,0 +1,67 @@
export type UpperCaseCharacters = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
export type StringDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
export type Whitespace =
| '\u{9}' // '\t'
| '\u{A}' // '\n'
| '\u{B}' // '\v'
| '\u{C}' // '\f'
| '\u{D}' // '\r'
| '\u{20}' // ' '
| '\u{85}'
| '\u{A0}'
| '\u{1680}'
| '\u{2000}'
| '\u{2001}'
| '\u{2002}'
| '\u{2003}'
| '\u{2004}'
| '\u{2005}'
| '\u{2006}'
| '\u{2007}'
| '\u{2008}'
| '\u{2009}'
| '\u{200A}'
| '\u{2028}'
| '\u{2029}'
| '\u{202F}'
| '\u{205F}'
| '\u{3000}'
| '\u{FEFF}';
export type WordSeparators = '-' | '_' | Whitespace;
export type AsciiPunctuation =
| '!'
| '"'
| '#'
| '$'
| '%'
| '&'
| '\''
| '('
| ')'
| '*'
| '+'
| ','
| '-'
| '.'
| '/'
| ':'
| ';'
| '<'
| '='
| '>'
| '?'
| '@'
| '['
| '\\'
| ']'
| '^'
| '_'
| '`'
| '{'
| '|'
| '}'
| '~';

View File

@@ -0,0 +1,8 @@
export type * from './array';
export type * from './characters';
export type * from './keys';
export type * from './numeric';
export type * from './object';
export type * from './string';
export type * from './tuple';
export type * from './type';

View File

@@ -0,0 +1,97 @@
import type {IsAny} from '../is-any';
import type {IsLiteral} from '../is-literal';
import type {ToString} from './string';
// Returns `never` if the key or property is not jsonable without testing whether the property is required or optional otherwise return the key.
type BaseKeyFilter<Type, Key extends keyof Type> = Key extends symbol
? never
: Type[Key] extends symbol
? never
/*
To prevent a problem where an object with only a `name` property is incorrectly treated as assignable to a function, we first check if the property is a record.
This check is necessary, because without it, if we don't verify whether the property is a record, an object with a type of `{name: any}` would return `never` due to its potential assignability to a function.
See: https://github.com/sindresorhus/type-fest/issues/657
*/
: Type[Key] extends Record<string, unknown>
? Key
: [(...arguments_: any[]) => any] extends [Type[Key]]
? never
: Key;
/**
Returns the required keys.
*/
export type FilterDefinedKeys<T extends object> = Exclude<
{
[Key in keyof T]: IsAny<T[Key]> extends true
? Key
: undefined extends T[Key]
? never
: T[Key] extends undefined
? never
: BaseKeyFilter<T, Key>;
}[keyof T],
undefined
>;
/**
Returns the optional keys.
*/
export type FilterOptionalKeys<T extends object> = Exclude<
{
[Key in keyof T]: IsAny<T[Key]> extends true
? never
: undefined extends T[Key]
? T[Key] extends undefined
? never
: BaseKeyFilter<T, Key>
: never;
}[keyof T],
undefined
>;
/**
Disallows any of the given keys.
*/
export type RequireNone<KeysType extends PropertyKey> = Partial<Record<KeysType, never>>;
/**
Utility type to retrieve only literal keys from type.
*/
export type LiteralKeyOf<T> = keyof {[K in keyof T as IsLiteral<K> extends true ? K : never]-?: never};
/**
Get the exact version of the given `Key` in the given object `T`.
Use-case: You known that a number key (e.g. 10) is in an object, but you don't know how it is defined in the object, as a string or as a number (e.g. 10 or '10'). You can use this type to get the exact version of the key. See the example.
@example
```
type Object = {
0: number;
'1': string;
};
type Key1 = ExactKey<Object, '0'>;
//=> 0
type Key2 = ExactKey<Object, 0>;
//=> 0
type Key3 = ExactKey<Object, '1'>;
//=> '1'
type Key4 = ExactKey<Object, 1>;
//=> '1'
```
@category Object
*/
export type ExactKey<T extends object, Key extends PropertyKey> =
Key extends keyof T
? Key
: ToString<Key> extends keyof T
? ToString<Key>
: Key extends `${infer NumberKey extends number}`
? NumberKey extends keyof T
? NumberKey
: never
: never;

View File

@@ -0,0 +1,118 @@
import type {IsNever} from '../is-never';
import type {NegativeInfinity, PositiveInfinity} from '../numeric';
import type {UnknownArray} from '../unknown-array';
import type {StringToNumber} from './string';
/**
Returns the absolute value of a given value.
@example
```
NumberAbsolute<-1>;
//=> 1
NumberAbsolute<1>;
//=> 1
NumberAbsolute<NegativeInfinity>
//=> PositiveInfinity
```
*/
export type NumberAbsolute<N extends number> = `${N}` extends `-${infer StringPositiveN}` ? StringToNumber<StringPositiveN> : N;
/**
Check whether the given type is a number or a number string.
Supports floating-point as a string.
@example
```
type A = IsNumberLike<'1'>;
//=> true
type B = IsNumberLike<'-1.1'>;
//=> true
type C = IsNumberLike<1>;
//=> true
type D = IsNumberLike<'a'>;
//=> false
*/
export type IsNumberLike<N> =
N extends number ? true
: N extends `${number}`
? true
: N extends `${number}.${number}`
? true
: false;
/**
Returns the minimum number in the given union of numbers.
Note: Just supports numbers from 0 to 999.
@example
```
type A = UnionMin<3 | 1 | 2>;
//=> 1
```
*/
export type UnionMin<N extends number> = InternalUnionMin<N>;
/**
The actual implementation of `UnionMin`. It's private because it has some arguments that don't need to be exposed.
*/
type InternalUnionMin<N extends number, T extends UnknownArray = []> =
T['length'] extends N
? T['length']
: InternalUnionMin<N, [...T, unknown]>;
/**
Returns the maximum number in the given union of numbers.
Note: Just supports numbers from 0 to 999.
@example
```
type A = UnionMax<1 | 3 | 2>;
//=> 3
```
*/
export type UnionMax<N extends number> = InternalUnionMax<N>;
/**
The actual implementation of `UnionMax`. It's private because it has some arguments that don't need to be exposed.
*/
type InternalUnionMax<N extends number, T extends UnknownArray = []> =
IsNever<N> extends true
? T['length']
: T['length'] extends N
? InternalUnionMax<Exclude<N, T['length']>, T>
: InternalUnionMax<N, [...T, unknown]>;
/**
Returns the number with reversed sign.
@example
```
ReverseSign<-1>;
//=> 1
ReverseSign<1>;
//=> -1
ReverseSign<NegativeInfinity>
//=> PositiveInfinity
ReverseSign<PositiveInfinity>
//=> NegativeInfinity
```
*/
export type ReverseSign<N extends number> =
// Handle edge cases
N extends 0 ? 0 : N extends PositiveInfinity ? NegativeInfinity : N extends NegativeInfinity ? PositiveInfinity :
// Handle negative numbers
`${N}` extends `-${infer P extends number}` ? P
// Handle positive numbers
: `-${N}` extends `${infer R extends number}` ? R : never;

View File

@@ -0,0 +1,236 @@
import type {Simplify} from '../simplify';
import type {UnknownArray} from '../unknown-array';
import type {IsEqual} from '../is-equal';
import type {KeysOfUnion} from '../keys-of-union';
import type {RequiredKeysOf} from '../required-keys-of';
import type {Merge} from '../merge';
import type {IfAny} from '../if-any';
import type {IfNever} from '../if-never';
import type {OptionalKeysOf} from '../optional-keys-of';
import type {FilterDefinedKeys, FilterOptionalKeys} from './keys';
import type {NonRecursiveType} from './type';
import type {ToString} from './string';
/**
Create an object type with the given key `<Key>` and value `<Value>`.
It will copy the prefix and optional status of the same key from the given object `CopiedFrom` into the result.
@example
```
type A = BuildObject<'a', string>;
//=> {a: string}
// Copy `readonly` and `?` from the key `a` of `{readonly a?: any}`
type B = BuildObject<'a', string, {readonly a?: any}>;
//=> {readonly a?: string}
```
*/
export type BuildObject<Key extends PropertyKey, Value, CopiedFrom extends object = {}> =
Key extends keyof CopiedFrom
? Pick<{[_ in keyof CopiedFrom]: Value}, Key>
: Key extends `${infer NumberKey extends number}`
? NumberKey extends keyof CopiedFrom
? Pick<{[_ in keyof CopiedFrom]: Value}, NumberKey>
: {[_ in Key]: Value}
: {[_ in Key]: Value};
/**
Returns a boolean for whether the given type is a plain key-value object.
*/
export type IsPlainObject<T> =
T extends NonRecursiveType | UnknownArray | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
? false
: T extends object
? true
: false;
/**
Extract the object field type if T is an object and K is a key of T, return `never` otherwise.
It creates a type-safe way to access the member type of `unknown` type.
*/
export type ObjectValue<T, K> =
K extends keyof T
? T[K]
: ToString<K> extends keyof T
? T[ToString<K>]
: K extends `${infer NumberK extends number}`
? NumberK extends keyof T
? T[NumberK]
: never
: never;
/**
For an object T, if it has any properties that are a union with `undefined`, make those into optional properties instead.
@example
```
type User = {
firstName: string;
lastName: string | undefined;
};
type OptionalizedUser = UndefinedToOptional<User>;
//=> {
// firstName: string;
// lastName?: string;
// }
```
*/
export type UndefinedToOptional<T extends object> = Simplify<
{
// Property is not a union with `undefined`, keep it as-is.
[Key in keyof Pick<T, FilterDefinedKeys<T>>]: T[Key];
} & {
// Property _is_ a union with defined value. Set as optional (via `?`) and remove `undefined` from the union.
[Key in keyof Pick<T, FilterOptionalKeys<T>>]?: Exclude<T[Key], undefined>;
}
>;
/**
Works similar to the built-in `Pick` utility type, except for the following differences:
- Distributes over union types and allows picking keys from any member of the union type.
- Primitives types are returned as-is.
- Picks all keys if `Keys` is `any`.
- Doesn't pick `number` from a `string` index signature.
@example
```
type ImageUpload = {
url: string;
size: number;
thumbnailUrl: string;
};
type VideoUpload = {
url: string;
duration: number;
encodingFormat: string;
};
// Distributes over union types and allows picking keys from any member of the union type
type MediaDisplay = HomomorphicPick<ImageUpload | VideoUpload, "url" | "size" | "duration">;
//=> {url: string; size: number} | {url: string; duration: number}
// Primitive types are returned as-is
type Primitive = HomomorphicPick<string | number, 'toUpperCase' | 'toString'>;
//=> string | number
// Picks all keys if `Keys` is `any`
type Any = HomomorphicPick<{a: 1; b: 2} | {c: 3}, any>;
//=> {a: 1; b: 2} | {c: 3}
// Doesn't pick `number` from a `string` index signature
type IndexSignature = HomomorphicPick<{[k: string]: unknown}, number>;
//=> {}
*/
export type HomomorphicPick<T, Keys extends KeysOfUnion<T>> = {
[P in keyof T as Extract<P, Keys>]: T[P]
};
/**
Extract all possible values for a given key from a union of object types.
@example
```
type Statuses = ValueOfUnion<{ id: 1, status: "open" } | { id: 2, status: "closed" }, "status">;
//=> "open" | "closed"
```
*/
export type ValueOfUnion<Union, Key extends KeysOfUnion<Union>> =
Union extends unknown ? Key extends keyof Union ? Union[Key] : never : never;
/**
Extract all readonly keys from a union of object types.
@example
```
type User = {
readonly id: string;
name: string;
};
type Post = {
readonly id: string;
readonly author: string;
body: string;
};
type ReadonlyKeys = ReadonlyKeysOfUnion<User | Post>;
//=> "id" | "author"
```
*/
export type ReadonlyKeysOfUnion<Union> = Union extends unknown ? keyof {
[Key in keyof Union as IsEqual<{[K in Key]: Union[Key]}, {readonly [K in Key]: Union[Key]}> extends true ? Key : never]: never
} : never;
/**
Merges user specified options with default options.
@example
```
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false};
type SpecifiedOptions = {leavesOnly: true};
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
//=> {maxRecursionDepth: 10; leavesOnly: true}
```
@example
```
// Complains if default values are not provided for optional options
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
type DefaultPathsOptions = {maxRecursionDepth: 10};
type SpecifiedOptions = {};
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
// ~~~~~~~~~~~~~~~~~~~
// Property 'leavesOnly' is missing in type 'DefaultPathsOptions' but required in type '{ maxRecursionDepth: number; leavesOnly: boolean; }'.
```
@example
```
// Complains if an option's default type does not conform to the expected type
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: 'no'};
type SpecifiedOptions = {};
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
// ~~~~~~~~~~~~~~~~~~~
// Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'.
```
@example
```
// Complains if an option's specified type does not conform to the expected type
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false};
type SpecifiedOptions = {leavesOnly: 'yes'};
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
// ~~~~~~~~~~~~~~~~
// Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'.
```
*/
export type ApplyDefaultOptions<
Options extends object,
Defaults extends Simplify<Omit<Required<Options>, RequiredKeysOf<Options>> & Partial<Record<RequiredKeysOf<Options>, never>>>,
SpecifiedOptions extends Options,
> =
IfAny<SpecifiedOptions, Defaults,
IfNever<SpecifiedOptions, Defaults,
Simplify<Merge<Defaults, {
[Key in keyof SpecifiedOptions
as Key extends OptionalKeysOf<Options>
? Extract<SpecifiedOptions[Key], undefined> extends never
? Key
: never
: Key
]: SpecifiedOptions[Key]
}> & Required<Options>> // `& Required<Options>` ensures that `ApplyDefaultOptions<SomeOption, ...>` is always assignable to `Required<SomeOption>`
>>;

View File

@@ -0,0 +1,210 @@
import type {NegativeInfinity, PositiveInfinity} from '../numeric';
import type {Trim} from '../trim';
import type {Whitespace} from './characters';
import type {BuildTuple} from './tuple';
/**
Return a string representation of the given string or number.
Note: This type is not the return type of the `.toString()` function.
*/
export type ToString<T> = T extends string | number ? `${T}` : never;
/**
Converts a numeric string to a number.
@example
```
type PositiveInt = StringToNumber<'1234'>;
//=> 1234
type NegativeInt = StringToNumber<'-1234'>;
//=> -1234
type PositiveFloat = StringToNumber<'1234.56'>;
//=> 1234.56
type NegativeFloat = StringToNumber<'-1234.56'>;
//=> -1234.56
type PositiveInfinity = StringToNumber<'Infinity'>;
//=> Infinity
type NegativeInfinity = StringToNumber<'-Infinity'>;
//=> -Infinity
```
@category String
@category Numeric
@category Template literal
*/
export type StringToNumber<S extends string> = S extends `${infer N extends number}`
? N
: S extends 'Infinity'
? PositiveInfinity
: S extends '-Infinity'
? NegativeInfinity
: never;
/**
Returns a boolean for whether the given string `S` starts with the given string `SearchString`.
@example
```
StartsWith<'abcde', 'abc'>;
//=> true
StartsWith<'abcde', 'bc'>;
//=> false
StartsWith<string, 'bc'>;
//=> never
StartsWith<'abcde', string>;
//=> never
```
@category String
@category Template literal
*/
export type StartsWith<S extends string, SearchString extends string> = string extends S | SearchString
? never
: S extends `${SearchString}${infer T}`
? true
: false;
/**
Returns an array of the characters of the string.
@example
```
StringToArray<'abcde'>;
//=> ['a', 'b', 'c', 'd', 'e']
StringToArray<string>;
//=> never
```
@category String
*/
export type StringToArray<S extends string, Result extends string[] = []> = string extends S
? never
: S extends `${infer F}${infer R}`
? StringToArray<R, [...Result, F]>
: Result;
/**
Returns the length of the given string.
@example
```
StringLength<'abcde'>;
//=> 5
StringLength<string>;
//=> never
```
@category String
@category Template literal
*/
export type StringLength<S extends string> = string extends S
? never
: StringToArray<S>['length'];
/**
Returns a boolean for whether the string is lowercased.
*/
export type IsLowerCase<T extends string> = T extends Lowercase<T> ? true : false;
/**
Returns a boolean for whether the string is uppercased.
*/
export type IsUpperCase<T extends string> = T extends Uppercase<T> ? true : false;
/**
Returns a boolean for whether a string is whitespace.
*/
export type IsWhitespace<T extends string> = T extends Whitespace
? true
: T extends `${Whitespace}${infer Rest}`
? IsWhitespace<Rest>
: false;
/**
Returns a boolean for whether the string is numeric.
This type is a workaround for [Microsoft/TypeScript#46109](https://github.com/microsoft/TypeScript/issues/46109#issuecomment-930307987).
*/
export type IsNumeric<T extends string> = T extends `${number}`
? Trim<T> extends T
? true
: false
: false;
/**
Returns a boolean for whether `A` represents a number greater than `B`, where `A` and `B` are both numeric strings and have the same length.
@example
```
SameLengthPositiveNumericStringGt<'50', '10'>;
//=> true
SameLengthPositiveNumericStringGt<'10', '10'>;
//=> false
```
*/
type SameLengthPositiveNumericStringGt<A extends string, B extends string> = A extends `${infer FirstA}${infer RestA}`
? B extends `${infer FirstB}${infer RestB}`
? FirstA extends FirstB
? SameLengthPositiveNumericStringGt<RestA, RestB>
: PositiveNumericCharacterGt<FirstA, FirstB>
: never
: false;
type NumericString = '0123456789';
/**
Returns a boolean for whether `A` is greater than `B`, where `A` and `B` are both positive numeric strings.
@example
```
PositiveNumericStringGt<'500', '1'>;
//=> true
PositiveNumericStringGt<'1', '1'>;
//=> false
PositiveNumericStringGt<'1', '500'>;
//=> false
```
*/
export type PositiveNumericStringGt<A extends string, B extends string> = A extends B
? false
: [BuildTuple<StringLength<A>, 0>, BuildTuple<StringLength<B>, 0>] extends infer R extends [readonly unknown[], readonly unknown[]]
? R[0] extends [...R[1], ...infer Remain extends readonly unknown[]]
? 0 extends Remain['length']
? SameLengthPositiveNumericStringGt<A, B>
: true
: false
: never;
/**
Returns a boolean for whether `A` represents a number greater than `B`, where `A` and `B` are both positive numeric characters.
@example
```
PositiveNumericCharacterGt<'5', '1'>;
//=> true
PositiveNumericCharacterGt<'1', '1'>;
//=> false
```
*/
type PositiveNumericCharacterGt<A extends string, B extends string> = NumericString extends `${infer HeadA}${A}${infer TailA}`
? NumericString extends `${infer HeadB}${B}${infer TailB}`
? HeadA extends `${HeadB}${infer _}${infer __}`
? true
: false
: never
: never;

View File

@@ -0,0 +1,90 @@
import type {GreaterThan} from '../greater-than';
import type {LessThan} from '../less-than';
import type {NegativeInfinity, PositiveInfinity} from '../numeric';
import type {UnknownArray} from '../unknown-array';
/**
Infer the length of the given tuple `<T>`.
Returns `never` if the given type is an non-fixed-length array like `Array<string>`.
@example
```
type Tuple = TupleLength<[string, number, boolean]>;
//=> 3
type Array = TupleLength<string[]>;
//=> never
// Supports union types.
type Union = TupleLength<[] | [1, 2, 3] | Array<number>>;
//=> 1 | 3
```
*/
export type TupleLength<T extends UnknownArray> =
// `extends unknown` is used to convert `T` (if `T` is a union type) to
// a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types))
T extends unknown
? number extends T['length']
? never // Return never if the given type is an non-flexed-length array like `Array<string>`
: T['length']
: never; // Should never happen
/**
Create a tuple type of the given length `<L>` and fill it with the given type `<Fill>`.
If `<Fill>` is not provided, it will default to `unknown`.
@link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
*/
export type BuildTuple<L extends number, Fill = unknown, T extends readonly unknown[] = []> = number extends L
? Fill[]
: L extends T['length']
? T
: BuildTuple<L, Fill, [...T, Fill]>;
/**
Returns the maximum value from a tuple of integers.
Note:
- Float numbers are not supported.
@example
```
ArrayMax<[1, 2, 5, 3]>;
//=> 5
ArrayMax<[1, 2, 5, 3, 99, -1]>;
//=> 99
```
*/
export type TupleMax<A extends number[], Result extends number = NegativeInfinity> = number extends A[number]
? never :
A extends [infer F extends number, ...infer R extends number[]]
? GreaterThan<F, Result> extends true
? TupleMax<R, F>
: TupleMax<R, Result>
: Result;
/**
Returns the minimum value from a tuple of integers.
Note:
- Float numbers are not supported.
@example
```
ArrayMin<[1, 2, 5, 3]>;
//=> 1
ArrayMin<[1, 2, 5, 3, -5]>;
//=> -5
```
*/
export type TupleMin<A extends number[], Result extends number = PositiveInfinity> = number extends A[number]
? never
: A extends [infer F extends number, ...infer R extends number[]]
? LessThan<F, Result> extends true
? TupleMin<R, F>
: TupleMin<R, Result>
: Result;

View File

@@ -0,0 +1,139 @@
import type {IsAny} from '../is-any';
import type {IsNever} from '../is-never';
import type {Primitive} from '../primitive';
/**
Matches any primitive, `void`, `Date`, or `RegExp` value.
*/
export type BuiltIns = Primitive | void | Date | RegExp;
/**
Matches non-recursive types.
*/
export type NonRecursiveType = BuiltIns | Function | (new (...arguments_: any[]) => unknown);
/**
Returns a boolean for whether the two given types extends the base type.
*/
export type IsBothExtends<BaseType, FirstType, SecondType> = FirstType extends BaseType
? SecondType extends BaseType
? true
: false
: false;
/**
Test if the given function has multiple call signatures.
Needed to handle the case of a single call signature with properties.
Multiple call signatures cannot currently be supported due to a TypeScript limitation.
@see https://github.com/microsoft/TypeScript/issues/29732
*/
export type HasMultipleCallSignatures<T extends (...arguments_: any[]) => unknown> =
T extends {(...arguments_: infer A): unknown; (...arguments_: infer B): unknown}
? B extends A
? A extends B
? false
: true
: true
: false;
/**
Returns a boolean for whether the given `boolean` is not `false`.
*/
export type IsNotFalse<T extends boolean> = [T] extends [false] ? false : true;
/**
Returns a boolean for whether the given type is primitive value or primitive type.
@example
```
IsPrimitive<'string'>
//=> true
IsPrimitive<string>
//=> true
IsPrimitive<Object>
//=> false
```
*/
export type IsPrimitive<T> = [T] extends [Primitive] ? true : false;
/**
Returns a boolean for whether A is false.
@example
```
Not<true>;
//=> false
Not<false>;
//=> true
```
*/
export type Not<A extends boolean> = A extends true
? false
: A extends false
? true
: never;
/**
Returns a boolean for whether the given type is a union type.
@example
```
type A = IsUnion<string | number>;
//=> true
type B = IsUnion<string>;
//=> false
```
*/
export type IsUnion<T> = InternalIsUnion<T>;
/**
The actual implementation of `IsUnion`.
*/
type InternalIsUnion<T, U = T> =
(
// @link https://ghaiklor.github.io/type-challenges-solutions/en/medium-isunion.html
IsNever<T> extends true
? false
: T extends any
? [U] extends [T]
? false
: true
: never
) extends infer Result
// In some cases `Result` will return `false | true` which is `boolean`,
// that means `T` has at least two types and it's a union type,
// so we will return `true` instead of `boolean`.
? boolean extends Result ? true
: Result
: never; // Should never happen
/**
An if-else-like type that resolves depending on whether the given type is `any` or `never`.
@example
```
// When `T` is a NOT `any` or `never` (like `string`) => Returns `IfNotAnyOrNever` branch
type A = IfNotAnyOrNever<string, 'VALID', 'IS_ANY', 'IS_NEVER'>;
//=> 'VALID'
// When `T` is `any` => Returns `IfAny` branch
type B = IfNotAnyOrNever<any, 'VALID', 'IS_ANY', 'IS_NEVER'>;
//=> 'IS_ANY'
// When `T` is `never` => Returns `IfNever` branch
type C = IfNotAnyOrNever<never, 'VALID', 'IS_ANY', 'IS_NEVER'>;
//=> 'IS_NEVER'
```
*/
export type IfNotAnyOrNever<T, IfNotAnyOrNever, IfAny = any, IfNever = never> =
IsAny<T> extends true
? IfAny
: IsNever<T> extends true
? IfNever
: IfNotAnyOrNever;

Some files were not shown because too many files have changed in this diff Show More