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

@beppobert/ts-template

v0.0.1

Published

This is a small customizable typesafe template engine written in Typescript.

Downloads

5

Readme

template-ts

This is a small customizable typesafe template engine written in Typescript.

Setup

Quickstart

npm i @beppobert/ts-template
import {
  TypeDefinition,
  ArgDefinition,
  OperationDefinition,
  Pattern,
  createSchema,
  template,
} from "@beppobert/ts-template";

// create your custom types

const stringType = new TypeDefinition("string", {
  validator: (input: string) => typeof input === "string",
  parseValue: (value): string => value,
  pattern: new Pattern<`"${string}"`, '""'>(/^\"(.*)\"$/),
});
const numberType = new TypeDefinition("number", {
  validator: (input: number) => typeof input === "number",
  parseValue: (value): number => Number(value),
  pattern: new Pattern<`${number}`, "0">(new RegExp(`^${Number}$`)),
});

// create your custom operations

const uppercaseOperation = new OperationDefinition("upper", {
  args: [],
  input: stringType,
  return: stringType,
  operation: (input) => input.toUpperCase(),
});

const replaceOperation = new OperationDefinition("replace", {
  args: [
    new ArgDefinition("searchValue", stringType),
    new ArgDefinition("replaceValue", stringType),
  ],
  input: stringType,
  return: stringType,
  operation: (input, { searchValue, replaceValue }) =>
    input.replace(searchValue, replaceValue),
});

const toString = new OperationDefinition("toString", {
  args: [],
  input: numberType,
  return: stringType,
  operation: (input) => input.toString(),
});

// create your  schema

const schema = createSchema(
  {
    types: [stringType, numberType],
    defaultType: "string",
  },
  {
    // group the operation based on their input type into an object
    string: [uppercaseOperation, replaceOperation],
    number: [toString],
  }
);

// create your template function

const templateFn = template(schema);

const templateString = templateFn("Hello {{name|upper}}"); // enjoy auto completion

Create a custom type

import { TypeDefinition, Pattern } from "@beppobert/ts-template";
/***
 * The Pattern class defines a pattern that your string in your arguments has to match
 * The first generic will define the typescript side of your pattern.
 * Any arg of type string will be checked against this type.
 * e.g. {{...|...|replace("a","b")}} <- "a" and "b" have to match the pattern
 *
 * The second generic will define a default value if the pattern doesn't match.
 *
 * The pattern regex will be used to validate your arg string.
 * It's last match should also return the value you want to parse.
 *
 * /
const strPattern = new Pattern<`"${string}"`, '""'>(/^\"(.*)\"$/);

const stringType = new TypeDefinition("string", {
  pattern: strPattern,
  // is called after the parsing step
  validator: (input: string) => typeof input === "string",

  // receives the last match of the pattern regex and must return a value of the desired type
  parseValue: (value): string => value,
});

Create a custom operation

import { OperationDefinition, ArgDefinition } from "@beppobert/ts-template";
/**
 * The first argument is the key of your operation.
 * It will be used in your template string to call your operation.
 */
const replace = new OperationDefinition("replace", {
  // define the arguments of your operation
  args: [
    new ArgDefinition("searchValue", stringType),
    new ArgDefinition("replaceValue", stringType),
  ],
  // define the input type of your operation
  input: stringType,
  // define the return type of your operation
  return: stringType,
  // define the operation
  operation: (input, { searchValue, replaceValue }) =>
    input.replace(searchValue, replaceValue),
});

Create a custom schema

The schema runs multiple runtime checks to ensure that your schema is valid.

import { createSchema } from "@beppobert/ts-template";

const schema = createSchema(
  {
    // define your types
    types: [stringType, numberType],
    // define your default type
    defaultType: "string",
  },
  {
    // group the operation based on their input type into an object
    string: [uppercaseOperation, replaceOperation],
    number: [toString],
  }
);

Create a custom template function

import { template } from "@beppobert/ts-template";

const templateFn = template(schema);
/**
 * A value you want to get replaced needs to be wrapped in {{...}}
 *
 * The first part of the string is the name of the value you want to replace.
 * If the value is optional you can add a ? before the name.
 * e.g. {{?name}} will be replaced with the value of name if it exists
 *
 * The second part of the string is the type of the value.
 * The type is prefixed with #. If it's not prefixed the default type will be used.
 * e.g. {{name#string}} is the same as {{name}} if string is the default type
 *
 * the third part of the string is the operations you want to call on the value.
 * e.g. {{name#string|upper|replace("a","b")}}. The typesytem ensures that after each operation you can only * call operations that are defined for the return type of the previous operation.
 * e.g.{{name#string|upper|toString}} will result in an error
 */
const templateString = templateFn(
  'Hello {{name#string|upper|replace("O","i")}}'
); // enjoy auto completion
templateString({ name: "Bob" }); // Hello BiB

const templateString2 = templateFn("Hello {{name|upper}}");