This commit is contained in:
Stefan Pejcic
2024-11-07 19:03:37 +01:00
parent c6df945ed5
commit 09f9f9502d
2472 changed files with 620417 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
import React from "react";
import dedent from "dedent";
import { SWIZZLE_CODES } from "@utils/swizzle/codes";
import chalk from "chalk";
import { markedTerminalRenderer } from "@utils/marked-terminal-renderer";
type Params = {
label: string;
files: [targetPath: string, statusCode: string][];
message?: string;
};
export const printSwizzleMessage = ({
label,
files,
message = "**`Warning:`** You should use the component where you want to use it.",
}: Params) => {
const errors = files.filter(([, statusCode]) =>
Object.values(SWIZZLE_CODES)
.filter((code) => code !== SWIZZLE_CODES.SUCCESS)
.includes(statusCode),
);
let status = "success";
switch (errors.length) {
// no errors
case 0:
status = "success";
break;
// all errors
case files.length:
status = "error";
break;
// some errors
default:
status = "warning";
break;
}
const clearFilePath = (filePath: string) => {
const relative = filePath?.replace(process.cwd(), "");
if (relative?.startsWith("/")) {
return relative.slice(1);
}
if (relative?.startsWith("./")) {
return relative.slice(2);
}
return relative;
};
const printStatusMessage = () => {
switch (status) {
case "success":
console.log(
chalk.blueBright(`Successfully swizzled ${chalk.bold(label)}`),
);
return;
case "warning":
console.log(
chalk.yellowBright(
`Swizzle completed with errors for ${chalk.bold(label)}`,
),
);
return;
case "error":
console.log(chalk.redBright(`Swizzle failed for ${chalk.bold(label)}`));
return;
default:
return;
}
};
const printFiles = () => {
const chalks = [];
chalks.push(chalk.dim(`File${files.length > 1 ? "s" : ""} created:`));
chalks.push(
files
.map(([targetPath, statusCode]) => {
if (statusCode === SWIZZLE_CODES.SUCCESS) {
return chalk.cyanBright.dim(` - ${clearFilePath(targetPath)}`);
}
if (statusCode === SWIZZLE_CODES.TARGET_ALREADY_EXISTS) {
return chalk.cyanBright.dim(
` - ${chalk.yellowBright.bold(
"[FILE_ALREADY_EXISTS] ",
)}${clearFilePath(targetPath)}`,
);
}
if (statusCode === SWIZZLE_CODES.SOURCE_PATH_NOT_A_FILE) {
return chalk.cyanBright.dim(
` - ${chalk.yellowBright.bold(
"[SOURCE NOT FOUND] ",
)}${clearFilePath(targetPath)}`,
);
}
return chalk.cyanBright.dim(
` - ${chalk.yellowBright.bold(`[${statusCode}]`)}${clearFilePath(
targetPath,
)}`,
);
})
.join("\n"),
);
console.log(chalks.join("\n"));
};
const printSwizzleMessage = () => {
if (message && status !== "error") {
console.log(markedTerminalRenderer(dedent(`\n${message}`)));
}
};
console.log("");
printStatusMessage();
printFiles();
console.log("");
printSwizzleMessage();
};

View File

@@ -0,0 +1 @@
export * from "./table";

View File

@@ -0,0 +1,48 @@
import * as packageUtils from "@utils/package";
import { getInstallCommand } from "./table";
test("Update warning npm command", async () => {
const testCases: {
output: string;
dependencies: string[];
scripts: Record<string, string>;
}[] = [
// have script, have dependency
{
output: "pnpm run refine update",
dependencies: ["@refinedev/cli"],
scripts: {
refine: "refine",
},
},
// has script, no dependency
{
output: "pnpm run refine update",
dependencies: ["@pankod/refine-cli"],
scripts: {
refine: "refine",
},
},
// no script, has dependency
{
output: "npx refine update",
dependencies: ["@refinedev/cli"],
scripts: {},
},
// no script, no dependency
{
output: "npx @refinedev/cli update",
dependencies: [],
scripts: {},
},
];
for (const testCase of testCases) {
jest
.spyOn(packageUtils, "getDependencies")
.mockReturnValue(testCase.dependencies);
jest.spyOn(packageUtils, "getScripts").mockReturnValue(testCase.scripts);
expect(await getInstallCommand()).toBe(testCase.output);
}
});

View File

@@ -0,0 +1,79 @@
import type { RefinePackageInstalledVersionData } from "@definitions/package";
import chalk from "chalk";
import center from "center-align";
import { getDependencies, getPreferedPM, getScripts } from "@utils/package";
import { getVersionTable } from "@components/version-table";
export interface UpdateWarningTableParams {
data: RefinePackageInstalledVersionData[];
}
export const printUpdateWarningTable = async (
params: UpdateWarningTableParams,
) => {
const data = params?.data;
const tableHead = Object.keys(data?.[0] || {});
if (!data || !tableHead.length) return;
const { table, width } = getVersionTable(data);
console.log();
console.log(center("Update Available", width));
console.log();
console.log(
`- ${chalk.yellow(
chalk.bold("Current"),
)}: The version of the package that is currently installed`,
);
console.log(
`- ${chalk.yellow(
chalk.bold("Wanted"),
)}: The maximum version of the package that satisfies the semver range specified in \`package.json\``,
);
console.log(
`- ${chalk.yellow(
chalk.bold("Latest"),
)}: The latest version of the package available on npm`,
);
console.log(table);
console.log(
center(
`To update ${chalk.bold("`Refine`")} packages with wanted version`,
width,
),
);
console.log(
center(
` Run the following command: ${chalk.yellowBright(
await getInstallCommand(),
)}`,
width,
),
);
console.log();
};
export const getInstallCommand = async () => {
const fallbackCommand = "npx @refinedev/cli update";
const dependencies = getDependencies();
const scriptKeys = Object.keys(getScripts());
const hasCli = dependencies.includes("@refinedev/cli");
const hasScript = scriptKeys.includes("refine");
if (!hasCli && !hasScript) {
return fallbackCommand;
}
const pm = await getPreferedPM();
if (hasScript) {
return `${pm.name} run refine update`;
}
if (hasCli) {
return "npx refine update";
}
return fallbackCommand;
};

View File

@@ -0,0 +1,151 @@
import type { RefinePackageInstalledVersionData } from "@definitions/package";
import Table from "cli-table3";
import chalk from "chalk";
import { removeANSIColors } from "@utils/text";
const columns = {
name: "name",
current: "current",
wanted: "wanted",
latest: "latest",
changelog: "changelog",
} as const;
const orderedColumns: (typeof columns)[keyof typeof columns][] = [
columns.name,
columns.current,
columns.wanted,
columns.latest,
columns.changelog,
];
export const getVersionTable = (
packages: RefinePackageInstalledVersionData[] = [],
) => {
const tableHead = Object.keys(packages?.[0] || {});
if (!packages || !tableHead.length) return { table: "", width: 0 };
const terminalWidth = process.stdout.columns || 80;
const nameColumnWidth =
Math.max(...packages.map((row) => row.name.length)) + 2;
const versionColumnWidth = 7 + 2;
const bordersWidth = 6;
const changelogColumnWidth = Math.min(
35,
terminalWidth - nameColumnWidth - versionColumnWidth * 3 - bordersWidth,
);
const columnWidths = {
name: nameColumnWidth,
current: versionColumnWidth,
wanted: versionColumnWidth,
latest: versionColumnWidth,
changelog: changelogColumnWidth,
} as const;
const table = new Table({
head: orderedColumns,
wordWrap: false,
wrapOnWordBoundary: true,
colWidths: orderedColumns.map((column) => columnWidths[column]),
style: {
head: ["blue"],
},
});
const ellipsisFromCenter = (text: string, length: number) => {
// if text is longer than length, cut it from the center to fit the length (add ellipsis)
if (text.length > length) {
const fitLength = length - 3;
const start = text.slice(0, Math.floor(fitLength / 2));
const end = text.slice(-Math.ceil(fitLength / 2));
return `${start}...${end}`;
}
return text;
};
packages.forEach((row) => {
table.push(
orderedColumns.map((column) => {
const columnValue = row[column];
if (!columnValue) return columnValue;
if (column === "latest" || column === "wanted") {
const installedVersion = parseVersions(row.current);
const latestVersion = parseVersions(columnValue);
const colors = getColorsByVersionDiffrence(
installedVersion,
latestVersion,
);
const textMajor = chalk[colors.major](latestVersion.major);
const textMinor = chalk[colors.minor](latestVersion.minor);
const textPatch = chalk[colors.patch](latestVersion.patch);
return `${textMajor}.${textMinor}.${textPatch}`;
}
if (column === "changelog") {
return chalk.blueBright.underline(columnValue);
}
return columnValue;
}),
);
});
const tableString = table.toString();
const tableWidth = removeANSIColors(
tableString.split("\n")?.[0] || "",
).length;
return { table: tableString, width: tableWidth };
};
const parseVersions = (text: string) => {
const versions = text.split(".");
return {
major: versions[0],
minor: versions[1],
patch: versions[2],
};
};
const getColorsByVersionDiffrence = (
installedVersion: ReturnType<typeof parseVersions>,
nextVersion: ReturnType<typeof parseVersions>,
) => {
const isMajorDiffrence =
installedVersion.major.trim() !== nextVersion.major.trim();
if (isMajorDiffrence)
return {
major: "red",
minor: "red",
patch: "red",
} as const;
const isMinorDiffrence =
installedVersion.minor.trim() !== nextVersion.minor.trim();
if (isMinorDiffrence)
return {
major: "white",
minor: "yellow",
patch: "yellow",
} as const;
const isPatchDiffrence =
installedVersion.patch.trim() !== nextVersion.patch.trim();
if (isPatchDiffrence)
return {
major: "white",
minor: "white",
patch: "green",
} as const;
return {
major: "white",
minor: "white",
patch: "white",
} as const;
};