unix-permissions
Version:
Swiss Army knife for Unix permissions
569 lines (537 loc) • 17.8 kB
TypeScript
/**
* Permission type used by [`chmod`](https://linux.die.net/man/1/chmod).
*
* Octal string where each digit represents a user class: `user`, `group` and
* `others`.
* Each digit's is a [bitfield](https://en.wikipedia.org/wiki/Bit_field)
* representing `read`, `write` and `execute`. Special permissions
* ([setuid](https://en.wikipedia.org/wiki/Setuid),
* [setgid](https://en.wikipedia.org/wiki/Setuid),
* [sticky](https://en.wikipedia.org/wiki/Sticky_bit)) can optionally be specified
* by prepending another digit.
*
* An operator can be prepended:
* - `=` (default): unset omitted permissions
* - `+`: leave omitted permissions as is
* - `-`: unset specified permissions
*
* @example
* ```js
* console.log(convert.stat('720')) // 'rwx-w----'
* console.log(convert.stat('7000')) // '--S--S--T'
* console.log(convert.stat('\\720')) // 'rwx-w----'
* console.log(convert.stat('0720')) // 'rwx-w----'
* console.log(convert.stat('0o720')) // 'rwx-w----'
* console.log(convert.symbolic('+720')) // 'u+rwx,g+w'
* console.log(convert.symbolic('-720')) // 'u-rwx,g-w'
* console.log(convert.symbolic('=720')) // 'u=rwx,g=w,o='
* ```
*/
export type PermissionOctal =
| `${OctalStart}${OctalDigit}`
| `${OctalStart}${OctalDigit}${OctalDigit}`
| `${OctalStart}${OctalDigit}${OctalDigit}${OctalDigit}`
| `${OctalStart}${OctalDigit}${OctalDigit}${OctalDigit}${OctalDigit}`
type OctalDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7'
type OctalPrefix = '' | '0o' | '0' | '\\'
type OctalOperator = '' | '=' | '+' | '-'
type OctalStart = `${OctalOperator}${OctalPrefix}`
/**
* Permission type used by Node.js
* [`fs.chmod()`](https://nodejs.org/api/fs.html#fs_fs_chmod_path_mode_callback).
*
* It is the same as `octal` except:
* - as a decimal number.
* - no operator can be used.
* - it can be used as input in [JavaScript](../README.md#usage-javascript) but
* not on the [command line](../README.md#usage-cli), where all numbers
* should be in [`octal`](#octal) form instead.
*
* @example
* ```js
* console.log(convert.stat(0)) // '---------'
* console.log(convert.stat(1)) // '--------x'
* console.log(convert.stat(3)) // '-------wx'
* console.log(convert.stat(8)) // '-----x---'
* console.log(convert.stat(512)) // '--------T'
* ```
*/
export type PermissionNumber = number
/**
* Permission type used by [`stat`](https://linux.die.net/man/2/stat) and
* [`ls`](https://linux.die.net/man/1/ls).
*
* It is a string where each character represents either the permission
* (`r`, `w`, `x`) or no permission (`-`). The special permission are indicated
* with `S`, `s`, `T` and `t` where lowercase implies `x` is also present.
*
* Optionally a first character can be specified to indicate the file type
* (e.g. `d` for directories).
*
* @example
* ```js
* console.log(convert.octal('--------x')) // '0001'
* console.log(convert.octal('--x--x--x')) // '0111'
* console.log(convert.octal('--------T')) // '1000'
* console.log(convert.octal('--------t')) // '1001'
* console.log(convert.octal('d--------x')) // '0001'
* console.log(convert.octal('--x --x --x')) // '0111'
* console.log(convert.octal('rwx --- ---')) // '0700'
* console.log(convert.octal('xwr --- ---')) // '0700'
* ```
*/
export type PermissionStat =
`${string}${PermissionStatOthersBit}${PermissionStatOthersBit}${PermissionStatOthersBit}`
type PermissionStatOthersBit = '-' | 'r' | 'w' | 'x' | 'X' | 't' | 'T'
/**
* Permission type used by [`chmod`](https://linux.die.net/man/1/chmod) as a
* string like `gu+rx`.
*
* Starts with the user class (`a` for all, `u` for user, `g` for group, `o` for
* others) then the operator (`+`, `-` or `=`) and ends with the permissions
* characters.
*
* While `+` leaves the omitted permissions as is, `=` unsets them. For example
* `o=x` is the same as combining `o+x` and `o-rwt`.
*
* Several groups can be specified using a comma-separated list like `g+x,o+r`.
*
* User classes can be concatenated like `go+x`.
*
* @example
* ```js
* console.log(convert.octal('o+wx')) // '+0003'
* console.log(convert.octal('o=wx')) // '0003'
* console.log(convert.octal('o-wx')) // '-0003'
* console.log(convert.octal('go+x')) // '+0011'
* console.log(convert.octal('g+x,o+x')) // '+0011'
* console.log(convert.octal('a+x')) // '+0111'
* console.log(convert.octal('+x')) // '+0111'
* console.log(convert.octal('a+s')) // '+6000'
* console.log(convert.octal('o+')) // '+0000'
* ```
*/
export type PermissionSymbolic =
| `${PermissionSymbolicSingle}`
| `${string},${PermissionSymbolicSingle}`
type PermissionSymbolicSingle =
`${PermissionSymbolicClasses}${PermissionSymbolicOperator}${PermissionSymbolicActions}`
type PermissionSymbolicClass = 'a' | 'u' | 'g' | 'o'
type PermissionSymbolicClasses = '' | `${string}${PermissionSymbolicClass}`
type PermissionSymbolicOperator = '+' | '=' | '-'
type PermissionSymbolicAction = 'x' | 'w' | 'r' | 'X' | 's' | 't'
type PermissionSymbolicActions = '' | `${string}${PermissionSymbolicAction}`
/**
* Permission type as an object.
* `undefined` leaves permissions as is while `false` unsets them.
*
* @example
* ```js
* console.log(convert.symbolic({ others: { read: true, execute: true } }))
* // 'o+rx'
*
* console.log(convert.symbolic({ others: { read: true, execute: false } }))
* // 'o+r,o-x'
*
* console.log(convert.symbolic({ others: { read: true, execute: undefined } }))
* // 'o+r'
*
* console.log(convert.symbolic({ all: { read: true } }))
* // 'a+r'
*
* console.log(convert.symbolic({}))
* // 'a+'
*
* console.log(
* convert.symbolic({ special: { setuid: true, setgid: true, sticky: true } }),
* )
* // 'ug+s,o+t'
* ```
*/
export type PermissionObject = Partial<{
user: PermissionObjectClass
group: PermissionObjectClass
others: PermissionObjectClass
all: PermissionObjectClass
special: PermissionObjectSpecial
}>
type PermissionObjectClass = Partial<{
read: PermissionObjectValue
write: PermissionObjectValue
execute: PermissionObjectValue
}>
type PermissionObjectSpecial = Partial<{
setuid: PermissionObjectValue
setgid: PermissionObjectValue
sticky: PermissionObjectValue
}>
type PermissionObjectValue = boolean | undefined
/**
* Permissions of a file for:
* - Each user class (user, group, others)
* - Each file operation (read, write, execute), including special operations
* (setuid, setgid, sticky)
*/
export type Permission =
| PermissionOctal
| PermissionNumber
| PermissionStat
| PermissionSymbolic
| PermissionObject
/**
* Type of permission format.
*/
export type PermissionType = 'octal' | 'number' | 'stat' | 'symbolic' | 'object'
export declare const convert: {
/**
* Returns `permission` converted to the octal type.
*
* @example
* ```js
* convert.octal('a+x') // '+0111'
*
* try {
* convert.octal('z+x') // Throws an exception (permission syntax is invalid)
* } catch (error) {
* console.log(error.message)
* }
* ```
*/
octal: (permission: Permission) => PermissionOctal
/**
* Returns `permission` converted to the number type.
*
* @example
* ```js
* convert.number('a+x') // 0o111
*
* try {
* convert.number('z+x') // Throws an exception (permission syntax is invalid)
* } catch (error) {
* console.log(error.message)
* }
* ```
*/
number: (permission: Permission) => PermissionNumber
/**
* Returns `permission` converted to the stat type.
*
* @example
* ```js
* convert.stat('a+x') // '--x--x--x'
*
* try {
* convert.stat('z+x') // Throws an exception (permission syntax is invalid)
* } catch (error) {
* console.log(error.message)
* }
* ```
*/
stat: (permission: Permission) => PermissionStat
/**
* Returns `permission` converted to the symbolic type.
*
* @example
* ```js
* convert.symbolic('--x--x--x') // 'a=x'
*
* try {
* convert.symbolic('--o--o--o') // Throws an exception (permission syntax is invalid)
* } catch (error) {
* console.log(error.message)
* }
* ```
*/
symbolic: (permission: Permission) => PermissionSymbolic
/**
* Returns `permission` converted to the object type.
*
* @example
* ```js
* convert.object('a+x')
* // {
* // user: { execute: true },
* // group: { execute: true },
* // others: { execute: true }
* // }
*
* try {
* convert.object('z+x') // Throws an exception (permission syntax is invalid)
* } catch (error) {
* console.log(error.message)
* }
* ```
*/
object: (permission: Permission) => PermissionObject
}
/**
* Returns the `permission`'s `type` or `'invalid'`.
*
* @example
* ```js
* console.log(type('1')) // 'octal'
* console.log(type(1)) // 'number'
* console.log(type('a+x')) // 'symbolic'
* console.log(type('a+i')) // 'invalid'
* ```
*/
export function type(permission: Permission): PermissionType
export function type(permission: unknown): 'invalid'
/**
* Normalizes a `permission` to its canonical shape.
* Throws an exception if `permission` is invalid.
*
* @example
* ```js
* console.log(normalize('1')) // '0001'
* console.log(normalize('g+x,o+x')) // 'go+x'
* console.log(normalize('d--- --- ---')) // '---------'
* console.log(normalize({ user: { read: undefined, write: true } }))
* // { user: { write: true } }
*
* try {
* normalize('z+x') // Throws an exception (permission syntax is invalid)
* } catch (error) {
* console.log(error.message)
* }
* ```
*/
export function normalize(permission: PermissionOctal): PermissionOctal
export function normalize(permission: PermissionNumber): PermissionNumber
export function normalize(permission: PermissionStat): PermissionStat
export function normalize(permission: PermissionSymbolic): PermissionSymbolic
export function normalize(permission: PermissionObject): PermissionObject
export function normalize(permission: unknown): never
/**
* Removes all negative permissions.
*
* @example
* ```js
* console.log(positive('o+x,o-rw')) // 'o+x'
* console.log(positive('o=x')) // 'o+x'
* console.log(positive('660')) // '+0660'
* console.log(invert('660')) // '0117'
* console.log(invert(positive('660'))) // '-0660'
* ```
*/
export function positive(permission: PermissionOctal): PermissionOctal
export function positive(permission: PermissionNumber): PermissionNumber
export function positive(permission: PermissionStat): PermissionStat
export function positive(permission: PermissionSymbolic): PermissionSymbolic
export function positive(permission: PermissionObject): PermissionObject
export function positive(permission: unknown): never
/**
* Tests whether `permission` includes `permissions`.
*
* @example
* ```js
* console.log(contain('--x--x--x', 'a=x')) // `true`
* console.log(contain('--x--x--x', 'a+x')) // `true`
* console.log(contain('--x--x--x', 'a-x')) // `false`
* console.log(contain('--x--x--x', 'a-w')) // `true`
* console.log(contain('o+x', 'o+x')) // `true`
* console.log(contain('o+x', 'o+x,o+x')) // `true`
* console.log(contain('o+x', 'o=w')) // `false`
* console.log(contain('o+x,o-w', 'o-w,o+x')) // `true`
* console.log(contain('o+x,o-w', 'o-w')) // `true`
* console.log(contain('o+x,o-w', 'o+x', 'o-w')) // `true`
* ```
*/
export function contain(
permission: Permission,
containedPermission: Permission,
...alsoContainedPermissions: Permission[]
): boolean
/**
* Tests whether `permission` equals exactly `permissions`.
*
* @example
* ```js
* console.log(equal('--x--x--x', 'a=x')) // `true`
* console.log(equal('--x--x--x', 'a+x')) // `false`
* console.log(equal('--x--x--x', 'a-x')) // `false`
* console.log(equal('--x--x--x', 'a-w')) // `false`
* console.log(equal('o+x', 'o+x')) // `true`
* console.log(equal('o+x', 'o+x,o+x')) // `true`
* console.log(equal('o+x', 'o=w')) // `false`
* console.log(equal('o+x,o-w', 'o-w,o+x')) // `true`
* console.log(equal('o+x,o-w', 'o-w')) // `false`
* console.log(equal('o+x,o-w', 'o+x', 'o-w')) // `false`
* ```
*/
export function equal(
permission: Permission,
equaledPermission: Permission,
...alsoEqualedPermissions: Permission[]
): boolean
/**
* Returns the result of setting `permissions` on `permission`.
* This is useful to avoid error-prone bitwise operations (`|`, `&`, `^`, `~`).
* This can also be used to remove special permissions using
* `set(permission, 'a-st')` since some functions like
* [`umask`](https://linux.die.net/man/2/umask) do not allow them.
*
* @example
* ```js
* console.log(set('---------', 'a+x')) // '--x--x--x'
* console.log(set('---------', 'a+x', 'a+r')) // 'r-xr-xr-x'
* console.log(set('--x--x--x', 'o-x')) // '--x--x---'
* console.log(set('a+x', 'a+r')) // 'a+rx'
* console.log(set('4660', 'a-st')) // '0660'
* ```
*/
export function set(
permission: PermissionOctal,
setPermission: Permission,
...alsoSetPermissions: Permission[]
): PermissionOctal
export function set(
permission: PermissionNumber,
setPermission: Permission,
...alsoSetPermissions: Permission[]
): PermissionNumber
export function set(
permission: PermissionStat,
setPermission: Permission,
...alsoSetPermissions: Permission[]
): PermissionStat
export function set(
permission: PermissionSymbolic,
setPermission: Permission,
...alsoSetPermissions: Permission[]
): PermissionSymbolic
export function set(
permission: PermissionObject,
setPermission: Permission,
...alsoSetPermissions: Permission[]
): PermissionObject
export function set(
permission: unknown,
setPermission: Permission,
...alsoSetPermissions: Permission[]
): never
/**
* Inverts `permission` including special permissions.
* This can be used in combination with `set()` to unset `permissions` instead
* of setting them.
*
* @example
* ```js
* console.log(not('u+xs')) // 'u-xs'
* console.log(not('u-xs')) // 'u+xs'
* console.log(not('u=x')) // 'u=rws'
* console.log(not('a=x')) // 'ug=rws,o=rwt'
* console.log(not('rws-ws-w-')) // '---r--r-t'
* console.log(not('0660')) // '7117'
* console.log(not('1660')) // '6117'
* console.log(set('rwxrwxrwx', not('a+x'))) // 'rw-rw-rw-'
* console.log(set('---------', not('a-x'))) // '--x--x--x'
* console.log(set('a+xr', not('a+r'))) // 'a+x,a-r'
* ```
*/
export function not(permission: PermissionOctal): PermissionOctal
export function not(permission: PermissionNumber): PermissionNumber
export function not(permission: PermissionStat): PermissionStat
export function not(permission: PermissionSymbolic): PermissionSymbolic
export function not(permission: PermissionObject): PermissionObject
export function not(permission: unknown): never
/**
* Inverts `permission` and removes special permissions.
* For example a [`umask`](https://linux.die.net/man/2/umask) of `117` means new
* files will be created with `661` permissions.
*
* @example
* ```js
* console.log(invert('u+xs')) // 'u-x'
* console.log(invert('u-xs')) // 'u+x'
* console.log(invert('u=x')) // 'u+rw,u-x'
* console.log(invert('a=x')) // 'a+rw,a-x'
* console.log(invert('rws-ws-w-')) // '---r--r-x'
* console.log(invert('0660')) // '0117'
* console.log(invert('1660')) // '0117'
* ```
*/
export function invert(permission: PermissionOctal): PermissionOctal
export function invert(permission: PermissionNumber): PermissionNumber
export function invert(permission: PermissionStat): PermissionStat
export function invert(permission: PermissionSymbolic): PermissionSymbolic
export function invert(permission: PermissionObject): PermissionObject
export function invert(permission: unknown): never
/**
* Retrieves the lowest permissions among all arguments.
*
* This does not return the lowest argument. Instead it returns a combination of
* the lowest bits of all arguments.
*
* This can be useful if you are looking for the lowest permission of a several
* files, e.g. during a directory recursion.
*
* @example
* ```js
* console.log(min('404', '440', '402')) // '0400'
* ```
*/
export function min(): undefined
export function min(
permission: PermissionOctal,
...otherPermissions: Permission[]
): PermissionOctal
export function min(
permission: PermissionNumber,
...otherPermissions: Permission[]
): PermissionNumber
export function min(
permission: PermissionStat,
...otherPermissions: Permission[]
): PermissionStat
export function min(
permission: PermissionSymbolic,
...otherPermissions: Permission[]
): PermissionSymbolic
export function min(
permission: PermissionObject,
...otherPermissions: Permission[]
): PermissionObject
export function min(
permission: unknown,
...otherPermissions: Permission[]
): never
/**
* Retrieves the highest permissions among all arguments.
*
* This does not return the highest argument. Instead it returns a combination
* of the highest bits of all arguments.
*
* This can be useful if you are looking for the highest permission of a several
* files, e.g. during a directory recursion.
*
* @example
* ```js
* console.log(max('404', '440', '402')) // '04446'
* ```
*/
export function max(): undefined
export function max(
permission: PermissionOctal,
...otherPermissions: Permission[]
): PermissionOctal
export function max(
permission: PermissionNumber,
...otherPermissions: Permission[]
): PermissionNumber
export function max(
permission: PermissionStat,
...otherPermissions: Permission[]
): PermissionStat
export function max(
permission: PermissionSymbolic,
...otherPermissions: Permission[]
): PermissionSymbolic
export function max(
permission: PermissionObject,
...otherPermissions: Permission[]
): PermissionObject
export function max(
permission: unknown,
...otherPermissions: Permission[]
): never