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

curriculum-compiler-json

v2.1.1

Published

Compile Enki Curriculum AST to JSON object

Downloads

9

Readme

Enki Curriculum Compiler JSON

Compiles Enki Curriculum AST into a json object.

See Enki curriculum processors for more details.

How it works

The compiler works in the following way:

  1. Iterates over all children of the AST provided
    • looks at the type value of each top-most node
    • if type is "yaml" => fires metadata compiler
    • if type is "headline" => fires headline compiler
    • if type is "section", it looks at the name field of the node
      • if name is "Content" => returns { content: compileString(node) }
      • if name is "Game Content" => returns { gameContent: compileString(node) }
      • if name is "Exercise" => returns { exercise: compileString(node) }
      • if name is "Practice" => fires question compiler with "practice" argument
      • if name is "Revision" => fires question compiler with "revision" argument
      • if name is "Quiz" => fires quiz compiler
      • if name is "Footnotes" => fires footnotes compiler
      • otherwise throws an error
    • otherwise throws an error
  2. combines all JSON properties returned by each sub-compiler into a single object
  3. returns the final JSON object

Compilers

Most of the compilers make use of the string compiler on top of which they do subsequent modifications.

Each of them will return a simple object { key: value }

Headline

compilers.headline(node)

Given an AST node as input:

{
  "type": "headline",
  "children": [
    {
      "type": "text",
      "value": "Sample title",
      ///
      }
    }
  }

It will compile the node, remove the \ns, trim the string and return an object:

{
  "headline": "Sample title"
}

Metadata

compilers.metadata(node)

Given an AST node as input:

{
  "type": "yaml",
  "value": "author: catalin\n\nlevels:\n  - basic\n  - medium\n  -...",
  "data": {
    "parsedData": {
      "author": "catalin",
      ...
    }
  }

It will return the already parsed data in node.data.parsedValue:

{
  "metadata": {
    "author": "catalin",
    ...
  }
}

Question

compilers.question(node, 'key')

This compiler is used for both "Practice" and "Revision" questions. Apart from the ast, this compiler takes another argument key:

question(ast, key) { /* ... */ }

Given a question AST node as input and a key:

{
  "type": "section",
  "name": "Revision" || "Practice",
  "children": [...]
}

It will return:

{
  "key": {
    "rawText": "question with two gaps ??? ???\n* answer1\n*answer2\nanswer3",
    "question": "question with two gaps ??? ???",
    "answers": [
      {
        "text": "answer1",
        "correct": true,
        "correctIndex": 0
      },
      {
        "text": "answer2",
        "correct": true,
        "correctIndex": 1
      },
      {
        "text": "answer3",
        "correct": false,
        "correctIndex": null
      }
    ]
  }
}

Each answer will have its text, a correct flag indicating if it's one of the correct answers of the question and a correctIndex integer which indicates the index of the question gap it should match.

Quiz

compilers.quiz(node)

This compiler is similar to the question compiler. In addition, it returns a headline field specific to quizzes.

Because quiz question don't have question gaps ???, the first answer will be marked as correct (from within the parser).

Given an AST node:

{
  "type": "section",
  "name": "Quiz",
  "children": [ ... ]
}

It returns the following object:

{
  "quiz": {
    "rawText": "### Quiz name\nQuiz text\n* answer1\nanswer2",
    "headline": "Quiz name",
    "question": "Quiz text",
    "answers": [
       {
        "text": "answer1",
        "correct": true,
        "correctIndex": 0
      },
      {
        "text": "answer2",
        "correct": false,
        "correctIndex": null
      }
    ]
  }
}

Footnotes

compilers.footnotes(node)

Given an AST node:

{
  "type": "section",
  "name": "Footnotes",
  "children": [ ... ]
}

It returns the following object:

{
  "footnotes": {
    "rawText": "fullFootnotesText",
    "items": [
      {
        "number": 1,
        "name": "Footnote name",
        "text": "Footnote text"
      },
       {
        "number": 2,
        "name": "Footnote name 2",
        "text": "Footnote text 2"
      }
    ]
  }
}

Schema

The final schema of a compiled JSON looks like:

{
  "metadata": {
    "author": "catalin",
    "levels": [
      "basic",
      "medium",
      "advanced"
    ],
    "type": "normal",
    "category": "must-know",
    "standards": {
      "sql.use-dql.0": 10,
      "sql.use-ddl.1": 1000
    },
    "tags": [
      "introduction",
      "workout"
    ],
    "stub": false,
    "links": [
      {
        "name": "EnkiCool",
        "url": "https://enki.com",
        "nature": "website"
      }
    ]
  },
  "headline": "Sample title with `code` within",
  "content": "This is a sample paragraph.[1]\n\nThis is a sample list[2]:\n\n* item one\n* item `two`\n\nSample code[3]:\n\n```javascript\nconsole.log('sample code')\n```\n",
  "gameContent": "Sample game content\n",
  "exercise": "Sample exercise\n",
  "practice": {
    "rawText": "This is a sample question with one gap:\n\n???\n\n* correct\n* incorrect\n* not a chance\n",
    "question": "This is a sample question with one gap:\n\n???\n",
    "answers": [
      {
        "text": "correct",
        "correct": true,
        "correctIndex": 0
      },
      {
        "text": "incorrect",
        "correct": true,
        "correctIndex": 1
      },
      {
        "text": "not a chance",
        "correct": true,
        "correctIndex": 2
      }
    ]
  },
  "revision": {
    "rawText": "This is a sample question with two gaps:\n\n???\n\n???\n\n* correct\n* also correct\n* nah bro\n* fam, just no\n",
    "question": "This is a sample question with two gaps:\n\n???\n\n???\n",
    "answers": [
      {
        "text": "correct",
        "correct": true,
        "correctIndex": 0
      },
      {
        "text": "also correct",
        "correct": false,
        "correctIndex": null
      },
      {
        "text": "nah bro",
        "correct": false,
        "correctIndex": null
      },
      {
        "text": "fam, just no",
        "correct": false,
        "correctIndex": null
      }
    ]
  },
  "quiz": {
    "rawText": "### Quiz title\n\n\nSample quiz question\n\n* correct\n* *incorrect*\n* not a `chance`\n* nope\n",
    "headline": "Quiz title",
    "question": "Sample quiz question\n",
    "answers": [
      {
        "text": "correct",
        "correct": true,
        "correctIndex": 0
      },
      {
        "text": "*incorrect*",
        "correct": false,
        "correctIndex": null
      },
      {
        "text": "not a `chance`",
        "correct": false,
        "correctIndex": null
      },
      {
        "text": "nope",
        "correct": false,
        "correctIndex": null
      }
    ]
  },
  "footnotes": {
    "rawText": "[1: Paragraph]\nSample explanation\n\n[2: List]\nSample list\n\n[3: Code]\nSample code\n\n```javascript\nvar x = 10\n```\n",
    "items": [
      {
        "number": "1",
        "name": " Paragraph",
        "text": "\nSample explanation\n\n"
      },
      {
        "number": "2",
        "name": " List",
        "text": "\nSample list\n\n"
      },
      {
        "number": "3",
        "name": " Code",
        "text": "\nSample code\n\n```javascript\nvar x = 10\n```\n"
      }
    ]
  }
}

API

Use the package like:

const {
  contentTypes
} = require('@enkidevs/curriculum-helpers')
const {
  getCompiler
} = require('@enkidevs/curriculum-compiler-json')

const json = getCompiler(contentTypes.INSIGHT).compileSync(ast)