@stryke/fs
Version:
A package containing various file system utilities that expand the functionality of NodeJs's built-in `fs` module.
1 lines • 10.2 kB
Source Map (JSON)
{"version":3,"file":"registry.mjs","names":[],"sources":["../src/registry.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { detectPackageManager } from \"@antfu/install-pkg\";\nimport { execSync } from \"node:child_process\";\nimport { parseArgs } from \"node:util\";\nimport { getWorkspaceRoot } from \"./get-workspace-root\";\n\nexport interface NodeOptionsToken {\n kind: \"option\";\n index: number;\n name: string;\n rawName: string;\n value: undefined;\n inlineValue: undefined;\n}\n\nconst parseNodeArgs = (args: string[]) => {\n const { values, tokens } = parseArgs({ args, strict: false, tokens: true });\n\n // For the `NODE_OPTIONS`, we support arguments with values without the `=`\n // sign. We need to parse them manually.\n let orphan: NodeOptionsToken | null | undefined = null;\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i]!;\n\n if (token.kind === \"option-terminator\") {\n break;\n }\n\n // When we encounter an option, if it's value is undefined, we should check\n // to see if the following tokens are positional parameters. If they are,\n // then the option is orphaned, and we can assign it.\n if (token.kind === \"option\") {\n orphan = typeof token.value === \"undefined\" ? token : null;\n continue;\n }\n\n // If the token isn't a positional one, then we can't assign it to the found\n // orphaned option.\n if (token.kind !== \"positional\") {\n orphan = null;\n continue;\n }\n\n // If we don't have an orphan, then we can skip this token.\n if (!orphan) {\n continue;\n }\n\n // If the token is a positional one, and it has a value, so add it to the\n // values object. If it already exists, append it with a space.\n if (orphan.name in values && typeof values[orphan.name] === \"string\") {\n values[orphan.name] += ` ${token.value}`;\n } else {\n values[orphan.name] = token.value;\n }\n }\n\n return values;\n};\n\n/**\n * Tokenizes the arguments string into an array of strings, supporting quoted\n * values and escaped characters.\n * Converted from: https://github.com/nodejs/node/blob/c29d53c5cfc63c5a876084e788d70c9e87bed880/src/node_options.cc#L1401\n *\n * @param input - The arguments string to be tokenized.\n * @returns An array of strings with the tokenized arguments.\n */\nexport const tokenizeArgs = (input: string): string[] => {\n const args: string[] = [];\n let isInString = false;\n let willStartNewArg = true;\n\n for (let i = 0; i < input.length; i++) {\n let char = input[i]!;\n\n // Skip any escaped characters in strings.\n if (char === \"\\\\\" && isInString) {\n // Ensure we don't have an escape character at the end.\n if (input.length === i + 1) {\n throw new Error(\"Invalid escape character at the end.\");\n }\n\n // Skip the next character.\n char = input[++i]!;\n }\n // If we find a space outside of a string, we should start a new argument.\n else if (char === \" \" && !isInString) {\n willStartNewArg = true;\n continue;\n }\n\n // If we find a quote, we should toggle the string flag.\n else if (char === '\"') {\n isInString = !isInString;\n continue;\n }\n\n // If we're starting a new argument, we should add it to the array.\n if (willStartNewArg) {\n args.push(char);\n willStartNewArg = false;\n }\n // Otherwise, add it to the last argument.\n else {\n args[args.length - 1] += char;\n }\n }\n\n if (isInString) {\n throw new Error(\"Unterminated string\");\n }\n\n return args;\n};\n\n/**\n * Get the node options from the environment variable `NODE_OPTIONS` and returns\n * them as an array of strings.\n *\n * @returns An array of strings with the node options.\n */\nconst getNodeOptionsArgs = () => {\n if (!process.env.NODE_OPTIONS) return [];\n\n return tokenizeArgs(process.env.NODE_OPTIONS);\n};\n\n/**\n * Stringify the arguments to be used in a command line. It will ignore any\n * argument that has a value of `undefined`.\n *\n * @param args - The arguments to be stringified.\n * @returns A string with the arguments.\n */\nexport function formatNodeOptions(\n args: Record<string, string | boolean | undefined>\n): string {\n return Object.entries(args)\n .map(([key, value]) => {\n if (value === true) {\n return `--${key}`;\n }\n\n if (value) {\n return `--${key}=${\n // Values with spaces need to be quoted. We use JSON.stringify to\n // also escape any nested quotes.\n value.includes(\" \") && !value.startsWith('\"')\n ? JSON.stringify(value)\n : value\n }`;\n }\n\n return null;\n })\n .filter(arg => arg !== null)\n .join(\" \");\n}\n\n/**\n * Get the node options from the `NODE_OPTIONS` environment variable and parse\n * them into an object without the inspect options.\n *\n * @returns An object with the parsed node options.\n */\nexport function getParsedNodeOptionsWithoutInspect() {\n const args = getNodeOptionsArgs();\n if (args.length === 0) return {};\n\n const parsed = parseNodeArgs(args);\n\n // Remove inspect options.\n delete parsed.inspect;\n delete parsed[\"inspect-brk\"];\n delete parsed.inspect_brk;\n\n return parsed;\n}\n\n/**\n * Get the node options from the `NODE_OPTIONS` environment variable and format\n * them into a string without the inspect options.\n *\n * @returns A string with the formatted node options.\n */\nexport function getFormattedNodeOptionsWithoutInspect() {\n const args = getParsedNodeOptionsWithoutInspect();\n if (Object.keys(args).length === 0) return \"\";\n\n return formatNodeOptions(args);\n}\n\n/**\n * Returns the package registry using the user's package manager. The URL will have a trailing slash.\n *\n * @param baseDir - The base directory to detect the package manager from.\n * @returns The package registry URL with a trailing slash.\n * @throws Will throw an error if the package manager cannot be detected or if the registry cannot be retrieved.\n */\nexport async function getRegistry(baseDir?: string) {\n const workspaceRoot = getWorkspaceRoot(baseDir);\n const pkgManager = await detectPackageManager(workspaceRoot);\n\n // Since `npm config` command fails in npm workspace to prevent workspace config conflicts,\n // add `--no-workspaces` flag to run under the context of the root project only.\n // Safe for non-workspace projects as it's equivalent to default `--workspaces=false`.\n // x-ref: https://github.com/vercel/next.js/issues/47121#issuecomment-1499044345\n // x-ref: https://github.com/npm/statusboard/issues/371#issue-920669998\n const resolvedFlags = pkgManager === \"npm\" ? \"--no-workspaces\" : \"\";\n let registry = `https://registry.npmjs.org/`;\n\n try {\n const output = execSync(\n `${pkgManager} config get registry ${resolvedFlags}`,\n {\n env: {\n ...process.env,\n NODE_OPTIONS: getFormattedNodeOptionsWithoutInspect()\n }\n }\n )\n .toString()\n .trim();\n\n if (output.startsWith(\"http\")) {\n registry = output.endsWith(\"/\") ? output : `${output}/`;\n }\n } catch (err) {\n throw new Error(`Failed to get registry from \"${pkgManager}\".`, {\n cause: err\n });\n }\n\n return registry;\n}\n"],"mappings":";;;;;;AAgCA,MAAM,iBAAiB,SAAmB;CACxC,MAAM,EAAE,QAAQ,WAAW,UAAU;EAAE;EAAM,QAAQ;EAAO,QAAQ;EAAM,CAAC;CAI3E,IAAI,SAA8C;AAClD,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,QAAQ,OAAO;AAErB,MAAI,MAAM,SAAS,oBACjB;AAMF,MAAI,MAAM,SAAS,UAAU;AAC3B,YAAS,OAAO,MAAM,UAAU,cAAc,QAAQ;AACtD;;AAKF,MAAI,MAAM,SAAS,cAAc;AAC/B,YAAS;AACT;;AAIF,MAAI,CAAC,OACH;AAKF,MAAI,OAAO,QAAQ,UAAU,OAAO,OAAO,OAAO,UAAU,SAC1D,QAAO,OAAO,SAAS,IAAI,MAAM;MAEjC,QAAO,OAAO,QAAQ,MAAM;;AAIhC,QAAO;;;;;;;;;;AAWT,MAAa,gBAAgB,UAA4B;CACvD,MAAM,OAAiB,EAAE;CACzB,IAAI,aAAa;CACjB,IAAI,kBAAkB;AAEtB,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,IAAI,OAAO,MAAM;AAGjB,MAAI,SAAS,QAAQ,YAAY;AAE/B,OAAI,MAAM,WAAW,IAAI,EACvB,OAAM,IAAI,MAAM,uCAAuC;AAIzD,UAAO,MAAM,EAAE;aAGR,SAAS,OAAO,CAAC,YAAY;AACpC,qBAAkB;AAClB;aAIO,SAAS,MAAK;AACrB,gBAAa,CAAC;AACd;;AAIF,MAAI,iBAAiB;AACnB,QAAK,KAAK,KAAK;AACf,qBAAkB;QAIlB,MAAK,KAAK,SAAS,MAAM;;AAI7B,KAAI,WACF,OAAM,IAAI,MAAM,sBAAsB;AAGxC,QAAO;;;;;;;;AAST,MAAM,2BAA2B;AAC/B,KAAI,CAAC,QAAQ,IAAI,aAAc,QAAO,EAAE;AAExC,QAAO,aAAa,QAAQ,IAAI,aAAa;;;;;;;;;AAU/C,SAAgB,kBACd,MACQ;AACR,QAAO,OAAO,QAAQ,KAAK,CACxB,KAAK,CAAC,KAAK,WAAW;AACrB,MAAI,UAAU,KACZ,QAAO,KAAK;AAGd,MAAI,MACF,QAAO,KAAK,IAAI,GAGd,MAAM,SAAS,IAAI,IAAI,CAAC,MAAM,WAAW,KAAI,GACzC,KAAK,UAAU,MAAM,GACrB;AAIR,SAAO;GACP,CACD,QAAO,QAAO,QAAQ,KAAK,CAC3B,KAAK,IAAI;;;;;;;;AASd,SAAgB,qCAAqC;CACnD,MAAM,OAAO,oBAAoB;AACjC,KAAI,KAAK,WAAW,EAAG,QAAO,EAAE;CAEhC,MAAM,SAAS,cAAc,KAAK;AAGlC,QAAO,OAAO;AACd,QAAO,OAAO;AACd,QAAO,OAAO;AAEd,QAAO;;;;;;;;AAST,SAAgB,wCAAwC;CACtD,MAAM,OAAO,oCAAoC;AACjD,KAAI,OAAO,KAAK,KAAK,CAAC,WAAW,EAAG,QAAO;AAE3C,QAAO,kBAAkB,KAAK;;;;;;;;;AAUhC,eAAsB,YAAY,SAAkB;CAElD,MAAM,aAAa,MAAM,qBADH,iBAAiB,QACoB,CAAC;CAO5D,MAAM,gBAAgB,eAAe,QAAQ,oBAAoB;CACjE,IAAI,WAAW;AAEf,KAAI;EACF,MAAM,SAAS,SACb,GAAG,WAAW,uBAAuB,iBACrC,EACE,KAAK;GACH,GAAG,QAAQ;GACX,cAAc,uCAAuC;GACtD,EACF,CACF,CACE,UAAU,CACV,MAAM;AAET,MAAI,OAAO,WAAW,OAAO,CAC3B,YAAW,OAAO,SAAS,IAAI,GAAG,SAAS,GAAG,OAAO;UAEhD,KAAK;AACZ,QAAM,IAAI,MAAM,gCAAgC,WAAW,KAAK,EAC9D,OAAO,KACR,CAAC;;AAGJ,QAAO"}