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 🙏

© 2024 – Pkg Stats / Ryan Hefner

moldable

v0.0.9

Published

Moldable is a fast code generator with markdown templates

Downloads

569

Readme

CI

moldable

A CLI tool for code generation under the influence of plop and scaffdog. It has the best of each tool, yet it is faster and more flexible. See the benchmarks for more information.

Installation

npm install -g moldable

Quick Start

Create a .moldable folder in the root directory of your application, and create Markdown file within it shown below. Name the file quick-start.md.

---
name: "quick-start"
description: "Quick Start"
prompts:
  - type: "base"
    name: "name"
    message: "Type your name"
    validate: "{{if eq (len .input) 0}}Name must have more than - characters{{end}}"
  - type: "select"
    name: "favoriteColor"
    message: "Select your favorite color"
    choices:
      - "Red"
      - "Green"
      - "Blue"
actions:
  - type: "add"
    path: "src/quick-start.json"
    template: "quick-start.json"
---

# quick-start.json

```json
{
  "name": "{{.name}}",
  "favoriteColor": "{{.favoriteColor}}"
}
```

Execute moldable in the root directory of your application, and select the quick-start generator.

# Answer the questions
? Select Generator:
  ▸ quick-start - Quick Start

✔  Type your name : John Doe█

?  Select your favorite color :
  ▸ Red
    Green
    Blue

# Results
🖨  Added:
  src/quick-start.json

Answer the questions that appear, and the code will be generated in the quick-start.json file.

{
  "name": "John Doe",
  "favoriteColor": "Red"
}

Advanced Usage

You can describe a generator for generating any code. Create a /.moldable folder in the root directory of your application, and create Markdown files within it.

.
└──  .moldable
    ├── foo.md
    └── bar.md

The name of the Markdown file corresponds to the generator name displayed when you launch moldable. When you run moldable, an interactive question starts according to the selected generator, and when all are answered, code is generated. This generator is divided into metadata (in YAML format) and content (in Markdown format). The structure of the metadata is as follows. You can use the syntax of Go's text/template in some properties.

| Name | Description | Required | Type | Example | | ----------- | ----------------------------------------------------------------------------- | ------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------ | | name | Template name (must match the Markdown file name) | :white_check_mark: | String | "pages" | | description | Template description | :white_check_mark: | String | "Page Generator" | | prompts | Questions to be asked sequentially after selecting a template | :white_check_mark: | Array of mapping | type: "base"name: "name"message: "Type a page name" | | actions | Settings for generating code using the values of the answers to the questions | :white_check_mark: | Array of mapping | type: "add"path: "src/app/{{.name}}/page.tsx"template: "{{.name | pascal}}/page.tsx" |

The structure of each element of the prompts value is as follows.

| Name | Description | Required | Type | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------- | ------------------------------------------------ | | type | Format of the question・base: Text input・select: Single selection・multiselect: Multiple selection・confirm: Y/N binary choice | :white_check_mark: | "base" | "select" | "multiselect" | "confirm" | | name | Variable name to store the result of the question. In places where text/template is valid, it can be referenced with a . start. | :white_check_mark: | String | | message | Content of the question | :white_check_mark: | String | | prefix | Supplement to the question, displayed before the question | | String | | suffix | Supplement to the question, displayed after the question | | String | | when | Place to skip the question. The results of the questions up to the current question can be referenced. | | String(text/template) | | validate | Place to validate the question. The value of the question being entered can be referenced with .input. | | String(text/template) | | defaultValues | Default value of the result of the questionData type・base: String・select: String・multiselect: Array of String・confirm: Boolean | | Any | | choises | Choices for select and multiselect | Required if type is select or multiselect | Array of String |

The structure of each element of the actions value is as follows.

| Name | Description | Required | Type | | -------- | ------------------------------------------------------------------------- | -------------------------- | --------------------- | | type | Type of code generation | :white_check_mark: | "add" | "append" | | path | Destination of the code output | :white_check_mark: | String(text/template) | | template | Template name for code generation (must match the heading in the content) | :white_check_mark: | String(text/template) | | skip | Place to skip code generation | | String(text/template) | | pattern | Destination to add code in append | Required if type is append | String |

In addition, for variables referenced within text/template, you can convert to the following cases using the format .var | case.

| Name | Case | | -------- | ------------- | | camel | camelCase | | snake | snake_case | | kebab | kebab-case | | dash | dash-case | | dot | dot.case | | proper | ProperCase | | pascal | PascalCase | | lower | lower case | | sentence | Sentence case | | constant | CONSTANT_CASE | | title | Title Case |

[!NOTE]

By attaching OnlyAlphanumeric to the end of each case modifier (e.g. pascalOnlyAlphanumeric), if the first character of the string is not alphanumeric, it is excluded and the case is converted. For example, [projectId] is converted to ProjectId with pascalOnlyAlphanumeric.

The content consists of headings and code blocks as follows.

---
actions:
  - type: "add"
    template: "page.tsx"
---

# page.tsx

```tsx
export const Page = (children: { children: React.ReactNode }) => <div>{children}</div>;
```

As mentioned earlier, the template of any element contained in actions needs to match the heading in the content. The syntax of text/template can also be used for headings.

Benchmarks

Environment

  • OS: macOS Monterey 12.6.3
  • CPU: Apple M1 Max
  • Memory: 64GB
  • Node.js: 20.11.1
  • npm: 10.5.1

We measured the time it took to generate a simple React component with each package. The benchmark project is available here.

import React from "react";

export const {{ name }}: React.FC = (children: { children: React.ReactNode }) => <div>{children}</div>;

Result

| Package | Version | Average time of 10 times(ms) | | ------------ | ------- | ---------------------------- | | plop | 6.2.11 | 0.233 | | scaffdog | 3.0.0 | 0.385 | | moldable | 0.0.4 | 0.182 |

Moldable is the fastest. This is because it is written in Go and executed by node after compiling it into a binary.

Third Party License

Parts of the code from the following projects have been borrowed and modified for use.

The list of licenses is available at THIRD_PARTY_LICENSE.

License

MIT License

Developers

Copyright

CyberAgent, Inc. All rights reserved.