.ts
TypeScript
(application/typescript)
// 1st-party
import type { ServiceMethodFactory } from "@ethicdevs/react-monolith";
// app
import type { LinguistFileInfos } from "../../types";
// service
import type { CodeAnalysisServiceDeps } from "./types";

const makeGetLinguistFileInfos: ServiceMethodFactory<
  CodeAnalysisServiceDeps,
  [string, string | undefined],
  Promise<LinguistFileInfos>
> = (deps) => {
  return async (path, content = undefined) => {
    const ext = deps.getFilePathExt(path);
    if (deps.imageExts.includes(ext)) {
      return {
        // TODO(improvement): make an algorithm to generate one color per ext?
        color: "gray",
        extensions: [ext],
        languageDisplayName: ext.toUpperCase(),
        language: ext,
        languageId: -1,
        mimeType: deps.extsMimeTypesMap[ext] || `image/${ext}`,
        type: "image",
      };
    }

    let language =
      content != null
        ? deps.languageDetect.contents(path, content)
        : deps.languageDetect.filename(path);

    if (language == null || language in deps.languagesMap === false) {
      language = "Shell";
    }

    const languageInfos = deps.languagesMap[language];
    if (languageInfos == null) {
      throw new Error(`Invalid language: not in languages map.`);
    }

    const languageResults: LinguistFileInfos = {
      color: languageInfos.color || "gray",
      extensions: languageInfos.extensions || [],
      languageDisplayName: language,
      language: languageInfos.aceMode,
      languageId: languageInfos.languageId,
      mimeType:
        languageInfos.codemirrorMimeType || `text/${languageInfos.aceMode}`,
      type: languageInfos.type,
    };

    return Promise.resolve(languageResults);
  };
};

export default makeGetLinguistFileInfos;