Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ const config: JestConfigWithTsJest = {
transform: {
"^.+\\.[tj]sx?$": ["ts-jest", tsJestTransformOptions],
},
collectCoverageFrom: [
"src/**"
],
};

export default config;
19 changes: 18 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"ts-jest-mock-import-meta": "^1.2.1",
"ts-node-dev": "^2.0.0",
"tsx": "^4.19.2",
"typescript": "^5.7.3"
"typescript": "^5.7.3",
"unionfs": "^4.5.4"
}
}
7 changes: 7 additions & 0 deletions src/__fixtures__/mock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Voluptate qui rem ut iure recusandae non voluptate.
Consequatur qui quos REPLACE_THIS optio quaerat voluptatem illo velit.
Rerum dolores possimus REPLACE_THIS non dolores.
Veniam sit quam porro rem distinctio omnis cumque suscipit. replace_this

REPLACE_THIS

7 changes: 7 additions & 0 deletions src/__fixtures__/templateMocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { NestedDirectoryJSON } from "memfs";

export const nestedDirectories: NestedDirectoryJSON = {
"nested-directory": {
"another-directory": null
}
}
File renamed without changes.
63 changes: 62 additions & 1 deletion src/__tests__/generatePluginFiles.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
import { transformFileContents, transformFileName } from "~/generatePluginFiles";
import path from "path";
import { vol, createFsFromVolume } from "memfs";
import { ufs } from "unionfs";
import generatePluginFiles, { transformFileContents, transformFileName } from "~/generatePluginFiles";
import { nestedDirectories } from "~/__fixtures__/templateMocks";
import assert from "assert";

jest.mock('fs', () => {
beforeEach(() => vol.mkdirSync(path.join(process.cwd(), '.playground'), { recursive: true }));
afterEach(() => vol.reset());

return ufs
.use(jest.requireActual('fs'))
.use(createFsFromVolume(vol) as any);
});

describe("transformFileName", () => {
const transforms = { "REPLACE_ME": "replaced" };
Expand Down Expand Up @@ -37,3 +51,50 @@ describe("transformFileContents", () => {
expect(result.split("\n").length).toBe(newlineSplits);
});
});

describe("generatePluginFiles", () => {
it("makes nested directories", () => {
vol.fromNestedJSON({ 'fixture': nestedDirectories });

generatePluginFiles("fixture", ".playground/newDir", {});

expect(ufs.existsSync(".playground/newDir")).toBe(true);
expect(ufs.existsSync(`.playground/newDir/${Object.keys(nestedDirectories)[0]}`)).toBe(true);
});

it("transforms file content", () => {
vol.fromNestedJSON({
'fixture': {
...nestedDirectories,
'REPLACE_THIS': ufs.readFileSync("src/__fixtures__/mock.md")
}
});

generatePluginFiles("fixture", ".playground/newDir", {
"REPLACE_THIS": "TO_THIS"
});

assert(ufs.existsSync(".playground/newDir/TO_THIS"));

const file = ufs.readFileSync(".playground/newDir/TO_THIS", "utf-8")
expect(file).toContain("TO_THIS");
expect(file).not.toContain("REPLACE_THIS");
});

it("moves gitignore in-place", () => {
vol.fromNestedJSON({
"fixture": {
"gitignore": "after",
".gitignore": "before",
}
});

generatePluginFiles("fixture", ".playground/newDir", {});

const dirContents = ufs.readdirSync(".playground/newDir");
expect(dirContents).toContain(".gitignore");
expect(dirContents).not.toContain("gitignore");

expect(ufs.readFileSync(".playground/newDir/.gitignore", "utf-8")).toEqual("after");
});
});
4 changes: 2 additions & 2 deletions src/generatePluginFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function transformFileContents(content: string, transforms?: Transforms):

// Source:
// https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/scripts/init.js
function renameOrOverwriteIfExistsGitignore(targetPath: string) {
function renameAndOverwriteIfExistsGitignore(targetPath: string) {
const gitignoreExists = fs.existsSync(path.join(targetPath, 'gitignore'));
if (!gitignoreExists) return;

Expand Down Expand Up @@ -67,7 +67,7 @@ function generatePluginFiles(templatePath: string, targetPath: string, transform
generatePluginFiles(originPath, destPath, transforms);
}

renameOrOverwriteIfExistsGitignore(targetPath);
renameAndOverwriteIfExistsGitignore(targetPath);
}

export default generatePluginFiles;
75 changes: 36 additions & 39 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,34 @@ renderMasthead();
renderCliInfo();
console.log();

const generateProject = new Promise(async (resolve, reject) => {
const dotnetCommands = [
'dotnet new solution',
'dotnet sln add src',
'dotnet build',
];

async function runShellCommands(commands: string[], targetPath: string) {
for (const command of commands) {
const startTime = performance.now();
const spinner = createSpinner(`Running '${command}'...`).start();

await new Promise<string>((resolve, reject) => {
exec(command, { cwd: targetPath }).on('close', code => {
if (code === 0) return resolve('done');
return reject(`Could not run command '${command}'`);
});
}).catch(e => {
spinner.fail(`Command '${command}' failed!`);
throw new Error(e);
});

const elapsed = Math.trunc(Math.abs(performance.now() - startTime));
spinner.succeed(`Ran '${command}' in ${elapsed}ms`);
}
}


const generateProject = new Promise<void>(async (resolve, reject) => {
let cancelled = false;
function onCancel() {
cancelled = true;
Expand All @@ -25,19 +52,12 @@ const generateProject = new Promise(async (resolve, reject) => {
const answers = await prompts(parameters, { onCancel });
if (cancelled) {
warn("Cancelled making a CounterStrikeSharp plugin.");
return resolve(true);
return resolve();
}

console.time("Done in");
const targetPath = path.resolve(TARGET_BASE, answers.containingDirectoryName);

const pluginName = (() => {
if (!answers.pluginSameName) {
return answers.pluginName;
}

return path.parse(answers.containingDirectoryName).base;
})();
const pluginName = answers.pluginName ?? path.parse(answers.containingDirectoryName).base;

if (fs.existsSync(targetPath)) {
return reject(`Path ${targetPath} already exists!`);
Expand All @@ -55,44 +75,21 @@ const generateProject = new Promise(async (resolve, reject) => {
fs.mkdirSync(targetPath, { recursive: true });
generatePluginFiles(templatePath, targetPath, transforms);

const dotnetCommands = [
'dotnet new solution',
'dotnet sln add src',
'dotnet build',
];

if (answers.setupUsingDotnetCli) {
for (const command of dotnetCommands) {
const startTime = performance.now();
const spinner = createSpinner(`Running '${command}'...`).start();

const doneOrError = await new Promise<string>((resolve, reject) => {
exec(command, { cwd: targetPath }).on('close', code => {
if (code === 0) return resolve('done');
return reject(`Could not run command '${command}'`);
});
}).catch(e => {
spinner.fail(`Command '${command}' failed!`);
return e;
});

if (doneOrError !== 'done') {
error(doneOrError);
return resolve(true);
}

const elapsed = Math.trunc(Math.abs(performance.now() - startTime));
spinner.succeed(`Ran '${command}' in ${elapsed}ms`);
try {
await runShellCommands(dotnetCommands, targetPath)
} catch (e) {
return reject(e);
}
}

console.timeEnd("Done in");
return resolve(true);
return resolve();
});

generateProject
.catch(err => {
error(err.message)
err instanceof Error ? error(err.message) : error(err);
if (!IS_PRODUCTION) console.error(err);
})
.finally(() => renderGoodbye());
2 changes: 1 addition & 1 deletion src/vanity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const HEADER = ` ____ _ ____ _ _ _ _
|_|
`;

const spinnerFrames = ((): any[] => {
const spinnerFrames = ((): string[] => {
const symbols = "⠁⠂⠄⡀⡈⡐⡠⣀⣁⣂⣄⣌⣔⣤⣥⣦⣮⣶⣷⣿⡿⠿⢟⠟⡛⠛⠫⢋⠋⠍⡉⠉⠑⠡⢁".split("");
const chunkLength = Math.round(Math.sqrt(symbols.length));

Expand Down