Files
medusa-store/www/packages/build-scripts/src/generate-edited-dates.ts
Shahed Nasser 0acd94aac3 docs: refactor medusa workflows reference (#8692)
* docs: fix handling of namespaces in core flows under definitions directory

* change nested handling

* docs-util: expand workflows under definitions in workflows reference

* remove check for definitions
2024-08-22 13:39:52 +03:00

167 lines
4.3 KiB
TypeScript

import { exec } from "child_process"
import { existsSync } from "fs"
import { readdir, readFile, stat, writeFile } from "fs/promises"
import path from "path"
import util from "util"
const promiseExec = util.promisify(exec)
const projectBasePath = path.resolve()
const rootPath = path.resolve("..", "..", "..")
const monorepoRelativePath = projectBasePath
.replace(rootPath, "")
.replace(/^\//, "")
const generatedFilePath = path.join(
projectBasePath,
"generated",
"edit-dates.mjs"
)
const getGitEditDatesOfPaths = async (
paths: string[]
): Promise<Record<string, string>> => {
const editDates: Record<string, string> = {}
await Promise.all(
paths.map(async (filePath) => {
const editDateProcess = await promiseExec(
`git log -1 --pretty="format:%cI" ${filePath}`
)
editDates[filePath] = editDateProcess.stdout || new Date().toISOString()
})
)
return editDates
}
// Note: this gets the date a file was edited in the OS. One drawback here
// is if a file is edited on a day, but the PR is merged a few days later, so the
// date doesn't accurately represent the publish date of the file.
const getOsLastEditDates = async (
paths: string[]
): Promise<Record<string, string | undefined>> => {
const editDates: Record<string, string | undefined> = {}
await Promise.all(
paths.map(async (filePath) => {
if (!existsSync(filePath)) {
// indicates that file was deleted
editDates[filePath] = undefined
return
}
const fileStat = await stat(filePath)
editDates[filePath] = fileStat.mtime.toISOString()
})
)
return editDates
}
const getChangedFiles = async (): Promise<string[]> => {
const changedFiles: string[] = []
// get untracked files
const untrackedFiles = await promiseExec(
`git ls-files --other --exclude-standard`
)
untrackedFiles.stdout.split("\n").forEach((file) => {
if (path.basename(file) !== "page.mdx") {
return
}
changedFiles.push(path.relative(projectBasePath, file))
})
// get tracked files
const trackedFiles = await promiseExec(
`{ git diff --name-only ; git diff --name-only --staged ; } | sort | uniq`
)
trackedFiles.stdout.split("\n").forEach((file) => {
// The above command retrieve the full file path relative to the monorepo
// so all parts before the project's path should be removed.
if (
!file.startsWith(monorepoRelativePath) ||
path.basename(file) !== "page.mdx"
) {
return
}
changedFiles.push(file.replace(`${monorepoRelativePath}/`, ""))
})
return changedFiles
}
const getAllProjectFiles = async (): Promise<string[]> => {
const appDir = path.join(projectBasePath, "app")
const allFiles: string[] = []
const filesInDir = await readdir(appDir, {
withFileTypes: true,
recursive: true,
})
filesInDir.forEach((file) => {
if (file.isDirectory() || path.basename(file.name) !== "page.mdx") {
return
}
const fullFilePath = path.join(file.path, file.name)
// TODO check if this produces correct file paths
allFiles.push(path.relative(projectBasePath, fullFilePath))
})
return allFiles
}
export const generateEditedDates = async () => {
const generatedFileExists = existsSync(generatedFilePath)
const type = generatedFileExists ? "git" : "all"
let files: string[] = []
let editDates: Record<string, string | undefined> = {}
if (type === "all") {
// get all files in a project
files = await getAllProjectFiles()
editDates = await getGitEditDatesOfPaths(files)
} else {
// set the last edit dates for git changes only
files = await getChangedFiles()
editDates = await getOsLastEditDates(files)
}
if (!files.length) {
return
}
const fileContentPrefix = `export const generatedEditDates = `
if (generatedFileExists) {
const existingEditDates = JSON.parse(
(await readFile(generatedFilePath, "utf-8")).replace(
fileContentPrefix,
""
)
)
editDates = Object.assign(existingEditDates, editDates)
// delete items that don't exist anymore (their value is undefined)
Object.keys(editDates)
.filter((key) => editDates[key] === undefined)
.forEach((key) => delete editDates[key])
}
await writeFile(
generatedFilePath,
`${fileContentPrefix}${JSON.stringify(editDates, undefined, 2)}`,
{
flag: "w",
}
)
}