From 587e89086398aba1affad53129b1d7801bba1e03 Mon Sep 17 00:00:00 2001 From: Lexus Drumgold Date: Sat, 21 Sep 2024 20:46:16 -0400 Subject: [PATCH] feat(lib): `extnames` Signed-off-by: Lexus Drumgold --- .dictionary.txt | 1 + README.md | 1 + src/__snapshots__/index.e2e.snap | 1 + src/interfaces/pathe.ts | 13 +++++++ src/lib/__snapshots__/extnames.snap | 36 ++++++++++++++++++ src/lib/__tests__/extnames.spec.ts | 21 +++++++++++ src/lib/extnames.ts | 57 +++++++++++++++++++++++++++++ src/lib/index.ts | 1 + src/pathe.ts | 2 + 9 files changed, 133 insertions(+) create mode 100644 src/lib/__snapshots__/extnames.snap create mode 100644 src/lib/__tests__/extnames.spec.ts create mode 100644 src/lib/extnames.ts diff --git a/.dictionary.txt b/.dictionary.txt index 746fc476..132e17ac 100644 --- a/.dictionary.txt +++ b/.dictionary.txt @@ -28,6 +28,7 @@ pathe pkgs posix preid +remarkrc shfmt tscu unstub diff --git a/README.md b/README.md index a4d71e3c..161be436 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ This package exports the following identifiers: - [`dirname`](./src/lib/dirname.ts) - [`dot`](./src/lib/dot.ts) - [`extname`](./src/lib/extname.ts) +- [`extnames`](./src/lib/extnames.ts) - [`formatExt`](./src/lib/format-ext.ts) - [`format`](./src/lib/format.ts) - [`isAbsolute`](./src/lib/is-absolute.ts) diff --git a/src/__snapshots__/index.e2e.snap b/src/__snapshots__/index.e2e.snap index 96ea2583..dbade033 100644 --- a/src/__snapshots__/index.e2e.snap +++ b/src/__snapshots__/index.e2e.snap @@ -10,6 +10,7 @@ exports[`e2e:pathe > should expose public api 1`] = ` "dirname", "dot", "extname", + "extnames", "format", "formatExt", "isAbsolute", diff --git a/src/interfaces/pathe.ts b/src/interfaces/pathe.ts index 0f89d6b7..d6da15fb 100644 --- a/src/interfaces/pathe.ts +++ b/src/interfaces/pathe.ts @@ -83,6 +83,19 @@ interface Pathe extends PosixPlatformPath { */ formatExt(this: void, ext: string | null | undefined): EmptyString | Ext + /** + * Get a list of file extensions for `path`. + * + * @see {@linkcode Ext} + * @see {@linkcode extname} + * + * @param {string} path + * Path to handle + * @return {Ext[]} + * List of extensions + */ + extnames(path: string): Ext[] + /** * Check if `value` is a device root. * diff --git a/src/lib/__snapshots__/extnames.snap b/src/lib/__snapshots__/extnames.snap new file mode 100644 index 00000000..5e8a67f8 --- /dev/null +++ b/src/lib/__snapshots__/extnames.snap @@ -0,0 +1,36 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`unit:lib/extnames > should return list of extensions ("") 1`] = `[]`; + +exports[`unit:lib/extnames > should return list of extensions (".") 1`] = `[]`; + +exports[`unit:lib/extnames > should return list of extensions (".remarkignore") 1`] = `[]`; + +exports[`unit:lib/extnames > should return list of extensions (".remarkrc.mjs") 1`] = ` +[ + ".mjs", +] +`; + +exports[`unit:lib/extnames > should return list of extensions ("/") 1`] = `[]`; + +exports[`unit:lib/extnames > should return list of extensions ("eslint.base.config.mjs") 1`] = ` +[ + ".base", + ".config", + ".mjs", +] +`; + +exports[`unit:lib/extnames > should return list of extensions ("grease.config.mjs") 1`] = ` +[ + ".config", + ".mjs", +] +`; + +exports[`unit:lib/extnames > should return list of extensions ("src/lib/extnames.ts") 1`] = ` +[ + ".ts", +] +`; diff --git a/src/lib/__tests__/extnames.spec.ts b/src/lib/__tests__/extnames.spec.ts new file mode 100644 index 00000000..4228b425 --- /dev/null +++ b/src/lib/__tests__/extnames.spec.ts @@ -0,0 +1,21 @@ +/** + * @file Unit Tests - extnames + * @module pathe/lib/tests/unit/extnames + */ + +import testSubject from '../extnames' + +describe('unit:lib/extnames', () => { + it.each>([ + [''], + ['.'], + ['.remarkignore'], + ['.remarkrc.mjs'], + ['/'], + ['eslint.base.config.mjs'], + ['grease.config.mjs'], + ['src/lib/extnames.ts'] + ])('should return list of extensions (%j)', path => { + expect(testSubject(path)).toMatchSnapshot() + }) +}) diff --git a/src/lib/extnames.ts b/src/lib/extnames.ts new file mode 100644 index 00000000..ff4e5a53 --- /dev/null +++ b/src/lib/extnames.ts @@ -0,0 +1,57 @@ +/** + * @file extnames + * @module pathe/lib/extnames + */ + +import validateString from '#internal/validate-string' +import type { EmptyString, Ext } from '@flex-development/pathe' +import dot from './dot' +import extname from './extname' +import toPosix from './to-posix' + +/** + * Get a list of file extensions for `path`. + * + * @see {@linkcode Ext} + * @see {@linkcode extname} + * + * @param {string} path + * Path to handle + * @return {Ext[]} + * List of extensions + */ +function extnames(path: string): Ext[] { + validateString(path, 'path') + + /** + * List of extensions. + * + * @const {Ext[]} extensions + */ + const extensions: Ext[] = [] + + /** + * Current path. + * + * @var {string} subpath + */ + let subpath: string = toPosix(path) + + while (subpath.includes(dot)) { + /** + * Current extension. + * + * @const {EmptyString | Ext} ext + */ + const ext: EmptyString | Ext = extname(subpath) + + if (ext === '') break + + extensions.unshift(ext) + subpath = subpath.slice(0, subpath.lastIndexOf(ext)) + } + + return extensions +} + +export default extnames diff --git a/src/lib/index.ts b/src/lib/index.ts index b712f2fc..8cbfd413 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -11,6 +11,7 @@ export { default as delimiter } from './delimiter' export { default as dirname } from './dirname' export { default as dot } from './dot' export { default as extname } from './extname' +export { default as extnames } from './extnames' export { default as format } from './format' export { default as formatExt } from './format-ext' export { default as isAbsolute } from './is-absolute' diff --git a/src/pathe.ts b/src/pathe.ts index e8a2051d..7409117d 100644 --- a/src/pathe.ts +++ b/src/pathe.ts @@ -18,6 +18,7 @@ import { dirname, dot, extname, + extnames, format, formatExt, isAbsolute, @@ -109,6 +110,7 @@ const pathe: Pathe = { dirname, dot, extname, + extnames, format, formatExt, isAbsolute,