{"version":3,"sources":["../../../src/utils/test/synth.ts"],"sourcesContent":["/* eslint-disable import/no-extraneous-dependencies */\n/* eslint-disable no-param-reassign */\n/* eslint-disable no-restricted-syntax */\n\n// Borrowed from: https://github.com/projen/projen/blob/main/src/util/synth.ts\n// They don't export it and we can't import it from the path using esm\n\nimport * as fs from 'fs';\nimport * as os from 'os';\nimport path from 'path';\nimport * as JSONC from 'comment-json';\nimport { glob } from 'glob';\nimport { JsonFile, Project } from 'projen';\n\nexport interface DirectorySnapshotOptions extends SnapshotOptions {\n  /**\n   * Globs of files to exclude.\n   * @defaultValue [] include all files\n   */\n  readonly excludeGlobs?: Array<string>;\n\n  /**\n   * Only snapshot the names of files and not their contents.\n   * The value for a path will be `true` if it exists.\n   *\n   * @defaultValue false include file content\n   */\n  readonly onlyFileNames?: boolean;\n\n  /**\n   * Parses files with different parser, supporting comments\n   * inside .json files.\n   * @defaultValue false\n   */\n  readonly supportJsonComments?: boolean;\n}\n\nfunction isJsonLikeFile(filePath: string): boolean {\n  const file = filePath.toLowerCase();\n  return (\n    file.endsWith('.json') || file.endsWith('.json5') || file.endsWith('.jsonc')\n  );\n}\n\n/**\n * Checks if a \"CommentArray\" has no comments stored in it.\n */\nfunction isCommentArrayWithoutComments(obj: any): boolean {\n  return (\n    obj instanceof JSONC.CommentArray &&\n    Object.getOwnPropertySymbols(obj).length === 0\n  );\n}\n\n/**\n * Converts type \"CommentArray\" back to regular JS \"Array\"\n * if there are no comments stored in it.\n * Prevents strict checks from failing.\n */\nfunction cleanCommentArrays(obj: any): typeof obj {\n  if (Array.isArray(obj) || isCommentArrayWithoutComments(obj)) {\n    return [...obj].map(cleanCommentArrays);\n  }\n\n  if (obj instanceof Object) {\n    for (const p of Object.keys(obj)) {\n      if (isCommentArrayWithoutComments(obj[p])) {\n        obj[p] = [...obj[p]].map(cleanCommentArrays);\n      } else if (obj[p] instanceof Object) {\n        obj[p] = cleanCommentArrays(obj[p]);\n      }\n    }\n  }\n\n  return obj;\n}\n\nexport function directorySnapshot(\n  root: string,\n  options: DirectorySnapshotOptions = {},\n) {\n  const output: SynthOutput = {};\n\n  const files = glob.sync('**', {\n    ignore: ['.git/**', ...(options.excludeGlobs ?? [])],\n    cwd: root,\n    nodir: true,\n    dot: true,\n  }); // returns relative file paths with POSIX separators\n\n  const parseJson = options.parseJson ?? true;\n\n  for (const file of files) {\n    const filePath = path.join(root, file);\n\n    let content;\n    if (options.onlyFileNames) {\n      content = true;\n    } else {\n      content = fs.readFileSync(filePath, 'utf8');\n      if (parseJson && isJsonLikeFile(filePath)) {\n        content = cleanCommentArrays(\n          JSONC.parse(content, undefined, !options.supportJsonComments),\n        );\n      }\n    }\n\n    output[file] = content;\n  }\n\n  return output;\n}\n\n/**\n * Options for the Snapshot synthesis\n */\nexport interface SnapshotOptions {\n  /**\n   * Parse .json files as a JS object for improved inspection.\n   * This will fail if the contents are invalid JSON.\n   *\n   * @defaultValue true\n   */\n  readonly parseJson?: boolean;\n}\n\nexport interface SynthOutput {\n  [filePath: string]: any;\n}\n\n/**\n * Creates a snapshot of the files generated by a project. Ignores any non-text\n * files so that the snapshots are human readable.\n */\nexport function synthSnapshot(\n  project: Project,\n  options: SnapshotOptions = {},\n): SynthOutput {\n  // defensive: verify that \"outdir\" is actually in a temporary directory\n  if (\n    !path.resolve(project.outdir).startsWith(os.tmpdir()) &&\n    !project.outdir.includes('project-temp-dir')\n  ) {\n    throw new Error(\n      'Trying to capture a snapshot of a project outside of tmpdir, which implies this test might corrupt an existing project',\n    );\n  }\n\n  const synthed = Symbol.for('synthed');\n  if (synthed in project) {\n    throw new Error('duplicate synth()');\n  }\n\n  (project as any)[synthed] = true;\n\n  const ENV_PROJEN_DISABLE_POST = process.env.PROJEN_DISABLE_POST;\n  try {\n    process.env.PROJEN_DISABLE_POST = 'true';\n    project.synth();\n    const ignoreExts = ['png', 'ico'];\n    return directorySnapshot(project.outdir, {\n      ...options,\n      excludeGlobs: ignoreExts.map((ext) => `**/*.${ext}`),\n      supportJsonComments: project.files.some(\n        // At least one json file in project supports comments\n        (file) => file instanceof JsonFile && file.supportsComments,\n      ),\n    });\n  } finally {\n    fs.rmSync(project.outdir, { force: true, recursive: true });\n\n    // values assigned to process.env.XYZ are automatically converted to strings\n    if (ENV_PROJEN_DISABLE_POST === undefined) {\n      delete process.env.PROJEN_DISABLE_POST;\n    } else {\n      process.env.PROJEN_DISABLE_POST = ENV_PROJEN_DISABLE_POST;\n    }\n  }\n}\n"],"mappings":"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","names":["path"]}