{"version":3,"sources":["../src/index.ts","../src/regexpEscape.ts","../src/StringReplaceAllPolyfill.ts"],"names":["VersionOrCurrentDate"],"mappings":"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","sourcesContent":["import { Result } from '@sapphire/result';\nimport type { BuildResult, OnLoadArgs, OnLoadOptions, OnLoadResult, Plugin } from 'esbuild';\nimport { readFile } from 'node:fs/promises';\nimport { extname, resolve } from 'node:path';\n\nimport './StringReplaceAllPolyfill';\n\nenum VersionOrCurrentDate {\n  Version = 'version',\n  CurrentDate = 'current-date'\n}\n\ninterface PluginOptions {\n  /**\n   * The [esbuild filter](https://esbuild.github.io/plugins/#filters) to\n   * apply for the filtering of files to parse with this plugin\n   *\n   * @default /.*​/\n   */\n  filter?: OnLoadOptions['filter'];\n  /**\n   * The [esbuild namespace](https://esbuild.github.io/plugins/#namespaces) to\n   * which the plugin should apply\n   *\n   * @default undefined\n   */\n  namespace?: OnLoadOptions['namespace'];\n  /**\n   * Whether the plugin should inject the package.json version or the\n   * current date (in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format)\n   *\n   * @default 'version'\n   */\n  versionOrCurrentDate?: 'version' | 'current-date' | VersionOrCurrentDate;\n  /**\n   * The default identifier that should be searched within the code and replaced with either the\n   * the version or the current date as configured by {@link PluginOptions.versionOrCurrentDate}.\n   *\n   * @default '[VI]{{inject}}[/VI]'\n   */\n  injectTag?: string;\n  /**\n   * Relative path to project's package.json\n   *\n   * Note if you set {@link PluginOptions.versionOrCurrentDate} to 'current-date' this option will be ignored.\n   *\n   * @default './package.json'\n   */\n  packageJsonPath?: string;\n  /**\n   * Whether to disable the `onLoad` trigger, which is used by default.\n   *\n   * In most cases you will not want to set this to `true`,\n   * but it can be useful if you have specified a custom `loader` mapper in `esbuild` through\n   * ```ts\n   * esbuild.build({ ...otherOptions, loader: { '.js': 'jsx' } });\n   * ```\n   *\n   * @default undefined\n   */\n  disableOnLoadTrigger?: boolean;\n}\n\nfunction getFilter(options: PluginOptions): RegExp {\n  if (!options.filter) {\n    return /.*/;\n  }\n\n  if (Object.prototype.toString.call(options.filter) !== '[object RegExp]') {\n    console.warn(\n      `Plugin \"esbuild-plugin-version-injector\": Options.filter must be a RegExp object, but gets an '${typeof options.filter}' type. \\nThis request will match ANY file!`\n    );\n    return /.*/;\n  }\n\n  return options.filter ?? /.*/;\n}\n\nfunction getInjectTag(options: PluginOptions): string {\n  return options.injectTag ?? '[VI]{{inject}}[/VI]';\n}\n\nasync function getVersionOrCurrentDate(options: PluginOptions): Promise<string | null> {\n  const { versionOrCurrentDate } = options;\n\n  if (versionOrCurrentDate === VersionOrCurrentDate.CurrentDate) {\n    return new Date().toISOString();\n  }\n\n  const packageFile = await Result.fromAsync(readFile(resolve(options.packageJsonPath ?? './package.json'), { encoding: 'utf-8' }));\n\n  if (packageFile.isErr()) {\n    return null;\n  }\n\n  const packageJson = Result.from<IMinimalPackageJson>(JSON.parse(packageFile.unwrap()));\n\n  if (packageJson.isErr()) {\n    return null;\n  }\n\n  const packageJsonVersion = packageJson.unwrap().version;\n\n  if (!packageJsonVersion) {\n    return null;\n  }\n\n  return packageJsonVersion;\n}\n\n/**\n * Resolves the proper [ESBuild content type loader](https://esbuild.github.io/content-types/) based on\n * the file extension using {@link extname}\n *\n * If no match can be found with the file extension, then the JavaScript content type loader is returned.\n * This matches how ESBuild handles would handle an unspecified loader or unknown file extension.\n *\n * @param args The esbuild {@link OnLoadArgs}\n * @returns The proper content type loader based on the file extension\n */\nfunction getEsbuildLoader(args: OnLoadArgs) {\n  const resolvedExtName = extname(args.path);\n\n  switch (resolvedExtName) {\n    case '.ts':\n    case '.mts':\n    case '.cts':\n      return 'ts';\n    case '.jsx':\n    case '.tsx':\n      return 'tsx';\n    case '.json':\n      return 'json';\n    case '.css':\n    case '.scss':\n    case '.sass':\n    case '.less':\n    case '.styl':\n      return 'css';\n    case '.txt':\n      return 'text';\n    case '.js':\n    case '.cjs':\n    case '.mjs':\n    default:\n      return 'js';\n  }\n}\n\nasync function handleOnLoad(args: OnLoadArgs, options: PluginOptions): Promise<OnLoadResult | undefined> {\n  const injectTag = getInjectTag(options);\n\n  const fileResult = await Result.fromAsync(readFile(args.path, { encoding: 'utf-8' }));\n\n  if (fileResult.isOk()) {\n    let unwrappedFileContents = fileResult.unwrap();\n    const hasInjectTag = unwrappedFileContents.includes(injectTag);\n\n    if (hasInjectTag) {\n      const versionOrCurrentDate = await getVersionOrCurrentDate(options);\n\n      if (versionOrCurrentDate) {\n        unwrappedFileContents = unwrappedFileContents.replaceAll(injectTag, versionOrCurrentDate);\n      }\n    }\n\n    return {\n      pluginData: args.pluginData,\n      contents: unwrappedFileContents,\n      loader: getEsbuildLoader(args)\n    };\n  }\n\n  return undefined;\n}\n\nasync function handleOnEnd(results: BuildResult, filter: RegExp, options: PluginOptions): Promise<void> {\n  const injectTag = getInjectTag(options);\n\n  for (const file of results.outputFiles ?? []) {\n    if (!filter.test(file.path)) {\n      continue;\n    }\n\n    const hasInjectTag = file.text.includes(injectTag);\n\n    if (hasInjectTag) {\n      const versionOrCurrentDate = await getVersionOrCurrentDate(options);\n\n      if (versionOrCurrentDate) {\n        const decoded = new TextDecoder().decode(file.contents);\n\n        const replaced = decoded.replaceAll(injectTag, versionOrCurrentDate);\n\n        file.contents = new TextEncoder().encode(replaced);\n      }\n    }\n  }\n}\n\nfunction esbuildPluginVersionInjector(\n  options: PluginOptions = {\n    filter: /.*/,\n    versionOrCurrentDate: VersionOrCurrentDate.Version,\n    injectTag: '[VI]{{inject}}[/VI]',\n    packageJsonPath: './package.json'\n  }\n): Plugin {\n  const filter = getFilter(options);\n  const { namespace } = options;\n\n  return {\n    name: 'esbuild-plugin-version-injector',\n    setup(build) {\n      if (!options.disableOnLoadTrigger) {\n        // This is used when this plugin is the first loader to be used (tsup and similar will load swc first which will make this never be called, BUT it will call onEnd)\n        build.onLoad({ filter, namespace }, (args) => handleOnLoad(args, options));\n      }\n\n      // This will process all files at the end, if a previous loader has taken care of loading+transforming\n      build.onEnd((results) => handleOnEnd(results, filter, options));\n    }\n  };\n}\n\n/**\n * The [esbuild-plugin-version-injector](https://github.com/favware/esbuild-plugin-version-injector/#readme) version\n * that you are currently using.\n */\n// eslint-disable-next-line @typescript-eslint/no-inferrable-types\nconst version: string = '1.2.1';\n\ninterface IMinimalPackageJson {\n  version: string;\n  name: string;\n  description?: string;\n}\n\nexport { VersionOrCurrentDate, esbuildPluginVersionInjector, version, type PluginOptions };\n","/**\n * https://github.com/sapphiredev/utilities/blob/main/packages/utilities/src/lib/regExpEsc.ts\n * @author The Sapphire Community and its contributors\n * @license MIT\n */\nconst REGEXPESC = /[-/\\\\^$*+?.()|[\\]{}]/g;\n\n/**\n * Cleans a string from regex injection\n * @param str The string to clean\n * https://github.com/sapphiredev/utilities/blob/main/packages/utilities/src/lib/regExpEsc.ts\n * @author The Sapphire Community and its contributors\n * @license MIT\n */\nexport function regExpEsc(str: string): string {\n  return str.replace(REGEXPESC, '\\\\$&');\n}\n","import { regExpEsc } from './regexpEscape';\n\n/**\n * String.prototype.replaceAll() polyfill\n * https://gomakethings.com/how-to-replace-a-section-of-a-string-with-another-one-with-vanilla-js/\n * @author Chris Ferdinandi\n * @license MIT\n */\nif (!String.prototype.replaceAll) {\n  // eslint-disable-next-line no-extend-native\n  String.prototype.replaceAll = function replaceAll(str: string | RegExp, newStr: string | ((substring: string, ...args: any[]) => string)): string {\n    // If a regex pattern\n    if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') {\n      // @ts-ignore newStr can be both a string or a function returning a string\n      return this.replace(str, newStr);\n    }\n\n    // If a string\n    // @ts-ignore newStr can be both a string or a function returning a string\n    return this.replace(new RegExp(regExpEsc(str), 'g'), newStr);\n  };\n}\n"]}