import { transformContext } from './chunk-ICBTTNWA.js';
import { transformEnv } from './chunk-7SMZV7EV.js';
import { transformErrors } from './chunk-AIBU7K67.js';
import { generateSourceMap } from './chunk-24SJQ3LP.js';
import { getCache, setCache } from './chunk-HICN6QWN.js';
import { getMagicString } from './chunk-MJMBYCPB.js';
import { createLog } from './chunk-5S5JGJML.js';
import { __name } from './chunk-6AXVLTU5.js';
import { declarationTransformer, transformer } from '@deepkit/type-compiler';
import { LogLevelLabel } from '@storm-software/config-tools/types';
import { readFileIfExistingSync } from '@stryke/fs/read-file';
import { hash } from '@stryke/hash/hash';
import { joinPaths } from '@stryke/path/join-paths';
import ts from 'typescript';

var Compiler = class {
  static {
    __name(this, "Compiler");
  }
  #cache = /* @__PURE__ */ new WeakMap();
  #options;
  /**
  * The logger function to use
  */
  log;
  /**
  * The cache directory
  */
  cacheDir;
  constructor(context, options = {}) {
    this.log = createLog("compiler", context.options);
    this.#options = options;
    this.cacheDir = joinPaths(context.envPaths.cache, hash(context.tsconfig.options));
  }
  /**
  * Transpile the module.
  *
  * @param context - The compiler context.
  * @param id - The name of the file to compile.
  * @param code - The source code to compile.
  * @returns The transpiled module.
  */
  async transpile(context, id, code, options = {}) {
    const source = this.getSourceFile(id, code);
    return this.transpileModule(context, source, options);
  }
  /**
  * Compile the source code.
  *
  * @param context - The compiler context.
  * @param id - The name of the file to compile.
  * @param code - The source code to compile.
  * @returns The compiled source code and source map.
  */
  async compile(context, id, code, options = {}) {
    this.log(LogLevelLabel.TRACE, `Compiling ${id}`);
    const source = this.getSourceFile(id, code);
    let transpiled;
    if (!options.skipCache) {
      transpiled = await this.getCache(context, source);
      if (transpiled) {
        this.log(LogLevelLabel.TRACE, `Cache hit: ${source.id}`);
      } else {
        this.log(LogLevelLabel.TRACE, `Cache miss: ${source.id}`);
      }
    }
    if (!transpiled) {
      transpiled = await this.transpileModule(context, source, options);
      await this.setCache(context, source, transpiled);
    }
    return transpiled;
  }
  /**
  * Get the source file.
  *
  * @param id - The name of the file.
  * @param code - The source code.
  * @returns The source file.
  */
  getSourceFile(id, code) {
    const content = code ?? readFileIfExistingSync(id);
    return {
      id,
      code: getMagicString(content),
      env: []
    };
  }
  /**
  * Get the result of the compiler.
  *
  * @param sourceFile - The source file.
  * @param transpiled - The transpiled source code.
  * @returns The result of the compiler.
  */
  getResult(sourceFile, transpiled) {
    return generateSourceMap(sourceFile.id, sourceFile.code, transpiled);
  }
  async getCache(context, sourceFile) {
    let cache = this.#cache.get(sourceFile);
    if (cache) {
      return cache;
    }
    if (context.options.skipCache) {
      return;
    }
    cache = await getCache(sourceFile, this.cacheDir);
    if (cache) {
      this.#cache.set(sourceFile, cache);
    }
    return cache;
  }
  async setCache(context, sourceFile, transpiled) {
    if (transpiled) {
      this.#cache.set(sourceFile, transpiled);
    } else {
      this.#cache.delete(sourceFile);
    }
    if (context.options.skipCache) {
      return;
    }
    return setCache(sourceFile, this.cacheDir, transpiled);
  }
  /**
  * Transpile the module.
  *
  * @param context - The compiler context.
  * @param source - The compiler source file.
  * @param options - The transpile options.
  * @returns The transpiled module.
  */
  async transpileModule(context, source, options = {}) {
    this.log(LogLevelLabel.TRACE, `Transpiling ${source.id} module with TypeScript compiler`);
    let transformed = source;
    if (options.onPreTransform) {
      await Promise.resolve(options.onPreTransform(context, source));
    }
    if (this.#options.onPreTransform) {
      await Promise.resolve(this.#options.onPreTransform(context, source));
    }
    if (!options.skipTransform) {
      if (context.options.platform === "node") {
        transformContext(source);
      }
      if (!options.skipEnvTransform) {
        transformed = await transformEnv(this.log, source, context);
      }
      if (!options.skipErrorsTransform) {
        await transformErrors(this.log, transformed, context);
      }
      if (this.#options.onTransform) {
        await Promise.resolve(this.#options.onTransform(context, transformed));
      }
    }
    if (context.unimport && !transformed.id.replaceAll("\\", "/").includes(joinPaths(context.artifactsDir, "runtime"))) {
      transformed = await context.unimport.injectImports(transformed);
    }
    if (this.#options.onPostTransform) {
      await Promise.resolve(this.#options.onPostTransform(context, transformed));
    }
    if (options.onPostTransform) {
      await Promise.resolve(options.onPostTransform(context, transformed));
    }
    const transpiled = ts.transpileModule(transformed.code.toString(), {
      compilerOptions: {
        ...context.tsconfig.options,
        configFilePath: context.options.tsconfig
      },
      fileName: transformed.id,
      transformers: {
        before: [
          transformer
        ],
        after: [
          declarationTransformer
        ]
      }
    });
    if (transpiled === null) {
      this.log(LogLevelLabel.ERROR, `Transform is null: ${transformed.id}`);
      throw new Error(`Transform is null: ${transformed.id}`);
    } else {
      this.log(LogLevelLabel.TRACE, `Transformed: ${transformed.id}`);
    }
    return transpiled.outputText;
  }
};

export { Compiler };
//# sourceMappingURL=chunk-GY3CS6YV.js.map
//# sourceMappingURL=chunk-GY3CS6YV.js.map