EdgeFunctions.utils.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import { common, dirname, relative } from '@std/path/posix'
  2. import { FileData } from '@/components/ui/FileExplorerAndEditor/FileExplorerAndEditor.types'
  3. import { EdgeFunctionBodyData } from '@/data/edge-functions/edge-function-body-query'
  4. export const getFallbackImportMapPath = (files: Omit<FileData, 'id' | 'content' | 'state'>[]) => {
  5. // try to find a deno.json or import_map.json file
  6. const regex = /^.*?(deno|import_map).json*$/i
  7. return files.find(({ name }) => regex.test(name))?.name
  8. }
  9. export const getFallbackEntrypointPath = (files: Omit<FileData, 'id' | 'content' | 'state'>[]) => {
  10. // when there's no matching entrypoint path is set,
  11. // we use few heuristics to find an entrypoint file
  12. // 1. If the function has only a single TS / JS file, if so set it as entrypoint
  13. const jsFiles = files.filter(
  14. ({ name }) =>
  15. name.endsWith('.js') || name.endsWith('.ts') || name.endsWith('.jsx') || name.endsWith('.tsx')
  16. )
  17. if (jsFiles.length === 1) {
  18. return jsFiles[0].name
  19. } else if (jsFiles.length) {
  20. // 2. If function has a `index` or `main` file use it as the entrypoint
  21. const regex = /^.*?(index|main).*$/i
  22. const matchingFile = jsFiles.find(({ name }) => regex.test(name))
  23. // 3. if no valid index / main file found, we set the entrypoint expliclty to first JS file
  24. return matchingFile ? matchingFile.name : jsFiles[0].name
  25. } else {
  26. // no potential entrypoint files found, this will most likely result in an error on deploy
  27. return 'index.ts'
  28. }
  29. }
  30. export const getStaticPatterns = (files: Omit<FileData, 'id' | 'content' | 'state'>[]) => {
  31. return files
  32. .filter(({ name }) => !name.match(/\.(js|ts|jsx|tsx|json|wasm)$/i))
  33. .map(({ name }) => name)
  34. }
  35. function getBasePath(entrypoint: string | undefined, fileNames: string[]): string {
  36. if (!entrypoint) {
  37. return '/'
  38. }
  39. let candidate = fileNames.find((name) => entrypoint.endsWith(name))
  40. if (candidate) {
  41. return dirname(candidate)
  42. } else {
  43. try {
  44. return dirname(new URL(entrypoint).pathname)
  45. } catch (e) {
  46. console.error('Failed to parse entrypoint', entrypoint)
  47. return '/'
  48. }
  49. }
  50. }
  51. export const formatFunctionBodyToFiles = ({
  52. functionBody,
  53. entrypointPath,
  54. }: {
  55. functionBody: EdgeFunctionBodyData
  56. entrypointPath?: string
  57. }) => {
  58. const entrypoint_path = functionBody.metadata?.deno2_entrypoint_path ?? entrypointPath
  59. // Set files from API response when available
  60. if (entrypoint_path) {
  61. const base_path = getBasePath(
  62. entrypoint_path,
  63. functionBody.files.map((file) => file.name)
  64. )
  65. const filesWithRelPath = functionBody.files
  66. // set file paths relative to entrypoint
  67. .map((file: { name: string; content: string }) => {
  68. try {
  69. // if the current file and base path doesn't share a common path,
  70. // return unmodified file
  71. const common_path = common([base_path, file.name])
  72. if (common_path === '' || common_path === '/tmp/') {
  73. return file
  74. }
  75. // prepend "/" to turn relative paths to absolute
  76. file.name = relative('/' + base_path, '/' + file.name)
  77. return file
  78. } catch (e) {
  79. console.error(e)
  80. // return unmodified file
  81. return file
  82. }
  83. })
  84. return filesWithRelPath.map((file: { name: string; content: string }, index: number) => {
  85. return {
  86. id: index + 1,
  87. name: file.name,
  88. content: file.content,
  89. state: 'unchanged',
  90. } as FileData
  91. })
  92. }
  93. return []
  94. }