{
  "version": 3,
  "sources": ["../Source/Npm/index.ts", "../Source/Npm/Npm.ts", "../Source/Npm/Npm.Error.ts", "../Source/Npm/Npm.Internal.ts"],
  "sourcesContent": ["/**\n * Utilities for working with `npm` (NodeJS) packages.\n * Many of these likely work with packages of other NodeJS\n * package managers and adjacent runtimes (*e.g.*, `bun` or `deno`).\n *\n * @module @sorrell/utilities/npm\n */\n/**\n * @file      index.ts\n * @author    Gage Sorrell <gage@sorrell.sh>\n * @copyright (c) 2026 Gage Sorrell\n * @license   MIT\n */\nexport * from \"./Npm.ts\";\nexport * from \"./Npm.Error.ts\";\n", "/**\n * @file      Npm.ts\n * @author    Gage Sorrell <gage@sorrell.sh>\n * @copyright (c) 2026 Gage Sorrell\n * @license   MIT\n */\nimport { promises as Fs, constants as FsConstants } from \"fs\";\nimport { PackageJsonParseError, RootDirectoryNotFoundError } from \"./Npm.Error.ts\";\nimport { dirname, join } from \"path\";\nimport type { IPackageJson } from \"package-json-type\";\nimport { IsValidDependencyImportSpecifierParts } from \"./Npm.Internal.ts\";\nimport Process from \"process\";\n/**\n * Get the `package.json` of the Node.js project in which the\n * given path, or the current working directory, resides.\n *\n * @param Path - The given path from which to look for a root directory.\n *\n * @throws {RootDirectoryNotFoundError | PackageJsonParseError} An error\n * describing either failure to identify a root directory, or failing to\n * parse the discovered `package.json`.\n *\n * @returns {Promise<IPackageJson>} The {@link IPackageJson} of {@link Path}\n * if provided, otherwise of `process.cwd()`.\n *\n * @example\n * Suppose `process.cwd() === \"./MyPackage\"`,\n * ```typescript\n * const PackageJson: IPackageJson = await GetPackageJson();\n * // `PackageJson` <- *The parsed `package.json` of `MyPackage`.*\n * ```\n */\nexport async function GetPackageJson(Path?: string): Promise<IPackageJson> {\n    const RootDirectory: string = await GetPackageRootDirectory(Path);\n    const PackageJsonPath: string = join(RootDirectory, \"package.json\");\n    const FileContents: string = await Fs.readFile(PackageJsonPath, \"utf-8\");\n    const PackageJson: IPackageJson = await (async (): Promise<IPackageJson> => {\n        try {\n            return JSON.parse(FileContents) as IPackageJson;\n        }\n        catch (Cause: unknown) {\n            throw new PackageJsonParseError({ Cause, Path: PackageJsonPath });\n        }\n    })();\n    return PackageJson;\n}\n/**\n * Get the root directory of the Node.js project in which the\n * current working directory resides.\n *\n * @param Path - The given path from which to look for a root directory.\n *\n * @throws {RootDirectoryNotFoundError} An error iff the root directory\n * of a NodeJS package could not be found.\n *\n * @returns {Promise<string>} The path to the root directory of the package\n * containing {@link Path} if specified, otherwise containing `process.cwd()`.\n *\n * @example\n * Suppose `process.cwd()` is any one of the following,\n *   - `/home/alex/myPackage`,\n *   - `/home/alex/myPackage/src/MyModule`,\n *   - `/home/alex/myPackage/resource/Images`,\n *\n * then,\n *\n * ```typescript\n * const Root: string = await GetPackageRootDirectory();\n * // `Root` <- `\"/home/alex/myPackage\"`\n * ```\n *\n * @example\n * Suppose `TestPath === \"/home/alex/Documents\"` is *not* a NodeJS package root\n * (of course, neither are `/home/alex` or `/home`).  Then,\n *\n * ```typescript\n * const TestPath: string = \"/home/alex/Documents\";\n * let Root: string | undefined = undefined;\n * try\n * {\n *     Root = await GetPackageRootDirectory(TestPath);\n * }\n * catch (Error: unknown)\n * {\n *      // `Error instanceof RootDirectoryNotFound`\n * }\n *\n * // `Root` <- `undefined`\n * ```\n *\n * @example\n * Suppose `process.cwd() === /home/alex/Downloads`, which is *not* a NodeJS package\n * (of course, neither are `/home/alex` or `/home`).  Then,\n *\n * ```typescript\n * let Root: string | undefined = undefined;\n * try\n * {\n *     Root = await GetPackageRootDirectory();\n * }\n * catch (Error: unknown)\n * {\n *      // `Error instanceof RootDirectoryNotFound`\n * }\n * // `Root` <- `undefined`\n * ```\n */\nexport async function GetPackageRootDirectory(Path?: string): Promise<string> {\n    let CurrentDirectory: string = await Fs.realpath(Path ?? Process.cwd());\n    while (true) {\n        const PackageJsonPath: string = join(CurrentDirectory, \"package.json\");\n        const PackageJsonExists: boolean = await (async (): Promise<boolean> => {\n            try {\n                await Fs.access(PackageJsonPath, FsConstants.F_OK);\n                return true;\n            }\n            catch {\n                return false;\n            }\n        })();\n        if (PackageJsonExists) {\n            return CurrentDirectory;\n        }\n        const ParentDirectory: string = dirname(CurrentDirectory);\n        if (ParentDirectory === CurrentDirectory) {\n            throw new RootDirectoryNotFoundError({ Path });\n        }\n        CurrentDirectory = ParentDirectory;\n    }\n}\n/* eslint-disable jsdoc/require-example */\n/**\n * Determine whether a given {@link ImportSpecifier} is valid.  That is, whether\n * it consists of a valid package name, possibly followed by a `/`-delimited path\n * that may be specified by the package's `\"exports\"` property in its `package.json`.\n *\n * @param ImportSpecifier - The `import` specifier `string` to test.\n *\n * @returns {boolean} Whether the given {@link ImportSpecifier} is a valid `string`\n * to use in an `import` statement.\n */\nexport function IsValidDependencyImportSpecifier(ImportSpecifier: string): boolean {\n    if (ImportSpecifier.length === 0) {\n        return false;\n    }\n    if (ImportSpecifier.trim() !== ImportSpecifier) {\n        return false;\n    }\n    if (ImportSpecifier.includes(\"\\\\\")) {\n        return false;\n    }\n    if (ImportSpecifier.startsWith(\".\") || ImportSpecifier.startsWith(\"/\")) {\n        return false;\n    }\n    if (ImportSpecifier.includes(\":\")) {\n        return false;\n    }\n    if (ImportSpecifier.includes(\"//\")) {\n        return false;\n    }\n    const ImportSpecifierParts: ReadonlyArray<string> = ImportSpecifier.split(\"/\");\n    if (ImportSpecifier.startsWith(\"@\")) {\n        return IsValidDependencyImportSpecifierParts(ImportSpecifierParts, true);\n    }\n    return IsValidDependencyImportSpecifierParts(ImportSpecifierParts, false);\n}\n;\n/* eslint-enable jsdoc/require-example */\n", "/**\n * @file      Npm.Error.ts\n * @author    Gage Sorrell <gage@sorrell.sh>\n * @copyright (c) 2026 Gage Sorrell\n * @license   MIT\n */\nimport { Data } from \"effect\";\n/**\n * An error describing that {@link GetPackageJson} failed to parse the discovered `package.json` file.\n *\n * @property {string | undefined} Path - The `Path` argument passed to the effect returning this error,\n * if one was given.\n * @property {unknown} Cause - The cause of this error.\n */\nexport class PackageJsonParseError extends Data.TaggedError(\"PackageJsonParseError\")<{\n    readonly Path: string | undefined;\n    readonly Cause: unknown;\n}> {\n}\n/**\n * An error describing that {@link GetPackageRootDirectory} failed.\n *\n * @property {string | undefined} Path - The `Path` argument passed to the effect returning\n * this error, if one was given.\n */\nexport class RootDirectoryNotFoundError extends Data.TaggedError(\"RootDirectoryNotFound\")<{\n    readonly Path: string | undefined;\n}> {\n}\n", "/**\n * @file      Npm.Internal.ts\n * @author    Gage Sorrell <gage@sorrell.sh>\n * @copyright (c) 2026 Gage Sorrell\n * @license   MIT\n */\n/* eslint-disable jsdoc/require-example */\n/**\n * For a given unscoped package, determine whether the {@link Parts | ordered parts} of\n * a given import specifier of the unscoped package are valid.\n *\n * @param Parts - The parts of the import specifier to test.\n *\n * @param IsScoped - Whether the parts comprise an import specifier of a scoped `npm` package.\n *\n * @returns {boolean} Whether the ordered {@link Parts | import specifier parts} are valid.\n */\nexport function IsValidDependencyImportSpecifierParts(Parts: ReadonlyArray<string>, IsScoped: boolean): boolean {\n    if (IsScoped) {\n        const [ScopeName, PackageName, ...PackageSubpathParts] = Parts;\n        if (ScopeName === undefined || PackageName === undefined) {\n            return false;\n        }\n        if (IsValidScopeName(ScopeName) === false) {\n            return false;\n        }\n        if (IsValidPackageName(PackageName, true) === false) {\n            return false;\n        }\n        return PackageSubpathParts.every(IsValidPackageSubpathPart);\n    }\n    else {\n        const [PackageName, ...PackageSubpathParts] = Parts;\n        if (PackageName === undefined) {\n            return false;\n        }\n        if (IsValidPackageName(PackageName, false) === false) {\n            return false;\n        }\n        return PackageSubpathParts.every(IsValidPackageSubpathPart);\n    }\n}\n;\n/**\n * Determine whether a given {@link PackageName} is valid.\n *\n * @param PackageName - The package name whose validity is tested.\n *\n * @param IsScoped - Whether the given {@link PackageName} should be scoped.\n *\n * @returns {boolean} Whether the given {@link PackageName} is valid.\n */\nfunction IsValidPackageName(PackageName: string, IsScoped: boolean): boolean {\n    if (IsScoped) {\n        if (PackageName.length === 0) {\n            return false;\n        }\n        return IsValidNpmNamePart(PackageName);\n    }\n    else {\n        if (PackageName.length === 0 || PackageName.length > 214) {\n            return false;\n        }\n        if (PackageName.startsWith(\".\") || PackageName.startsWith(\"_\")) {\n            return false;\n        }\n        return IsValidNpmNamePart(PackageName);\n    }\n}\n;\n/**\n * Determine whether the given {@link ScopeName} is valid.\n *\n * @param ScopeName - The scope name to test.\n * @returns {boolean} Whether the given {@link ScopeName} is valid.\n */\nfunction IsValidScopeName(ScopeName: string): boolean {\n    if (ScopeName.length < 2) {\n        return false;\n    }\n    if (ScopeName.startsWith(\"@\") === false) {\n        return false;\n    }\n    return IsValidNpmNamePart(ScopeName.slice(1));\n}\n;\n/**\n * Determine whether the given {@link NamePart | part of an npm package name} is valid.\n *\n * @param NamePart - The name part to test.\n *\n * @returns {boolean} Whether the given {@link NamePart} is valid.\n */\nfunction IsValidNpmNamePart(NamePart: string): boolean {\n    if (NamePart.length === 0) {\n        return false;\n    }\n    if (NamePart !== NamePart.toLowerCase()) {\n        return false;\n    }\n    return /^[a-z0-9._~!$&'()*+,;=-]+$/u.test(NamePart);\n}\n;\n/**\n * Determine whether the given {@link Part | part of an npm package name} is a valid\n * part of a subpath within an `npm` package name.\n *\n * @param Part - The subpath part to test.\n *\n * @returns {boolean} Whether the given {@link NamePart} is valid.\n */\nfunction IsValidPackageSubpathPart(Part: string): boolean {\n    if (Part.length === 0) {\n        return false;\n    }\n    if (Part === \".\" || Part === \"..\") {\n        return false;\n    }\n    return /^[A-Za-z0-9._~!$&'()*+,;=@-]+$/u.test(Part);\n}\n;\n/* eslint-enable jsdoc/require-example */\n"],
  "mappings": "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",
  "names": ["Fs", "Process", "FsConstants"]
}
