{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Helper routines for use with the jsii compiler\n *\n * These are mostly used for testing, but all projects that need to exercise\n * the JSII compiler to test something need to share this code, so might as\n * well put it in one reusable place.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { PackageJson, loadAssemblyFromPath, writeAssembly } from '@jsii/spec';\nimport * as spec from '@jsii/spec';\nimport { DiagnosticCategory } from 'typescript';\n\nimport { Compiler, CompilerOptions } from './compiler';\nimport { loadProjectInfo, ProjectInfo } from './project-info';\nimport { formatDiagnostic, JsiiError } from './utils';\n\n/**\n * A set of source files for `sourceToAssemblyHelper`, at least containing 'index.ts'\n */\nexport type MultipleSourceFiles = {\n  'index.ts': string;\n  [name: string]: string;\n};\n\n/**\n * Compile a piece of source and return the JSII assembly for it\n *\n * Only usable for trivial cases and tests.\n *\n * @param source can either be a single `string` (the content of `index.ts`), or\n *               a map of fileName to content, which *must* include `index.ts`.\n * @param options accepts a callback for historical reasons but really expects to\n *                take an options object.\n */\nexport function sourceToAssemblyHelper(\n  source: string | MultipleSourceFiles,\n  options?: TestCompilationOptions | ((obj: PackageJson) => void),\n): spec.Assembly {\n  return compileJsiiForTest(source, options).assembly;\n}\n\nexport interface HelperCompilationResult {\n  /**\n   * The generated assembly\n   */\n  readonly assembly: spec.Assembly;\n\n  /**\n   * Generated .js/.d.ts file(s)\n   */\n  readonly files: Record<string, string>;\n\n  /**\n   * The packageInfo used\n   */\n  readonly packageJson: PackageJson;\n\n  /**\n   * Whether to compress the assembly file\n   */\n  readonly compressAssembly: boolean;\n}\n\n/**\n * Compile a piece of source and return the assembly and compiled sources for it\n *\n * Only usable for trivial cases and tests.\n *\n * @param source can either be a single `string` (the content of `index.ts`), or\n *               a map of fileName to content, which *must* include `index.ts`.\n * @param options accepts a callback for historical reasons but really expects to\n *                take an options object.\n */\nexport function compileJsiiForTest(\n  source: string | { 'index.ts': string; [name: string]: string },\n  options?: TestCompilationOptions | ((obj: PackageJson) => void),\n  compilerOptions?: Omit<CompilerOptions, 'projectInfo' | 'watch'>,\n): HelperCompilationResult {\n  if (typeof source === 'string') {\n    source = { 'index.ts': source };\n  }\n\n  const inSomeLocation =\n    isOptionsObject(options) && options.compilationDirectory ? inOtherDir(options.compilationDirectory) : inTempDir;\n\n  // Easiest way to get the source into the compiler is to write it to disk somewhere.\n  // I guess we could make an in-memory compiler host but that seems like work...\n  return inSomeLocation(() => {\n    for (const [fileName, content] of Object.entries(source)) {\n      fs.mkdirSync(path.dirname(fileName), { recursive: true });\n      fs.writeFileSync(fileName, content, { encoding: 'utf-8' });\n    }\n    const { projectInfo, packageJson } = makeProjectInfo(\n      'index.ts',\n      typeof options === 'function'\n        ? options\n        : (pi) => {\n            Object.assign(pi, options?.packageJson ?? options?.projectInfo ?? {});\n          },\n    );\n    const compiler = new Compiler({\n      projectInfo,\n      ...compilerOptions,\n    });\n    const emitResult = compiler.emit();\n\n    const errors = emitResult.diagnostics.filter((d) => d.category === DiagnosticCategory.Error);\n    for (const error of errors) {\n      console.error(formatDiagnostic(error, projectInfo.projectRoot));\n      // logDiagnostic() doesn't work out of the box, so console.error() it is.\n    }\n    if (errors.length > 0 || emitResult.emitSkipped) {\n      throw new JsiiError('There were compiler errors');\n    }\n    const assembly = loadAssemblyFromPath(process.cwd(), false);\n    const files: Record<string, string> = {};\n\n    for (const filename of Object.keys(source)) {\n      let jsFile = filename.replace(/\\.ts$/, '.js');\n      let dtsFile = filename.replace(/\\.ts$/, '.d.ts');\n      if (projectInfo.tsc?.outDir && filename !== 'README.md') {\n        jsFile = path.join(projectInfo.tsc.outDir, jsFile);\n        dtsFile = path.join(projectInfo.tsc.outDir, dtsFile);\n      }\n\n      // eslint-disable-next-line no-await-in-loop\n      files[jsFile] = fs.readFileSync(jsFile, { encoding: 'utf-8' });\n      // eslint-disable-next-line no-await-in-loop\n      files[dtsFile] = fs.readFileSync(dtsFile, { encoding: 'utf-8' });\n\n      const warningsFileName = '.warnings.jsii.js';\n      if (fs.existsSync(warningsFileName)) {\n        // eslint-disable-next-line no-await-in-loop\n        files[warningsFileName] = fs.readFileSync(warningsFileName, {\n          encoding: 'utf-8',\n        });\n      }\n    }\n\n    return {\n      assembly,\n      files,\n      packageJson,\n      compressAssembly: isOptionsObject(options) && options.compressAssembly ? true : false,\n    } as HelperCompilationResult;\n  });\n}\n\nfunction inTempDir<T>(block: () => T): T {\n  const origDir = process.cwd();\n  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'jsii'));\n  process.chdir(tmpDir);\n  const ret = block();\n  process.chdir(origDir);\n  fs.rmSync(tmpDir, { force: true, recursive: true });\n  return ret;\n}\n\nfunction inOtherDir(dir: string) {\n  // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint\n  return <T extends unknown>(block: () => T): T => {\n    const origDir = process.cwd();\n    process.chdir(dir);\n    try {\n      return block();\n    } finally {\n      process.chdir(origDir);\n    }\n  };\n}\n\n/**\n * Obtain project info so we can call the compiler\n *\n * Creating this directly in-memory leads to slightly different behavior from calling\n * jsii from the command-line, and I don't want to figure out right now.\n *\n * Most consistent behavior seems to be to write a package.json to disk and\n * then calling the same functions as the CLI would.\n */\nfunction makeProjectInfo(\n  types: string,\n  cb?: (obj: PackageJson) => void,\n): { projectInfo: ProjectInfo; packageJson: PackageJson } {\n  const packageJson: PackageJson = {\n    types,\n    main: types.replace(/(?:\\.d)?\\.ts(x?)/, '.js$1'),\n    name: 'testpkg', // That's what package.json would tell if we look up...\n    version: '0.0.1',\n    license: 'Apache-2.0',\n    author: { name: 'John Doe' },\n    repository: { type: 'git', url: 'https://github.com/aws/jsii.git' },\n    jsii: {},\n  };\n\n  if (cb) {\n    cb(packageJson);\n  }\n\n  fs.writeFileSync(\n    'package.json',\n    JSON.stringify(packageJson, (_: string, v: any) => v, 2),\n    'utf-8',\n  );\n\n  const { projectInfo } = loadProjectInfo(path.resolve(process.cwd(), '.'));\n  return { projectInfo, packageJson };\n}\n\nexport interface TestCompilationOptions {\n  /**\n   * The directory in which we write and compile the files\n   */\n  readonly compilationDirectory?: string;\n\n  /**\n   * Parts of projectInfo to override (package name etc)\n   *\n   * @deprecated Prefer using `packageJson` instead.\n   */\n  readonly projectInfo?: Partial<PackageJson>;\n\n  /**\n   * Parts of projectInfo to override (package name etc)\n   *\n   * @default - Use some default values\n   */\n  readonly packageJson?: Partial<PackageJson>;\n\n  /**\n   * Whether to compress the assembly file.\n   *\n   * @default false\n   */\n  readonly compressAssembly?: boolean;\n}\n\nfunction isOptionsObject(\n  x: TestCompilationOptions | ((obj: PackageJson) => void) | undefined,\n): x is TestCompilationOptions {\n  return x ? typeof x === 'object' : false;\n}\n\n/**\n * An NPM-ready workspace where we can install test-compile dependencies and compile new assemblies\n */\nexport class TestWorkspace {\n  /**\n   * Create a new workspace.\n   *\n   * Creates a temporary directory, don't forget to call cleanUp\n   */\n  public static create(): TestWorkspace {\n    const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'jsii-testworkspace'));\n    fs.mkdirSync(tmpDir, { recursive: true });\n    return new TestWorkspace(tmpDir);\n  }\n\n  /**\n   * Execute a block with a temporary workspace\n   */\n  public static withWorkspace<A>(block: (ws: TestWorkspace) => A): A {\n    const ws = TestWorkspace.create();\n    try {\n      return block(ws);\n    } finally {\n      ws.cleanup();\n    }\n  }\n\n  private readonly installed = new Set<string>();\n\n  private constructor(public readonly rootDirectory: string) {}\n\n  /**\n   * Add a test-compiled jsii assembly as a dependency\n   */\n  public addDependency(dependencyAssembly: HelperCompilationResult) {\n    if (this.installed.has(dependencyAssembly.assembly.name)) {\n      throw new JsiiError(\n        `A dependency with name '${dependencyAssembly.assembly.name}' was already installed. Give one a different name.`,\n      );\n    }\n    this.installed.add(dependencyAssembly.assembly.name);\n\n    // The following is silly, however: the helper has compiled the given source to\n    // an assembly, and output files, and then removed their traces from disk.\n    // We need those files back on disk, so write them back out again.\n    //\n    // We will drop them in 'node_modules/<name>' so they can be imported\n    // as if they were installed.\n    const modDir = path.join(this.rootDirectory, 'node_modules', dependencyAssembly.assembly.name);\n    fs.mkdirSync(modDir, { recursive: true });\n\n    writeAssembly(modDir, dependencyAssembly.assembly, {\n      compress: dependencyAssembly.compressAssembly,\n    });\n    fs.writeFileSync(\n      path.join(modDir, 'package.json'),\n      JSON.stringify(dependencyAssembly.packageJson, null, 2),\n      'utf-8',\n    );\n\n    for (const [fileName, fileContents] of Object.entries(dependencyAssembly.files)) {\n      fs.mkdirSync(path.dirname(path.join(modDir, fileName)), {\n        recursive: true,\n      });\n      fs.writeFileSync(path.join(modDir, fileName), fileContents);\n    }\n  }\n\n  public dependencyDir(name: string) {\n    if (!this.installed.has(name)) {\n      throw new JsiiError(`No dependency with name '${name}' has been installed`);\n    }\n    return path.join(this.rootDirectory, 'node_modules', name);\n  }\n\n  public cleanup() {\n    fs.rmSync(this.rootDirectory, { force: true, recursive: true });\n  }\n}\n\n// Alias for backwards compatibility\nexport type PackageInfo = PackageJson;\n\n/**\n * TSConfig paths can either be relative to the project or absolute.\n * This function normalizes paths to be relative to the provided root.\n * After normalization, code using these paths can be much simpler.\n *\n * @param root the project root\n * @param pathToNormalize the path to normalize, might be empty\n */\nexport function normalizeConfigPath(root: string, pathToNormalize?: string): string | undefined {\n  if (pathToNormalize == null || !path.isAbsolute(pathToNormalize)) {\n    return pathToNormalize;\n  }\n  return path.relative(root, pathToNormalize);\n}\n"]}