{"version":3,"sources":["../../src/fixFolderImportsPlugin.ts"],"sourcesContent":["import { dirname, resolve } from \"path\";\nimport { type Plugin } from \"esbuild\";\n\n/**\n * ESBuild plugin that replaces import paths pointing to directories\n * with explicit paths to the index file, but only if the output files\n * indicate that a direct file doesn't exist and an index file does.\n *\n * For example, it transforms:\n * ```javascript\n * import { myFunction } from '../folder';\n * ```\n * into:\n * ```javascript\n * import { myFunction } from '../folder/index';\n * ```\n *\n * @returns {import('esbuild').Plugin} An ESBuild plugin object.\n */\nexport const fixFolderImportsPlugin = (): Plugin => ({\n  name: \"fixFolderImportsPlugin\",\n  setup(build) {\n    // Determine the output file extension based on the build options.\n    const outExtension = build.initialOptions.outExtension?.[\".js\"] ?? \".js\";\n\n    // Hook into the 'onEnd' event of the build process.\n    build.onEnd((result) => {\n      // If there are build errors, do not proceed.\n      if (result.errors.length > 0) {\n        return;\n      }\n\n      // Collect all .js output file paths in a set for quick existence checks.\n      const allJsOutputs = new Set(\n        (result.outputFiles ?? [])\n          .filter((f) => f.path.endsWith(outExtension))\n          .map((f) => f.path)\n      );\n\n      // Iterate over each JS output file\n      for (const outputFile of result.outputFiles ?? []) {\n        if (!outputFile.path.endsWith(outExtension)) {\n          continue;\n        }\n\n        // Original file contents and the file path\n        const fileContents = outputFile.text;\n        const filePath = outputFile.path;\n\n        // Modify the file contents by replacing directory imports\n        // with explicit index file imports based on the set of output files\n        const nextFileContents = modifyFolderImports(\n          fileContents,\n          filePath,\n          outExtension,\n          allJsOutputs\n        );\n\n        // Update the output file contents only if something changed\n        if (nextFileContents !== fileContents) {\n          outputFile.contents = Buffer.from(nextFileContents, \"utf-8\");\n        }\n      }\n    });\n  },\n});\n\n/**\n * Regex for matching ESM and CJS relative imports.\n */\nconst ESM_RELATIVE_IMPORT_EXP = /from\\s*['\"](\\..+?)['\"]/g;\nconst CJS_RELATIVE_IMPORT_EXP = /require\\s*\\(\\s*['\"](\\..+?)['\"]\\s*\\)/g;\n\n/**\n * Regex to detect if an import path already has a file extension.\n */\nconst hasExtensionRegex = /\\.[^./\\\\]+$/;\n\n/**\n * For each import/require statement in a file, check if it refers to a directory\n * without an explicit index file. If so, and if an `index` file actually exists,\n * transform the path to include `/index`.\n */\nconst modifyFolderImports = (\n  contents: string,\n  filePath: string,\n  outExtension: string,\n  allJsOutputs: Set<string>\n): string => {\n  // Replace ESM imports\n  contents = contents.replace(ESM_RELATIVE_IMPORT_EXP, (match, importPath) => {\n    const newPath = replaceFolderImport(\n      importPath,\n      filePath,\n      outExtension,\n      allJsOutputs\n    );\n    return match.replace(importPath, newPath);\n  });\n\n  // Replace CJS requires\n  contents = contents.replace(CJS_RELATIVE_IMPORT_EXP, (match, importPath) => {\n    const newPath = replaceFolderImport(\n      importPath,\n      filePath,\n      outExtension,\n      allJsOutputs\n    );\n    return match.replace(importPath, newPath);\n  });\n\n  return contents;\n};\n\n/**\n * Decide whether the given import path should have `/index` appended\n * by checking against the set of all generated output paths.\n */\nconst replaceFolderImport = (\n  importPath: string,\n  filePath: string,\n  outExtension: string,\n  allJsOutputs: Set<string>\n): string => {\n  // If the path already ends with a slash, a dot, or has an extension, skip\n  if (\n    importPath.endsWith(\"/\") ||\n    importPath.endsWith(\".\") ||\n    hasExtensionRegex.test(importPath)\n  ) {\n    return importPath;\n  }\n\n  // Compute the absolute paths for \"importPath\" and \"importPath + /index\"\n  const currentDir = dirname(filePath);\n  const candidateFile = resolve(currentDir, importPath) + outExtension;\n  const candidateIndex =\n    resolve(currentDir, importPath, \"index\") + outExtension;\n\n  // If candidateFile is found, do not add /index; otherwise check candidateIndex\n  if (allJsOutputs.has(candidateFile)) {\n    return importPath;\n  } else if (allJsOutputs.has(candidateIndex)) {\n    return importPath + \"/index\";\n  }\n\n  return importPath;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAiC;AAmB1B,MAAM,yBAAyB,OAAe;AAAA,EACnD,MAAM;AAAA,EACN,MAAM,OAAO;AAEX,UAAM,eAAe,MAAM,eAAe,eAAe,KAAK,KAAK;AAGnE,UAAM,MAAM,CAAC,WAAW;AAEtB,UAAI,OAAO,OAAO,SAAS,GAAG;AAC5B;AAAA,MACF;AAGA,YAAM,eAAe,IAAI;AAAA,SACtB,OAAO,eAAe,CAAC,GACrB,OAAO,CAAC,MAAM,EAAE,KAAK,SAAS,YAAY,CAAC,EAC3C,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,MACtB;AAGA,iBAAW,cAAc,OAAO,eAAe,CAAC,GAAG;AACjD,YAAI,CAAC,WAAW,KAAK,SAAS,YAAY,GAAG;AAC3C;AAAA,QACF;AAGA,cAAM,eAAe,WAAW;AAChC,cAAM,WAAW,WAAW;AAI5B,cAAM,mBAAmB;AAAA,UACvB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAGA,YAAI,qBAAqB,cAAc;AACrC,qBAAW,WAAW,OAAO,KAAK,kBAAkB,OAAO;AAAA,QAC7D;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAKA,MAAM,0BAA0B;AAChC,MAAM,0BAA0B;AAKhC,MAAM,oBAAoB;AAO1B,MAAM,sBAAsB,CAC1B,UACA,UACA,cACA,iBACW;AAEX,aAAW,SAAS,QAAQ,yBAAyB,CAAC,OAAO,eAAe;AAC1E,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,WAAO,MAAM,QAAQ,YAAY,OAAO;AAAA,EAC1C,CAAC;AAGD,aAAW,SAAS,QAAQ,yBAAyB,CAAC,OAAO,eAAe;AAC1E,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,WAAO,MAAM,QAAQ,YAAY,OAAO;AAAA,EAC1C,CAAC;AAED,SAAO;AACT;AAMA,MAAM,sBAAsB,CAC1B,YACA,UACA,cACA,iBACW;AAEX,MACE,WAAW,SAAS,GAAG,KACvB,WAAW,SAAS,GAAG,KACvB,kBAAkB,KAAK,UAAU,GACjC;AACA,WAAO;AAAA,EACT;AAGA,QAAM,iBAAa,qBAAQ,QAAQ;AACnC,QAAM,oBAAgB,qBAAQ,YAAY,UAAU,IAAI;AACxD,QAAM,qBACJ,qBAAQ,YAAY,YAAY,OAAO,IAAI;AAG7C,MAAI,aAAa,IAAI,aAAa,GAAG;AACnC,WAAO;AAAA,EACT,WAAW,aAAa,IAAI,cAAc,GAAG;AAC3C,WAAO,aAAa;AAAA,EACtB;AAEA,SAAO;AACT;","names":[]}