@mateoserrano/simple-config 1.1.9 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +55 -15
  2. package/dist/core/commands/command.copy.factory.js +6 -0
  3. package/dist/core/commands/command.copy.factory.spec.js +10 -0
  4. package/dist/core/commands/command.copy.js +40 -0
  5. package/dist/core/commands/command.install.factory.js +11 -0
  6. package/dist/core/commands/command.install.factory.spec.js +23 -0
  7. package/dist/core/commands/command.js +12 -0
  8. package/dist/core/commands/command.silent.factory.js +6 -0
  9. package/dist/core/commands/command.silent.factory.spec.js +9 -0
  10. package/dist/core/commands/command.silent.js +15 -0
  11. package/dist/core/commands/command.spec.js +11 -0
  12. package/dist/core/commands/constants.js +11 -0
  13. package/dist/core/commands/index.js +3 -0
  14. package/dist/core/dependencies/constants.js +59 -0
  15. package/dist/core/dependencies/dependency.js +1 -0
  16. package/dist/core/dependencies/dependency.representation.factory.js +5 -0
  17. package/dist/core/dependencies/dependency.representation.factory.spec.js +16 -0
  18. package/dist/core/dependencies/index.js +2 -0
  19. package/dist/core/files/file.copier.js +32 -0
  20. package/dist/core/files/file.copier.spec.js +63 -0
  21. package/dist/core/files/file.handler.js +12 -0
  22. package/dist/core/files/index.js +4 -0
  23. package/dist/core/files/package.manager.js +30 -0
  24. package/dist/core/files/path.manager.js +9 -0
  25. package/dist/core/index.js +4 -0
  26. package/dist/core/utils/index.js +1 -0
  27. package/dist/core/utils/logger.js +11 -0
  28. package/dist/domain/helpers.js +25 -0
  29. package/dist/domain/index.js +1 -0
  30. package/dist/functions.js +32 -0
  31. package/dist/index.js +1 -0
  32. package/dist/instances.js +11 -0
  33. package/dist/scripts/init.js +6 -0
  34. package/dist/wires/constants.js +47 -0
  35. package/dist/wires/index.js +2 -0
  36. package/dist/wires/instances.js +13 -0
  37. package/package.json +12 -7
  38. package/templates/eslint.config.js +28 -6
  39. package/templates/lint-staged.config.js +1 -1
  40. package/templates/tsconfig.json +11 -3
  41. package/scripts/init.js +0 -13
  42. package/src/constants.js +0 -68
  43. package/src/core/commands.js +0 -4
  44. package/src/core/deps.js +0 -20
  45. package/src/core/files.js +0 -24
  46. package/src/core/index.js +0 -3
  47. package/src/core/urls.js +0 -20
  48. package/src/core/utils/files.js +0 -7
  49. package/src/core/utils/index.js +0 -1
  50. package/src/functions.js +0 -44
  51. package/src/index.js +0 -1
package/README.md CHANGED
@@ -1,29 +1,69 @@
1
1
  # Simple configuration for TypeScript development
2
2
 
3
3
  > This package is intended to be used as a development dependency.
4
- > No development dependency used to develop this package is necessarily
5
- > installed.
4
+ > To know that dependencies this package will install, do now refer
5
+ > to the GitHub repository of the project. Instead, refer to the
6
+ > [overview](#overview).
6
7
 
7
8
  ## Overview
8
9
 
9
- This package provides a quite simple configuration for common tools in
10
- TypeScript development. It will install the following dependencies to
11
- your project:
10
+ This package includes some simple configuration files for TypeScript
11
+ development. When installed, this package will include a script that:
12
12
 
13
- 1. TypeScript (tsx)
14
- 2. ESLint
15
- 3. Prettier
16
- 4. lint-staged
17
- 5. Husky
18
-
19
- And will configure husky to run only lint-staged when pre-committing.
13
+ * Installs a curated set of **development dependencies**. See more in
14
+ the [development dependencies](#development-dependencies) section.
15
+ * Creates template configuration files for:
16
+ * TypeScript
17
+ * ESLint (Flat Config)
18
+ * Prettier
19
+ * lint-staged
20
+ See more in the [configuration files](#configuration-files) section.
21
+ * Initializes **Husky** and registers a working `pre-commit` hook that
22
+ runs lint-staged.
20
23
 
21
24
  ## Installation
22
25
 
23
- The following commands will install the package and configure it for your
24
- project.
26
+ After installing this package, you must run the following script to install
27
+ the dependencies and set up Husky.
28
+
29
+ Run the following commands in your project's root directory:
25
30
 
26
31
  ```bash
27
- npm i -D @mateoserrano/simple-config
32
+ npm i @mateoserrano/simple-config --save-dev
28
33
  npx dev-config
29
34
  ```
35
+
36
+ ### Development dependencies
37
+
38
+ After having run the script, the following dependencies will have been installed:
39
+
40
+ * `typescript`
41
+ * `eslint`
42
+ * `typescript-eslint`
43
+ * `@eslint/js`
44
+ * `prettier`
45
+ * `eslint-config-prettier`
46
+ * `lint-staged`
47
+ * `husky`
48
+ * `globals`
49
+
50
+ ## Configuration files
51
+
52
+ After having run the script, the following configuration files will have been
53
+ created:
54
+
55
+ * `eslint.config.js`
56
+ * `prettier.config.js`
57
+ * `lint-staged.config.js`
58
+ * `tsconfig.json`
59
+
60
+ As they are templates, you might modify any of these to suit your needs, although
61
+ they should be enough to get you started.
62
+
63
+ Note that the `tsconfig.json` file sets the standard to ES2020 and the module type
64
+ to ESM.
65
+
66
+ ## 📄 License
67
+
68
+ MIT
69
+
@@ -0,0 +1,6 @@
1
+ import { CommandCopy } from './command.copy.js';
2
+ export class CommandCopyFactory {
3
+ create(source, destination) {
4
+ return new CommandCopy(source, destination);
5
+ }
6
+ }
@@ -0,0 +1,10 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { CommandCopyFactory } from './command.copy.factory.js';
3
+ describe('CommandCopyFactory', () => {
4
+ it('should create a valid copy command', () => {
5
+ const factory = new CommandCopyFactory();
6
+ const result = factory.create('ran', 'dom');
7
+ expect(result.getSource()).toEqual('ran');
8
+ expect(result.getDestination()).toEqual('dom');
9
+ });
10
+ });
@@ -0,0 +1,40 @@
1
+ import { basename, join } from 'node:path';
2
+ import { cpSync, existsSync, mkdirSync } from 'node:fs';
3
+ import { Logger } from '../utils/index.js';
4
+ import { Command } from './command.js';
5
+ export class CommandCopy {
6
+ constructor(source, destination) {
7
+ this.destination = destination;
8
+ this.logger = new Logger();
9
+ this.command = new Command(source, (src) => {
10
+ this.copyFileToFolderOrSkip(src, this.destination);
11
+ });
12
+ }
13
+ run() {
14
+ this.command.run();
15
+ }
16
+ getSource() {
17
+ return this.command.getCommand();
18
+ }
19
+ getDestination() {
20
+ return this.destination;
21
+ }
22
+ copyFileToFolderOrSkip(sourceFile, targetDirectory) {
23
+ const sourceFileName = basename(sourceFile);
24
+ const outputFileName = join(targetDirectory, sourceFileName);
25
+ if (!existsSync(sourceFile)) {
26
+ this.logger.error(`File does not exist: ${sourceFile}`);
27
+ return;
28
+ }
29
+ if (!existsSync(targetDirectory)) {
30
+ this.logger.log(`Creating folder ${targetDirectory}...`);
31
+ mkdirSync(targetDirectory, { recursive: true });
32
+ }
33
+ if (existsSync(outputFileName)) {
34
+ this.logger.log(`File ${sourceFileName} already exists in ${targetDirectory}. Skipping...`);
35
+ return;
36
+ }
37
+ const destinationPath = join(targetDirectory, sourceFileName);
38
+ cpSync(sourceFile, destinationPath);
39
+ }
40
+ }
@@ -0,0 +1,11 @@
1
+ import { DependencyRepresentationFactory } from '../dependencies/index.js';
2
+ import { CommandSilentFactory } from './command.silent.factory.js';
3
+ export class CommandInstallFactory {
4
+ constructor() {
5
+ this.dependencyRepresentationFactory = new DependencyRepresentationFactory();
6
+ this.commandSilentFactory = new CommandSilentFactory();
7
+ }
8
+ create(dependencies) {
9
+ return this.commandSilentFactory.create(`npm i -D ${dependencies.map(this.dependencyRepresentationFactory.create).join(' ')} --save-exact`);
10
+ }
11
+ }
@@ -0,0 +1,23 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { faker } from '@faker-js/faker';
3
+ import { CommandInstallFactory } from './command.install.factory.js';
4
+ function makeDependency(overrides = {}) {
5
+ return {
6
+ name: faker.word.noun(),
7
+ ...(faker.datatype.boolean()
8
+ ? { version: faker.system.semver() }
9
+ : {}),
10
+ ...overrides,
11
+ };
12
+ }
13
+ describe('CommandInstallFactory', () => {
14
+ let factory;
15
+ beforeEach(() => {
16
+ factory = new CommandInstallFactory();
17
+ });
18
+ it('should create a valid npm install command', () => {
19
+ const deps = Array.from({ length: 5 }, () => makeDependency());
20
+ const result = factory.create(deps);
21
+ expect(result.getCommand()).toEqual(`npm i -D ${deps.map((dep) => (dep.version ? `${dep.name}@${dep.version}` : dep.name)).join(' ')} --save-exact`);
22
+ });
23
+ });
@@ -0,0 +1,12 @@
1
+ export class Command {
2
+ constructor(command, runMechanism) {
3
+ this.command = command;
4
+ this.runMechanism = runMechanism;
5
+ }
6
+ run() {
7
+ this.runMechanism(this.command);
8
+ }
9
+ getCommand() {
10
+ return this.command;
11
+ }
12
+ }
@@ -0,0 +1,6 @@
1
+ import { CommandSilent } from './command.silent.js';
2
+ export class CommandSilentFactory {
3
+ create(command) {
4
+ return new CommandSilent(command);
5
+ }
6
+ }
@@ -0,0 +1,9 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { CommandSilentFactory } from './command.silent.factory.js';
3
+ describe('CommandSilentFactory', () => {
4
+ it('should create a valid silent command', () => {
5
+ const factory = new CommandSilentFactory();
6
+ const result = factory.create('random');
7
+ expect(result.getCommand()).toEqual('random');
8
+ });
9
+ });
@@ -0,0 +1,15 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { Command } from './command.js';
3
+ export class CommandSilent {
4
+ constructor(command) {
5
+ this.command = new Command(command, () => {
6
+ execSync(command, { stdio: 'ignore' });
7
+ });
8
+ }
9
+ run() {
10
+ this.command.run();
11
+ }
12
+ getCommand() {
13
+ return this.command.getCommand();
14
+ }
15
+ }
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { Command } from './command.js';
3
+ describe('Command', () => {
4
+ it('should log the command', () => {
5
+ const commandString = 'hello world!';
6
+ const runMechanism = vi.fn();
7
+ const command = new Command(commandString, runMechanism);
8
+ command.run();
9
+ expect(runMechanism).toHaveBeenCalledWith(commandString);
10
+ });
11
+ });
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setUpHuskyCommand = exports.prepareHuskyCommand = exports.addHuskyPrepareCommand = void 0;
4
+ const command_silent_factory_1 = require("./command.silent.factory");
5
+ const commandSilentFactory = new command_silent_factory_1.CommandSilentFactory();
6
+ const addHuskyPrepare = 'npm pkg set scripts.prepare="husky init"';
7
+ const prepareHusky = 'npm run prepare';
8
+ const setUpHusky = 'echo "npx lint-staged" > .husky/pre-commit';
9
+ exports.addHuskyPrepareCommand = commandSilentFactory.create(addHuskyPrepare);
10
+ exports.prepareHuskyCommand = commandSilentFactory.create(prepareHusky);
11
+ exports.setUpHuskyCommand = commandSilentFactory.create(setUpHusky);
@@ -0,0 +1,3 @@
1
+ export * from './command.silent.js';
2
+ export * from './command.silent.factory.js';
3
+ export * from './command.install.factory.js';
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.devDepFiles = exports.devDeps = void 0;
4
+ exports.devDeps = [
5
+ {
6
+ name: 'tsx',
7
+ version: '4.20.6',
8
+ },
9
+ {
10
+ name: 'eslint',
11
+ version: '9.39.1',
12
+ },
13
+ {
14
+ name: 'typescript-eslint',
15
+ version: '8.46.4',
16
+ },
17
+ {
18
+ name: '@eslint/js',
19
+ version: '9.39.1',
20
+ },
21
+ {
22
+ name: 'prettier',
23
+ version: '3.6.2',
24
+ },
25
+ {
26
+ name: 'eslint-config-prettier',
27
+ version: '10.1.8',
28
+ },
29
+ {
30
+ name: 'lint-staged',
31
+ version: '16.2.7',
32
+ },
33
+ {
34
+ name: 'husky',
35
+ version: '9.1.7',
36
+ },
37
+ {
38
+ name: 'globals',
39
+ version: '17.0.0',
40
+ }
41
+ ];
42
+ exports.devDepFiles = [
43
+ {
44
+ source: 'eslint.config.js',
45
+ target: '.',
46
+ },
47
+ {
48
+ source: 'prettier.config.js',
49
+ target: '.',
50
+ },
51
+ {
52
+ source: 'lint-staged.config.js',
53
+ target: '.',
54
+ },
55
+ {
56
+ source: 'tsconfig.json',
57
+ target: '.',
58
+ },
59
+ ];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ export class DependencyRepresentationFactory {
2
+ create(dependency) {
3
+ return dependency.version ? `${dependency.name}@${dependency.version}` : dependency.name;
4
+ }
5
+ }
@@ -0,0 +1,16 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { DependencyRepresentationFactory } from './dependency.representation.factory.js';
3
+ describe('DependencyRepresentationFactory', () => {
4
+ let factory;
5
+ beforeEach(() => {
6
+ factory = new DependencyRepresentationFactory();
7
+ });
8
+ it('should create <name>@<version>', () => {
9
+ const result = factory.create({ name: 'random', version: 'random' });
10
+ expect(result).toEqual('random@random');
11
+ });
12
+ it('should create <name>', () => {
13
+ const result = factory.create({ name: 'random' });
14
+ expect(result).toEqual('random');
15
+ });
16
+ });
@@ -0,0 +1,2 @@
1
+ export * from './dependency.js';
2
+ export * from './dependency.representation.factory.js';
@@ -0,0 +1,32 @@
1
+ import { PathManager } from './path.manager.js';
2
+ export class FileCopier {
3
+ constructor(fileHandler, logger) {
4
+ this.fileHandler = fileHandler;
5
+ this.logger = logger;
6
+ this.pathManager = new PathManager();
7
+ }
8
+ createFolderIfNotExist(folder) {
9
+ if (!this.fileHandler.verifyIfFileExists(folder)) {
10
+ this.logger.log(`Creating folder ${folder}...`);
11
+ this.fileHandler.createFolder(folder);
12
+ }
13
+ }
14
+ copyFileToFolder(fileName, folder) {
15
+ if (!this.fileHandler.verifyIfFileExists(fileName)) {
16
+ this.logger.error(`File does not exist: ${fileName}`);
17
+ return;
18
+ }
19
+ this.createFolderIfNotExist(folder);
20
+ const outputFileName = this.pathManager.changeDirectory(folder, this.pathManager.getFileBasename(fileName));
21
+ this.fileHandler.copyFile(fileName, outputFileName);
22
+ }
23
+ copyFileToFolderOrSkip(fileName, folder) {
24
+ const fileBasename = this.pathManager.getFileBasename(fileName);
25
+ const outputFileName = this.pathManager.changeDirectory(folder, fileBasename);
26
+ if (this.fileHandler.verifyIfFileExists(outputFileName)) {
27
+ this.logger.log(`File ${fileBasename} already exists in ${folder}. Skipping...`);
28
+ return;
29
+ }
30
+ this.copyFileToFolder(fileName, folder);
31
+ }
32
+ }
@@ -0,0 +1,63 @@
1
+ import { basename, join } from 'node:path';
2
+ import { describe, it, beforeEach, vi, expect } from 'vitest';
3
+ import { faker } from '@faker-js/faker';
4
+ import { FileCopier } from './file.copier.js';
5
+ describe('FileCopier', () => {
6
+ faker.seed(404);
7
+ let fileHandler;
8
+ let logger;
9
+ let fileCopier;
10
+ beforeEach(() => {
11
+ fileHandler = {
12
+ createFolder: vi.fn(),
13
+ verifyIfFileExists: vi.fn(),
14
+ copyFile: vi.fn(),
15
+ };
16
+ logger = {
17
+ log: vi.fn(),
18
+ error: vi.fn(),
19
+ };
20
+ fileCopier = new FileCopier(fileHandler, logger);
21
+ });
22
+ describe('copyFileToFolder', () => {
23
+ it('should copy files to folder', () => {
24
+ const file = faker.system.filePath();
25
+ const folder = faker.system.directoryPath();
26
+ const outputFileName = join(folder, basename(file));
27
+ fileHandler.verifyIfFileExists.mockReturnValue(true);
28
+ fileCopier.copyFileToFolder(file, folder);
29
+ expect(fileHandler.copyFile).toHaveBeenCalledWith(file, outputFileName);
30
+ });
31
+ it('should call logger.error if file does not exist', () => {
32
+ fileHandler.verifyIfFileExists.mockReturnValue(false);
33
+ fileCopier.copyFileToFolder('dummy', 'dummy');
34
+ expect(logger.error).toHaveBeenCalled();
35
+ });
36
+ it('should create folder if it does not exist', () => {
37
+ const folder = faker.system.directoryPath();
38
+ fileHandler.verifyIfFileExists.mockReturnValueOnce(true).mockReturnValueOnce(false);
39
+ fileCopier.copyFileToFolder('dummy', folder);
40
+ expect(logger.log).toHaveBeenCalled();
41
+ expect(fileHandler.createFolder).toHaveBeenCalledWith(folder);
42
+ });
43
+ });
44
+ describe('copyFileToFolderOrSkip', () => {
45
+ let spy;
46
+ beforeEach(() => {
47
+ spy = vi.spyOn(fileCopier, 'copyFileToFolder');
48
+ });
49
+ it('should log if file exist', () => {
50
+ fileHandler.verifyIfFileExists.mockReturnValue(true);
51
+ fileCopier.copyFileToFolderOrSkip('dummy', 'dummy');
52
+ expect(logger.log).toHaveBeenCalled();
53
+ expect(spy).not.toHaveBeenCalled();
54
+ });
55
+ it('should call copyFileToFolder if file does not exist', () => {
56
+ const file = faker.system.filePath();
57
+ const folder = faker.system.directoryPath();
58
+ fileHandler.verifyIfFileExists.mockReturnValue(false);
59
+ fileCopier.copyFileToFolderOrSkip(file, folder);
60
+ expect(spy).toHaveBeenCalledWith(file, folder);
61
+ });
62
+ });
63
+ });
@@ -0,0 +1,12 @@
1
+ import { cpSync, existsSync, mkdirSync } from 'node:fs';
2
+ export class FileHandler {
3
+ createFolder(folderName, recursive = true) {
4
+ mkdirSync(folderName, { recursive });
5
+ }
6
+ verifyIfFileExists(filePath) {
7
+ return existsSync(filePath);
8
+ }
9
+ copyFile(source, destination) {
10
+ return cpSync(source, destination);
11
+ }
12
+ }
@@ -0,0 +1,4 @@
1
+ export { FileCopier } from './file.copier.js';
2
+ export { FileHandler } from './file.handler.js';
3
+ export { PathManager } from './path.manager.js';
4
+ export { PackageManager } from './package.manager.js';
@@ -0,0 +1,30 @@
1
+ import { dirname } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ export class PackageManager {
4
+ constructor(fileHandler, pathManager) {
5
+ this.fileHandler = fileHandler;
6
+ this.pathManager = pathManager;
7
+ }
8
+ getDirnameFromFileInPackage(fileName) {
9
+ let current = dirname(fileURLToPath(import.meta.url));
10
+ while (true) {
11
+ if (this.fileHandler.verifyIfFileExists(this.pathManager.changeDirectory(current, fileName))) {
12
+ return current;
13
+ }
14
+ const parent = this.pathManager.changeDirectory(current, '..');
15
+ if (parent === current) {
16
+ throw new Error(`File ${fileName} not found`);
17
+ }
18
+ current = parent;
19
+ }
20
+ }
21
+ verifyValidPackage(folder) {
22
+ return this.fileHandler.verifyIfFileExists(this.pathManager.changeDirectory(folder, 'package.json'));
23
+ }
24
+ getPackageRootPath() {
25
+ return this.getDirnameFromFileInPackage('package.json');
26
+ }
27
+ getTemplatesFolderPath() {
28
+ return this.pathManager.changeDirectory(this.getDirnameFromFileInPackage('templates'), 'templates/');
29
+ }
30
+ }
@@ -0,0 +1,9 @@
1
+ import { basename, join } from 'node:path';
2
+ export class PathManager {
3
+ changeDirectory(folder, relativePath) {
4
+ return join(folder, relativePath);
5
+ }
6
+ getFileBasename(file) {
7
+ return basename(file);
8
+ }
9
+ }
@@ -0,0 +1,4 @@
1
+ export * from './commands/index.js';
2
+ export * from './dependencies/index.js';
3
+ export * from './files/index.js';
4
+ export * from './utils/index.js';
@@ -0,0 +1 @@
1
+ export * from './logger.js';
@@ -0,0 +1,11 @@
1
+ export class Logger {
2
+ log(message) {
3
+ console.log(message);
4
+ }
5
+ error(message) {
6
+ console.error(message);
7
+ }
8
+ warn(message) {
9
+ console.warn(message);
10
+ }
11
+ }
@@ -0,0 +1,25 @@
1
+ import { initHuskyCommand, prepareHuskyCommand, setUpHuskyCommand, devDeps, devDepFiles, logger, fileCopier, commandInstallFactory, packageManager, cwd, pathManager, } from '../wires/index.js';
2
+ export const assertValidNodePackage = () => {
3
+ if (!packageManager.verifyValidPackage(cwd)) {
4
+ logger.error('Error: package.json not found.');
5
+ process.exit(1);
6
+ }
7
+ };
8
+ export const installDependencies = () => {
9
+ logger.log('Installing dependencies...');
10
+ commandInstallFactory.create(devDeps).run();
11
+ };
12
+ export const configureHusky = () => {
13
+ logger.log('Configuring Husky...');
14
+ initHuskyCommand.run();
15
+ prepareHuskyCommand.run();
16
+ setUpHuskyCommand.run();
17
+ };
18
+ export const copyConfigurationFiles = () => {
19
+ logger.log('Copying configuration files...');
20
+ const templatesDirectory = packageManager.getTemplatesFolderPath();
21
+ devDepFiles.forEach((file) => {
22
+ logger.log(`Copying file ${file}...`);
23
+ fileCopier.copyFileToFolderOrSkip(pathManager.changeDirectory(templatesDirectory, file), cwd);
24
+ });
25
+ };
@@ -0,0 +1 @@
1
+ export * from './helpers.js';
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.copyConfigurationFiles = exports.configureHusky = exports.installDependencies = exports.assertValidNodePackage = void 0;
4
+ const wires_1 = require("./wires");
5
+ const assertValidNodePackage = () => {
6
+ if (!wires_1.packageManager.verifyValidPackage(wires_1.cwd)) {
7
+ wires_1.logger.error('Error: package.json not found.');
8
+ process.exit(1);
9
+ }
10
+ };
11
+ exports.assertValidNodePackage = assertValidNodePackage;
12
+ const installDependencies = () => {
13
+ wires_1.logger.log('Installing dependencies...');
14
+ wires_1.commandInstallFactory.create(wires_1.devDeps).run();
15
+ };
16
+ exports.installDependencies = installDependencies;
17
+ const configureHusky = () => {
18
+ wires_1.logger.log('Configuring Husky...');
19
+ wires_1.initHuskyCommand.run();
20
+ wires_1.prepareHuskyCommand.run();
21
+ wires_1.setUpHuskyCommand.run();
22
+ };
23
+ exports.configureHusky = configureHusky;
24
+ const copyConfigurationFiles = () => {
25
+ wires_1.logger.log('Copying configuration files...');
26
+ const templatesDirectory = wires_1.packageManager.getTemplatesFolderPath();
27
+ wires_1.devDepFiles.forEach((file) => {
28
+ wires_1.logger.log(`Copying file ${file}...`);
29
+ wires_1.fileCopier.copyFileToFolderOrSkip(file.source, wires_1.pathManager.changeDirectory(templatesDirectory, file.target));
30
+ });
31
+ };
32
+ exports.copyConfigurationFiles = copyConfigurationFiles;
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from './domain/helpers.js';
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cwd = exports.packageManager = exports.commandInstallFactory = exports.fileCopier = exports.fileHandler = exports.pathManager = exports.logger = void 0;
4
+ const core_1 = require("./core");
5
+ exports.logger = new core_1.Logger();
6
+ exports.pathManager = new core_1.PathManager();
7
+ exports.fileHandler = new core_1.FileHandler();
8
+ exports.fileCopier = new core_1.FileCopier(exports.fileHandler, exports.logger);
9
+ exports.commandInstallFactory = new core_1.CommandInstallFactory();
10
+ exports.packageManager = new core_1.PackageManager(exports.fileHandler, exports.pathManager);
11
+ exports.cwd = process.cwd();
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import { assertValidNodePackage, installDependencies, configureHusky, copyConfigurationFiles, } from '../index.js';
3
+ assertValidNodePackage();
4
+ installDependencies();
5
+ configureHusky();
6
+ copyConfigurationFiles();
@@ -0,0 +1,47 @@
1
+ export const devDeps = [
2
+ {
3
+ name: 'typescript',
4
+ version: '5.9.3',
5
+ },
6
+ {
7
+ name: 'eslint',
8
+ version: '9.39.1',
9
+ },
10
+ {
11
+ name: 'typescript-eslint',
12
+ version: '8.46.4',
13
+ },
14
+ {
15
+ name: '@eslint/js',
16
+ version: '9.39.1',
17
+ },
18
+ {
19
+ name: 'prettier',
20
+ version: '3.6.2',
21
+ },
22
+ {
23
+ name: 'eslint-config-prettier',
24
+ version: '10.1.8',
25
+ },
26
+ {
27
+ name: 'lint-staged',
28
+ version: '16.2.7',
29
+ },
30
+ {
31
+ name: 'husky',
32
+ version: '9.1.7',
33
+ },
34
+ {
35
+ name: 'globals',
36
+ version: '17.0.0',
37
+ },
38
+ ];
39
+ export const devDepFiles = [
40
+ 'eslint.config.js',
41
+ 'prettier.config.js',
42
+ 'lint-staged.config.js',
43
+ 'tsconfig.json',
44
+ ];
45
+ export const initHusky = 'npx husky init';
46
+ export const prepareHusky = 'npm run prepare';
47
+ export const setUpHusky = 'echo "npx lint-staged" > .husky/pre-commit';
@@ -0,0 +1,2 @@
1
+ export * from './constants.js';
2
+ export * from './instances.js';
@@ -0,0 +1,13 @@
1
+ import { Logger, PathManager, FileHandler, FileCopier, CommandInstallFactory, CommandSilentFactory, PackageManager, } from '../core/index.js';
2
+ import { initHusky, prepareHusky, setUpHusky } from './constants.js';
3
+ const commandSilentFactory = new CommandSilentFactory();
4
+ export const logger = new Logger();
5
+ export const pathManager = new PathManager();
6
+ export const fileHandler = new FileHandler();
7
+ export const fileCopier = new FileCopier(fileHandler, logger);
8
+ export const commandInstallFactory = new CommandInstallFactory();
9
+ export const packageManager = new PackageManager(fileHandler, pathManager);
10
+ export const cwd = process.cwd();
11
+ export const initHuskyCommand = commandSilentFactory.create(initHusky);
12
+ export const prepareHuskyCommand = commandSilentFactory.create(prepareHusky);
13
+ export const setUpHuskyCommand = commandSilentFactory.create(setUpHusky);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mateoserrano/simple-config",
3
- "version": "1.1.9",
3
+ "version": "1.2.1",
4
4
  "description": "Initialize ESLint, Prettier, Husky and lint-staged for modern TypeScript projects",
5
5
  "license": "MIT",
6
6
  "author": "Mateo Serrano (https://github.com/Mateo-Serrano-24504)",
@@ -23,20 +23,20 @@
23
23
  "url": "https://github.com/Mateo-Serrano-24504/simple-config/issues"
24
24
  },
25
25
  "files": [
26
- "scripts/",
26
+ "dist/",
27
27
  "templates/",
28
- "src/**",
29
28
  "README.md",
30
29
  "LICENSE"
31
30
  ],
32
31
  "bin": {
33
- "dev-config": "./scripts/init.js"
32
+ "dev-config": "dist/scripts/init.js"
34
33
  },
35
34
  "engines": {
36
35
  "node": ">=20"
37
36
  },
38
37
  "devDependencies": {
39
38
  "@eslint/js": "9.39.1",
39
+ "@faker-js/faker": "^10.2.0",
40
40
  "@types/node": "25.0.3",
41
41
  "eslint": "9.39.1",
42
42
  "eslint-config-prettier": "10.1.8",
@@ -44,10 +44,15 @@
44
44
  "husky": "9.1.7",
45
45
  "lint-staged": "16.2.7",
46
46
  "prettier": "3.6.2",
47
- "tsx": "4.20.6",
48
- "typescript-eslint": "8.46.4"
47
+ "standard-version": "^9.5.0",
48
+ "typescript": "5.9.3",
49
+ "typescript-eslint": "8.46.4",
50
+ "vitest": "4.0.17"
49
51
  },
50
52
  "scripts": {
51
- "prepare": "husky"
53
+ "prepare": "husky",
54
+ "test": "vitest",
55
+ "build": "tsc",
56
+ "release": "standard-version"
52
57
  }
53
58
  }
@@ -1,17 +1,39 @@
1
+ import js from '@eslint/js'
1
2
  import globals from 'globals'
3
+ import tseslint from 'typescript-eslint'
2
4
 
3
- export default [
5
+ export default tseslint.config([
6
+ js.configs.recommended,
7
+ ...tseslint.configs.recommended,
4
8
  {
5
- files: ['**/*.js', '**/*.ts'],
9
+ ignores: ['dist/**'],
10
+ },
11
+ {
12
+ files: ['**/*.ts'],
6
13
  languageOptions: {
7
- ecmaVersion: 'latest',
8
- sourceType: 'module',
14
+ parser: tseslint.parser,
15
+ parserOptions: {
16
+ ecmaVersion: 'latest',
17
+ sourceType: 'module',
18
+ },
9
19
  globals: {
10
20
  ...globals.node,
11
21
  },
12
22
  },
23
+ plugins: {
24
+ '@typescript-eslint': tseslint.plugin,
25
+ },
13
26
  rules: {
14
- 'no-console': 'off',
27
+ '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
28
+ '@typescript-eslint/no-explicit-any': 'warn',
29
+ '@typescript-eslint/consistent-type-imports': 'warn',
30
+ },
31
+ },
32
+ {
33
+ files: ['**/*.js'],
34
+ languageOptions: {
35
+ sourceType: 'module',
36
+ globals: globals.node,
15
37
  },
16
38
  },
17
- ]
39
+ ])
@@ -1,3 +1,3 @@
1
1
  export default {
2
- '*.{ts,tsx,js,json}': ['eslint --fix', 'prettier --write'],
2
+ '*.{ts,js,json}': ['eslint --fix', 'prettier --write'],
3
3
  }
@@ -1,14 +1,22 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2020",
4
- "module": "commonjs",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+
5
7
  "outDir": "dist",
6
8
  "rootDir": "src",
9
+
7
10
  "esModuleInterop": true,
8
- "moduleResolution": "node",
9
11
  "resolveJsonModule": true,
10
- "forceConsistentCasingInFileNames": true,
12
+
11
13
  "strict": true,
14
+ "noImplicitOverride": true,
15
+ "noUncheckedIndexedAccess": true,
16
+ "exactOptionalPropertyTypes": true,
17
+ "useUnknownInCatchVariables": true,
18
+
19
+ "forceConsistentCasingInFileNames": true,
12
20
  "skipLibCheck": true
13
21
  },
14
22
  "include": ["src/**/*.ts"]
package/scripts/init.js DELETED
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import {
4
- assertValidNodePackage,
5
- installDependencies,
6
- configureHusky,
7
- copyConfigurationFiles,
8
- } from '../src/index.js'
9
-
10
- assertValidNodePackage()
11
- installDependencies()
12
- configureHusky()
13
- copyConfigurationFiles()
package/src/constants.js DELETED
@@ -1,68 +0,0 @@
1
- export const devDeps = {
2
- tsx: {
3
- package: 'tsx',
4
- version: '4.20.6',
5
- },
6
- eslint: {
7
- package: 'eslint',
8
- version: '9.39.1',
9
- },
10
- typescriptEslint: {
11
- package: 'typescript-eslint',
12
- version: '8.46.4',
13
- },
14
- eslintJs: {
15
- package: '@eslint/js',
16
- version: '9.39.1',
17
- },
18
- prettier: {
19
- package: 'prettier',
20
- version: '3.6.2',
21
- },
22
- eslintConfigPrettier: {
23
- package: 'eslint-config-prettier',
24
- version: '10.1.8',
25
- },
26
- lintStaged: {
27
- package: 'lint-staged',
28
- version: '16.2.7',
29
- },
30
- husky: {
31
- package: 'husky',
32
- version: '9.1.7',
33
- },
34
- globals: {
35
- package: 'globals',
36
- version: '17.0.0',
37
- }
38
- }
39
- export const devDepFiles = {
40
- eslint: [
41
- {
42
- source: 'eslint.config.js',
43
- target: '.',
44
- },
45
- ],
46
- prettier: [
47
- {
48
- source: 'prettier.config.js',
49
- target: '.',
50
- },
51
- ],
52
- lintStaged: [
53
- {
54
- source: 'lint-staged.config.js',
55
- target: '.',
56
- },
57
- ],
58
- typescript: [
59
- {
60
- source: 'tsconfig.json',
61
- target: '.',
62
- },
63
- ],
64
- }
65
- export const addHuskyPrepare = 'npm pkg set scripts.prepare="husky init"'
66
- export const installCmd = (installNames) => `npm install -D ${installNames.join(' ')} --save-exact`
67
- export const prepareHuskyCommand = 'npm run prepare'
68
- export const setupHuskyCommand = 'echo "npx lint-staged" > .husky/pre-commit'
@@ -1,4 +0,0 @@
1
- import { execSync } from 'node:child_process'
2
-
3
- export const runCommand = (command) => execSync(command, { stdio: 'inherit' })
4
- export const runCommandSilent = (command) => execSync(command, { stdio: 'ignore' })
package/src/core/deps.js DELETED
@@ -1,20 +0,0 @@
1
- import { moveFromPath } from './utils/index.js'
2
- import { getPackageRoot } from './urls.js'
3
- import { copyFileToFolderOrSkip } from './files.js'
4
-
5
- export const getTemplatesFolder = (templatesRelativePath) => {
6
- const packageRoot = getPackageRoot()
7
- return moveFromPath(packageRoot, templatesRelativePath)
8
- }
9
- export const getInstallNames = (devDeps) =>
10
- Object.values(devDeps).map((dep) => `${dep.package}@${dep.version}`)
11
- export const copyFilesToTargetOrSkip = (devDepFiles, templatesDirectory) => {
12
- const cwd = process.cwd()
13
- Object.values(devDepFiles).forEach((group) =>
14
- group.forEach((file) => {
15
- const source = moveFromPath(templatesDirectory, file.source)
16
- const targetFolder = moveFromPath(cwd, file.target)
17
- copyFileToFolderOrSkip(source, targetFolder)
18
- }),
19
- )
20
- }
package/src/core/files.js DELETED
@@ -1,24 +0,0 @@
1
- import { basename } from 'node:path'
2
- import { cpSync } from 'node:fs'
3
- import { createFolder, verifyValidFile, verifyValidDirectory, moveFromPath } from './utils/index.js'
4
-
5
- export const verifyNodePackage = () => verifyValidFile(moveFromPath(process.cwd(), 'package.json'))
6
- export function copyFileToFolderOrSkip(sourceFile, targetDirectory) {
7
- const sourceFileName = basename(sourceFile)
8
- const outputFileName = moveFromPath(targetDirectory, sourceFileName)
9
-
10
- if (!verifyValidFile(sourceFile)) {
11
- console.error(`File does not exist: ${sourceFile}`)
12
- return
13
- }
14
- if (!verifyValidDirectory(targetDirectory)) {
15
- console.log(`Creating folder ${targetDirectory}...`)
16
- createFolder(targetDirectory)
17
- }
18
- if (verifyValidFile(outputFileName)) {
19
- console.log(`File ${sourceFileName} already exists in ${targetDirectory}. Skipping...`)
20
- return
21
- }
22
- const destinationPath = moveFromPath(targetDirectory, sourceFileName)
23
- cpSync(sourceFile, destinationPath)
24
- }
package/src/core/index.js DELETED
@@ -1,3 +0,0 @@
1
- export * from './commands.js'
2
- export * from './deps.js'
3
- export * from './files.js'
package/src/core/urls.js DELETED
@@ -1,20 +0,0 @@
1
- import { fileURLToPath } from 'node:url'
2
- import { moveFromPath, verifyValidFile } from './utils/files.js'
3
-
4
- export function getPackageRoot() {
5
- let current = fileURLToPath(new URL('.', import.meta.url))
6
-
7
- while (true) {
8
- if (verifyValidFile(moveFromPath(current, 'package.json'))) {
9
- return current
10
- }
11
-
12
- const parent = moveFromPath(current, '..')
13
-
14
- if (parent === current) {
15
- throw new Error('package.json not found')
16
- }
17
-
18
- current = parent
19
- }
20
- }
@@ -1,7 +0,0 @@
1
- import { join } from 'node:path'
2
- import { existsSync, mkdirSync } from 'node:fs'
3
-
4
- export const createFolder = (dirname) => mkdirSync(dirname, { recursive: true })
5
- export const verifyValidFile = (filePath) => existsSync(filePath)
6
- export const verifyValidDirectory = (directory) => existsSync(directory)
7
- export const moveFromPath = (directory, filename) => join(directory, filename)
@@ -1 +0,0 @@
1
- export * from './files.js'
package/src/functions.js DELETED
@@ -1,44 +0,0 @@
1
- import {
2
- copyFilesToTargetOrSkip,
3
- getInstallNames,
4
- getTemplatesFolder,
5
- runCommandSilent,
6
- verifyNodePackage,
7
- } from './core/index.js'
8
- import {
9
- addHuskyPrepare,
10
- devDepFiles,
11
- devDeps,
12
- installCmd,
13
- prepareHuskyCommand,
14
- setupHuskyCommand,
15
- } from './constants.js'
16
-
17
- const runAddPrepareCommand = () => runCommandSilent(addHuskyPrepare)
18
- const runInstallCommand = (installNames) => runCommandSilent(installCmd(installNames))
19
- const runHuskyCommand = () => {
20
- runCommandSilent(prepareHuskyCommand)
21
- runCommandSilent(setupHuskyCommand)
22
- }
23
- const getInstallationArguments = () => getInstallNames(devDeps)
24
-
25
- export const assertValidNodePackage = () => {
26
- if (!verifyNodePackage()) {
27
- console.error('Error: package.json not found.')
28
- process.exit(1)
29
- }
30
- }
31
- export const installDependencies = () => {
32
- console.log('Installing dependencies...')
33
- runAddPrepareCommand()
34
- runInstallCommand(getInstallationArguments())
35
- }
36
- export const configureHusky = () => {
37
- console.log('Configuring Husky...')
38
- runHuskyCommand()
39
- }
40
- export const copyConfigurationFiles = () => {
41
- console.log('Copying configuration files...')
42
- const templatesDirectory = getTemplatesFolder('templates')
43
- copyFilesToTargetOrSkip(devDepFiles, templatesDirectory)
44
- }
package/src/index.js DELETED
@@ -1 +0,0 @@
1
- export * from './functions.js'