npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

forji

v1.0.5

Published

Library for building project structures with dynamic folder/file names

Downloads

130

Readme

🏗️ 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].