1.0.5 โ€ข Published 4 months ago

forji v1.0.5

Weekly downloads
-
License
-
Repository
-
Last release
4 months ago

๐Ÿ—๏ธ Project Builder

Version License: MIT TypeScript Node.js NPM

๐Ÿ“ A powerful, type-safe library for programmatically generating project structures with templates

โœจ Features

  • ๐ŸŽฏ Type-Safe - Written in TypeScript with complete type definitions
  • ๐Ÿงฉ Flexible - Create any folder/file structure with a simple object definition
  • ๐Ÿ”„ Template Variables - Use variables in file names and content
  • ๐Ÿ” File Discovery - Helpers to find files and folders in your generated structure
  • ๐ŸŽฎ Singleton Pattern - Easy to use across your application without managing state
  • ๐Ÿ“‚ Path Management - Access paths to your created files and folders
  • โšก Asynchronous - Built with promises for non-blocking performance

๐Ÿ“ฆ Installation

npm install forji
# or
yarn add forji
# or
pnpm add forji
# or
bun add forji

๐Ÿš€ Quick Start

import { Build } from 'forji';

async function main() {
  // Define your project structure
  const structure = {
    src: {
      components: {
        Button$tsx: 'export const Button = () => <button>Click me</button>;',
        index$ts: 'export * from "./Button";'
      },
      utils: {
        helpers$ts: 'export const sum = (a: number, b: number) => a + b;'
      },
      index$ts: 'export * from "./components";'
    },
    package$json: JSON.stringify({
      name: "{{projectName}}",
      version: "1.0.0"
    }, null, 2)
  };

  // Build the project with template variables
  await Build(structure, './my-project', {
    projectName: 'awesome-app'
  });

  console.log('๐ŸŽ‰ Project successfully generated!');
}

main().catch(console.error);

๐Ÿ“˜ API Reference

Core Functions

Build(structure, rootPath, variables)

๐Ÿ› ๏ธ Creates a project structure based on a configuration object.

import { Build } from 'forji';

const result = await Build(
  {
    'src': { /* folders and files */ },
    'README.md': '# My Project'
  },
  './output',
  { version: '1.0.0' }
);

getFolder(folderName)

๐Ÿ“‚ Retrieves the path of a folder by name.

import { getFolder } from 'forji';

const componentsPath = getFolder('components');
// -> '/path/to/project/src/components'

getFile(fileName)

๐Ÿ“„ Retrieves the path of a file by name.

import { getFile } from 'forji';

const readmePath = getFile('README.md');
// -> '/path/to/project/README.md'

getPath(name)

๐Ÿ” Retrieves the path of a file or folder by name.

import { getPath } from 'forji';

const path = getPath('Button.tsx');
// -> '/path/to/project/src/components/Button.tsx'

findFile(fileName, directory?)

๐Ÿ”Ž Recursively searches for a file starting from a directory.

import { findFile } from 'forji';

const configPath = await findFile('config.json');
// -> '/path/to/project/config.json' (if found)

ProjectBuilder Class

The ProjectBuilder class uses the singleton pattern and manages the internal state of your project.

import { ProjectBuilder } from 'forji';

const builder = ProjectBuilder.getInstance();
const tsFiles = builder.getFilesByExtension('ts');

Methods

  • getFilesByExtension(extension) - ๐Ÿท๏ธ Returns all files with the specified extension
  • getFilesInFolder(folderName) - ๐Ÿ“ Returns all files in a specific folder

๐Ÿ“ Template Variables

Project Builder supports powerful templating with variables that can be used in both file/folder names and content using the {{variableName}} syntax.

Basic Usage

Variables are defined in the third parameter of Build() and then referenced in your structure definition:

const structure = {
  'src': {
    '{{componentName}}$tsx': 'export const {{componentName}} = () => <div>Hello</div>;'
  }
};

await Build(structure, './output', {
  componentName: 'Header'
});
// Creates: ./output/src/Header.tsx with content: export const Header = () => <div>Hello</div>;

Supported Variable Types

The TemplateVariables type supports various primitive values:

type TemplateVariables = Record<string, string | number | boolean>;

// Example
await Build(structure, './output', {
  appName: 'MyAwesomeApp',       // string
  version: 1.0,                  // number
  isProduction: true,            // boolean
  port: 3000                     // number
});

Variables in File/Folder Names

Variables can be used in any part of a path:

const structure = {
  '{{srcFolder}}': {
    '{{componentFolder}}': {
      '{{prefix}}Button$tsx': '// {{copyright}}'
    }
  }
};

await Build(structure, './output', {
  srcFolder: 'src',
  componentFolder: 'components',
  prefix: 'UI',
  copyright: 'ยฉ 2025 Example Corp'
});
// Creates: ./output/src/components/UIButton.tsx

Variables in File Content

Variables shine when generating dynamic file content:

const structure = {
  'package$json': JSON.stringify({
    name: "{{projectName}}",
    version: "{{version}}",
    description: "{{description}}",
    scripts: {
      "start": "node dist/index.js",
      "dev": "nodemon --exec ts-node src/index.ts",
      "build": "tsc",
      "test": "{{testCommand}}"
    },
    dependencies: {{dependencies}}
  }, null, 2)
};

await Build(structure, './output', {
  projectName: 'api-service',
  version: '0.1.0',
  description: 'Backend API service',
  testCommand: 'jest --coverage',
  dependencies: JSON.stringify({
    "express": "^4.18.2",
    "dotenv": "^16.0.3"
  })
});

Dynamic Configuration Files

Generate configuration files with environment-specific settings:

function generateConfig(variables) {
  const env = variables.environment;
  
  let dbConfig = {};
  if (env === 'development') {
    dbConfig = {
      host: 'localhost',
      port: 5432
    };
  } else if (env === 'production') {
    dbConfig = {
      host: 'db.example.com',
      port: 5432,
      ssl: true
    };
  }
  
  return JSON.stringify({
    appName: variables.appName,
    port: variables.port,
    database: dbConfig,
    logLevel: env === 'development' ? 'debug' : 'info'
  }, null, 2);
}

const structure = {
  'config$json': generateConfig
};

await Build(structure, './my-app', {
  appName: 'MyService',
  environment: 'development',
  port: 3000
});

Combining with Content Generators

Variables can be mixed with dynamic content generation:

const structure = {
  src: {
    models: {
      '{{entityName}}$ts': () => {
        // This function has access to the variables via closure
        return `export interface {{entityName}} {
  id: string;
  name: string;
  createdAt: Date;
  {{customFields}}
}`;
      }
    }
  }
};

await Build(structure, './api', {
  entityName: 'User',
  customFields: `
  email: string;
  password: string;
  role: 'admin' | 'user';`
});

Variable Interpolation in Arrays or Objects

For complex structures, consider pre-processing with variables:

function generateRouteFiles(routes) {
  const files = {};
  
  routes.forEach(route => {
    const fileName = `${route.name}Route$ts`;
    files[fileName] = `import { Router } from 'express';
const router = Router();

router.get('/${route.path}', (req, res) => {
  res.json({ message: '${route.description}' });
});

export default router;`;
  });
  
  return files;
}

const routes = [
  { name: 'user', path: 'users', description: 'Get all users' },
  { name: 'product', path: 'products', description: 'Get all products' }
];

const structure = {
  'src': {
    'routes': generateRouteFiles(routes)
  }
};

await Build(structure, './api');

๐Ÿงช Advanced Usage

File Name Formatting

The library supports special formatting for file names:

const structure = {
  // Using $ for extensions
  'tsconfig$json': '{ "compilerOptions": {} }',
  
  // Using quotes for names with special characters
  '"README.md"': '# Project Documentation'
};

Accessing Build Results

import { Build, getFilesByExtension } from 'forji';

// Build project
const builder = await Build(structure, './output');

// Get all TypeScript files
const tsFiles = builder.getFilesByExtension('ts');

// Get all files in the components folder
const componentFiles = builder.getFilesInFolder('components');

๐Ÿ”ง Configuration Examples

React Project

const reactProject = {
  src: {
    components: {
      App$tsx: `import React from 'react';
export const App = () => <div>Hello World</div>;`,
      index$ts: 'export * from "./App";'
    },
    index$tsx: `import React from 'react';
import ReactDOM from 'react-dom';
import { App } from './components';

ReactDOM.render(<App />, document.getElementById('root'));`
  },
  public: {
    'index.html': `<!DOCTYPE html>
<html>
  <head>
    <title>{{projectName}}</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>`
  },
  package$json: JSON.stringify({
    name: "{{projectName}}",
    version: "{{version}}",
    dependencies: {
      "react": "^18.2.0",
      "react-dom": "^18.2.0"
    }
  }, null, 2)
};

๐Ÿ“Š Project Structure

forji/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ index.ts         # Main entry point
โ”‚   โ”œโ”€โ”€ ProjectBuilder.ts # Core builder class
โ”‚   โ”œโ”€โ”€ types.ts         # Type definitions
โ”‚   โ””โ”€โ”€ utils.ts         # Utility functions
โ”œโ”€โ”€ package.json
โ””โ”€โ”€ README.md

๐Ÿค Contributing

Contributions, issues and feature requests are welcome!

  1. ๐Ÿด Fork the project
  2. ๐Ÿ”จ Make your changes
  3. ๐Ÿ”„ Create a pull request

๐Ÿ“œ License

MIT ยฉ ๐Ÿ—๏ธ Hicham Jebara.


1.0.5

4 months ago

1.0.4

4 months ago

1.0.3

4 months ago

1.0.2

4 months ago

1.0.1

4 months ago

1.0.0

4 months ago