FoalTS / foal

Full-featured Node.js framework, with no complexity. 🚀 Simple and easy to use, TypeScript-based and well-documented.
https://foalts.org/
MIT License
1.88k stars 138 forks source link

How do I create more advanced foal scripts? #1103

Closed haneefkassam closed 1 year ago

haneefkassam commented 1 year ago

The documentation currently leaves a bit to be desired. It highlights the simple use-case/happy path, but if you want to do anything somewhat complex, good luck finding it in the documentation. A few examples:

The documentation doesn't describe any of this or point me in a direction where I can find this information (the happy-path example doesn't help at all. There is a mention of passing in array values as a command line parameter, but there's no indication of how you would code this in the schema, for example)

scho-to commented 1 year ago

Hi @haneefkassam,

On the page https://foalts.org/docs/common/validation-and-sanitization#ajv-the-json-schema-validator, it is stated, that FoalTS uses AJV and for further information on AJV, you should concider their docs, as there are a lot of examples already.

You can specify certain string values by adding a "pattern" keys to the properties: (From the AJV Docs)

export const schema = {
  additionalProperties: false,
  properties: {
    action: { type: "string", pattern: "REGEX HERE" },
    text: { type: "string" },
  },
  required: ["action"],
  type: "object",
};

There you can specify rules using regex.

Here is a simple example, derived from the "create-todo"-Script from this Tutorial in the FoalTS docs:

// 3p
import { createConnection } from "typeorm";

//Application
import { Todo } from "../app/entities/todo.entity";

export const schema = {
  additionalProperties: false,
  properties: {
    action: { type: "string", pattern: "list|create" },
    text: { type: "string" },
  },
  required: ["action"],
  type: "object",
};

export async function main(args: { action: string; text?: string }) {
  const connection = await createConnection();

  try {
    const { action, text } = args;
    switch (action) {
      case "create":
        await createTodo(text);
        break;
      case "list":
        await listTodos();
        break;
      default:
        throw new Error("action not supported yet");
    }
  } catch (error) {
    console.error(error);
  } finally {
    await connection.close();
  }
}

async function createTodo(text: string | undefined) {
  if (!text) {
    throw new Error("No text provided!");
  }

  // Create a new task with the text given in the command line.
  const todo = new Todo();
  todo.text = text;

  // Save the task in the database and then display it in the console.
  console.log(await todo.save());
}

async function listTodos() {
  const todos = await Todo.find();
  console.log(todos);
}

For your second and third question:

LoicPoullain commented 1 year ago

The documentation currently leaves a bit to be desired. It highlights the simple use-case/happy path, but if you want to do anything somewhat complex, good luck finding it in the documentation.

Foal is an open-source project and it’s maintained only by volunteers. The development of the framework represents hundreds of days of work and is available for free without any compensation. Using kind language is surely the best way to get help and improve the product.

  • What options do I have to specify certain allowed values in the JSON schema when creating a cli? I want a parameter to only have certain values (ie. foal run my-script action=<some-string>. I want <some-string> to only accept the values "list" and "create"). The documentation doesn't make this clear at all how this is even possible, nor does it link to the library foal is using to help users find the information (I know foal is using commander and ajv, but both have multiple ways to accomplish this, and it's unclear how foal abstracts those libraries)

There is an option pattern that can be used with a regex in the JSON schema: https://ajv.js.org/json-schema.html#pattern

  • How do I create positional arguments?

This is currently not possible. If you wish to positional arguments, one way is to not use foal run and create your own script system with commander or something else.

  • How do I prompt the user for input?

The library prompt might be useful in this case.

haneefkassam commented 1 year ago

@LoicPoullain Yes, you are right, this is my mistake. Foal is a fantastic framework that pulls together a bunch of very useful libraries and tools. I do apologize for the tone of my initial msg, it was uncalled for. I guess I was looking for something very descriptive (like all of the properties of the request or session object in ctx argument of controller methods). The documentation is of a different style, so it's just taking some getting used to.