Finish adding JS API docs.

This commit is contained in:
Joshua Bemenderfer 2023-02-21 16:00:53 -05:00
parent 87eb5b7fbd
commit fb90f825ed
8 changed files with 379 additions and 170 deletions

View File

@ -7,7 +7,8 @@ set languageMeta = {
'c': { name: 'C', icon: '<svg viewBox="0 0 128 128"><path fill="#659AD3" d="M115.4 30.7L67.1 2.9c-.8-.5-1.9-.7-3.1-.7-1.2 0-2.3.3-3.1.7l-48 27.9c-1.7 1-2.9 3.5-2.9 5.4v55.7c0 1.1.2 2.4 1 3.5l106.8-62c-.6-1.2-1.5-2.1-2.4-2.7z"></path><path fill="#03599C" d="M10.7 95.3c.5.8 1.2 1.5 1.9 1.9l48.2 27.9c.8.5 1.9.7 3.1.7 1.2 0 2.3-.3 3.1-.7l48-27.9c1.7-1 2.9-3.5 2.9-5.4V36.1c0-.9-.1-1.9-.6-2.8l-106.6 62z"></path><path fill="#fff" d="M85.3 76.1C81.1 83.5 73.1 88.5 64 88.5c-13.5 0-24.5-11-24.5-24.5s11-24.5 24.5-24.5c9.1 0 17.1 5 21.3 12.5l13-7.5c-6.8-11.9-19.6-20-34.3-20-21.8 0-39.5 17.7-39.5 39.5s17.7 39.5 39.5 39.5c14.6 0 27.4-8 34.2-19.8l-12.9-7.6z"></path></svg>' },
'javascript': { name: 'JavaScript', icon: '<svg viewBox="0 0 128 128"><path fill="#F0DB4F" d="M1.408 1.408h125.184v125.185H1.408z"></path><path fill="#323330" d="M116.347 96.736c-.917-5.711-4.641-10.508-15.672-14.981-3.832-1.761-8.104-3.022-9.377-5.926-.452-1.69-.512-2.642-.226-3.665.821-3.32 4.784-4.355 7.925-3.403 2.023.678 3.938 2.237 5.093 4.724 5.402-3.498 5.391-3.475 9.163-5.879-1.381-2.141-2.118-3.129-3.022-4.045-3.249-3.629-7.676-5.498-14.756-5.355l-3.688.477c-3.534.893-6.902 2.748-8.877 5.235-5.926 6.724-4.236 18.492 2.975 23.335 7.104 5.332 17.54 6.545 18.873 11.531 1.297 6.104-4.486 8.08-10.234 7.378-4.236-.881-6.592-3.034-9.139-6.949-4.688 2.713-4.688 2.713-9.508 5.485 1.143 2.499 2.344 3.63 4.26 5.795 9.068 9.198 31.76 8.746 35.83-5.176.165-.478 1.261-3.666.38-8.581zM69.462 58.943H57.753l-.048 30.272c0 6.438.333 12.34-.714 14.149-1.713 3.558-6.152 3.117-8.175 2.427-2.059-1.012-3.106-2.451-4.319-4.485-.333-.584-.583-1.036-.667-1.071l-9.52 5.83c1.583 3.249 3.915 6.069 6.902 7.901 4.462 2.678 10.459 3.499 16.731 2.059 4.082-1.189 7.604-3.652 9.448-7.401 2.666-4.915 2.094-10.864 2.07-17.444.06-10.735.001-21.468.001-32.237z"></path></svg>' },
'typescript': { name: 'TypeScript', icon: '<svg viewBox="0 0 128 128"><path fill="#fff" d="M22.67 47h99.67v73.67H22.67z"></path><path data-name="original" fill="#007acc" d="M1.5 63.91v62.5h125v-125H1.5zm100.73-5a15.56 15.56 0 017.82 4.5 20.58 20.58 0 013 4c0 .16-5.4 3.81-8.69 5.85-.12.08-.6-.44-1.13-1.23a7.09 7.09 0 00-5.87-3.53c-3.79-.26-6.23 1.73-6.21 5a4.58 4.58 0 00.54 2.34c.83 1.73 2.38 2.76 7.24 4.86 8.95 3.85 12.78 6.39 15.16 10 2.66 4 3.25 10.46 1.45 15.24-2 5.2-6.9 8.73-13.83 9.9a38.32 38.32 0 01-9.52-.1 23 23 0 01-12.72-6.63c-1.15-1.27-3.39-4.58-3.25-4.82a9.34 9.34 0 011.15-.73L82 101l3.59-2.08.75 1.11a16.78 16.78 0 004.74 4.54c4 2.1 9.46 1.81 12.16-.62a5.43 5.43 0 00.69-6.92c-1-1.39-3-2.56-8.59-5-6.45-2.78-9.23-4.5-11.77-7.24a16.48 16.48 0 01-3.43-6.25 25 25 0 01-.22-8c1.33-6.23 6-10.58 12.82-11.87a31.66 31.66 0 019.49.26zm-29.34 5.24v5.12H56.66v46.23H45.15V69.26H28.88v-5a49.19 49.19 0 01.12-5.17C29.08 59 39 59 51 59h21.83z"></path></svg>' },
'python': { name: 'Python', icon: '<svg viewBox="0 0 128 128"><linearGradient id="python-original-a" gradientUnits="userSpaceOnUse" x1="70.252" y1="1237.476" x2="170.659" y2="1151.089" gradientTransform="matrix(.563 0 0 -.568 -29.215 707.817)"><stop offset="0" stop-color="#5A9FD4"></stop><stop offset="1" stop-color="#306998"></stop></linearGradient><linearGradient id="python-original-b" gradientUnits="userSpaceOnUse" x1="209.474" y1="1098.811" x2="173.62" y2="1149.537" gradientTransform="matrix(.563 0 0 -.568 -29.215 707.817)"><stop offset="0" stop-color="#FFD43B"></stop><stop offset="1" stop-color="#FFE873"></stop></linearGradient><path fill="url(#python-original-a)" d="M63.391 1.988c-4.222.02-8.252.379-11.8 1.007-10.45 1.846-12.346 5.71-12.346 12.837v9.411h24.693v3.137H29.977c-7.176 0-13.46 4.313-15.426 12.521-2.268 9.405-2.368 15.275 0 25.096 1.755 7.311 5.947 12.519 13.124 12.519h8.491V67.234c0-8.151 7.051-15.34 15.426-15.34h24.665c6.866 0 12.346-5.654 12.346-12.548V15.833c0-6.693-5.646-11.72-12.346-12.837-4.244-.706-8.645-1.027-12.866-1.008zM50.037 9.557c2.55 0 4.634 2.117 4.634 4.721 0 2.593-2.083 4.69-4.634 4.69-2.56 0-4.633-2.097-4.633-4.69-.001-2.604 2.073-4.721 4.633-4.721z" transform="translate(0 10.26)"></path><path fill="url(#python-original-b)" d="M91.682 28.38v10.966c0 8.5-7.208 15.655-15.426 15.655H51.591c-6.756 0-12.346 5.783-12.346 12.549v23.515c0 6.691 5.818 10.628 12.346 12.547 7.816 2.297 15.312 2.713 24.665 0 6.216-1.801 12.346-5.423 12.346-12.547v-9.412H63.938v-3.138h37.012c7.176 0 9.852-5.005 12.348-12.519 2.578-7.735 2.467-15.174 0-25.096-1.774-7.145-5.161-12.521-12.348-12.521h-9.268zM77.809 87.927c2.561 0 4.634 2.097 4.634 4.692 0 2.602-2.074 4.719-4.634 4.719-2.55 0-4.633-2.117-4.633-4.719 0-2.595 2.083-4.692 4.633-4.692z" transform="translate(0 10.26)"></path><radialGradient id="python-original-c" cx="1825.678" cy="444.45" r="26.743" gradientTransform="matrix(0 -.24 -1.055 0 532.979 557.576)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#B8B8B8" stop-opacity=".498"></stop><stop offset="1" stop-color="#7F7F7F" stop-opacity="0"></stop></radialGradient><path opacity=".444" fill="url(#python-original-c)" d="M97.309 119.597c0 3.543-14.816 6.416-33.091 6.416-18.276 0-33.092-2.873-33.092-6.416 0-3.544 14.815-6.417 33.092-6.417 18.275 0 33.091 2.872 33.091 6.417z"></path></svg>' }
'python': { name: 'Python', icon: '<svg viewBox="0 0 128 128"><linearGradient id="python-original-a" gradientUnits="userSpaceOnUse" x1="70.252" y1="1237.476" x2="170.659" y2="1151.089" gradientTransform="matrix(.563 0 0 -.568 -29.215 707.817)"><stop offset="0" stop-color="#5A9FD4"></stop><stop offset="1" stop-color="#306998"></stop></linearGradient><linearGradient id="python-original-b" gradientUnits="userSpaceOnUse" x1="209.474" y1="1098.811" x2="173.62" y2="1149.537" gradientTransform="matrix(.563 0 0 -.568 -29.215 707.817)"><stop offset="0" stop-color="#FFD43B"></stop><stop offset="1" stop-color="#FFE873"></stop></linearGradient><path fill="url(#python-original-a)" d="M63.391 1.988c-4.222.02-8.252.379-11.8 1.007-10.45 1.846-12.346 5.71-12.346 12.837v9.411h24.693v3.137H29.977c-7.176 0-13.46 4.313-15.426 12.521-2.268 9.405-2.368 15.275 0 25.096 1.755 7.311 5.947 12.519 13.124 12.519h8.491V67.234c0-8.151 7.051-15.34 15.426-15.34h24.665c6.866 0 12.346-5.654 12.346-12.548V15.833c0-6.693-5.646-11.72-12.346-12.837-4.244-.706-8.645-1.027-12.866-1.008zM50.037 9.557c2.55 0 4.634 2.117 4.634 4.721 0 2.593-2.083 4.69-4.634 4.69-2.56 0-4.633-2.097-4.633-4.69-.001-2.604 2.073-4.721 4.633-4.721z" transform="translate(0 10.26)"></path><path fill="url(#python-original-b)" d="M91.682 28.38v10.966c0 8.5-7.208 15.655-15.426 15.655H51.591c-6.756 0-12.346 5.783-12.346 12.549v23.515c0 6.691 5.818 10.628 12.346 12.547 7.816 2.297 15.312 2.713 24.665 0 6.216-1.801 12.346-5.423 12.346-12.547v-9.412H63.938v-3.138h37.012c7.176 0 9.852-5.005 12.348-12.519 2.578-7.735 2.467-15.174 0-25.096-1.774-7.145-5.161-12.521-12.348-12.521h-9.268zM77.809 87.927c2.561 0 4.634 2.097 4.634 4.692 0 2.602-2.074 4.719-4.634 4.719-2.55 0-4.633-2.117-4.633-4.719 0-2.595 2.083-4.692 4.633-4.692z" transform="translate(0 10.26)"></path><radialGradient id="python-original-c" cx="1825.678" cy="444.45" r="26.743" gradientTransform="matrix(0 -.24 -1.055 0 532.979 557.576)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#B8B8B8" stop-opacity=".498"></stop><stop offset="1" stop-color="#7F7F7F" stop-opacity="0"></stop></radialGradient><path opacity=".444" fill="url(#python-original-c)" d="M97.309 119.597c0 3.543-14.816 6.416-33.091 6.416-18.276 0-33.092-2.873-33.092-6.416 0-3.544 14.815-6.417 33.092-6.417 18.275 0 33.091 2.872 33.091 6.417z"></path></svg>' },
'sh': { name: 'shell' }
}
%}
@ -26,7 +27,9 @@ set languageMeta = {
h-12 {{ node.summaryClass }}
"
>
{% if languageMeta[example.language].icon %}
<div class="w-[16px] h-[16px] hidden md:block">{{ languageMeta[example.language].icon | safe }}</div>
{% endif %}
{{ example.name or languageMeta[example.language].name }}
</summary>
<pre

View File

@ -11,8 +11,6 @@ Section light
TableOfContents
Block
class max-w-prose
Heading 1 Terrace C Documentation
class -ml-2
@ -29,6 +27,8 @@ Section light
To use it, download and include the following files in your project tree:
- [parser.h](https://git.thederf.com/thederf/Terrace/src/branch/main/packages/c/parser.h) - Core terrace parser
- [document.h](https://git.thederf.com/thederf/Terrace/src/branch/main/packages/c/document.h) - (optional) Convenience functions for parsing of documents
A simple example program using to read each line from stdin and output parser information, looking for a "title" key:
CodeBlock c
// Provides getline() for reading from stdin
#include <stdio.h>
@ -79,6 +79,30 @@ Section light
Markdown
Heading 2 Core API
class mt-12
Heading 3 terrace_linedata_t
class my-6
CodeBlock c
// Holds the parsed information from each line.
typedef struct terrace_linedata_s {
// Which character is being used for indentation. Avoids having to specify it on each terrace_parse_line call.
char indent;
// How many indent characters are present in the current line before the first non-indent character.
unsigned int level;
// The number of characters before the start of the line's "head" section.
// (Normally the same as `level`)
unsigned int offsetHead;
// The number of characters before the start of the line's "tail" section.
unsigned int offsetTail;
} terrace_linedata_t;
Heading 3 terrace_parse_line()
class my-6
CodeBlock c
void terrace_parse_line(char* line, terrace_linedata_t *lineData)
Heading 2 Recipes
class mt-12
@ -156,38 +180,6 @@ Section light
free(line);
}
Heading 2 Core API
class mt-12
Markdown
In most cases, you'll use the [Document API](#document-api) instead.
The Core API provides low-level parsing for individual lines.
Heading 3 terrace_linedata_t
class my-6
CodeBlock c
// Holds the parsed information from each line.
typedef struct terrace_linedata_s {
// Which character is being used for indentation. Avoids having to specify it on each terrace_parse_line call.
char indent;
// How many indent characters are present in the current line before the first non-indent character.
unsigned int level;
// The number of characters before the start of the line's "head" section.
// (Normally the same as `level`)
unsigned int offsetHead;
// The number of characters before the start of the line's "tail" section.
unsigned int offsetTail;
} terrace_linedata_t;
Heading 3 terrace_create_line_data()
class my-6
Heading 3 terrace_parse_line()
class my-6
CodeBlock c
void terrace_parse_line(char* line, terrace_linedata_t *lineData)
Heading 2 Contributing
class mt-12

View File

@ -11,15 +11,13 @@ Section light
TableOfContents
Block
class max-w-prose
Heading 1 Terrace JavaScript Documentation
class -ml-2
Markdown
Documentation is available for the following languages:
- [C](/docs/c/) - 10% Complete
- [JavaScript](/docs/javascript/) - 50% Complete
- [JavaScript](/docs/javascript/) - 75% Complete
- [Python](/docs/python/) - 0% Complete
Heading 2 Getting Started
@ -37,132 +35,86 @@ Section light
# Yarn (https://yarnpkg.com/)
$ yarn add @terrace-lang/js
Heading 2 Recipes
class mt-12
Heading 3 Read object properties
class mb-2
Markdown
Read known properties from a Terrace block and write them to an object.
CodeBlock javascript
// Provides simple convenience functions over the core parser
// CommonJS: const { useDocument } = require('@terrace-lang/js/document')
import { useDocument } from '@terrace-lang/js/document'
// A helper for iterating over a string line-by-line
// CommonJS: const { createStringReader } = require('@terrace-lang/js/readers/js-string')
import { createStringReader } from '@terrace-lang/js/readers/js-string'
const input = `
object
string_property An example string
numeric_property An example property
`
const output = {
string_property: null,
numeric_property: null
}
// useDocument returns convenience functions
const { next, level, head, tail, match } = useDocument(createStringReader(input))
// next() parses the next line in the document
while (await next()) {
// match('object') is equivalent to head() === 'object'
// Essentially: "If the current line starts with 'object'"
if (match('object')) {
const objectLevel = level()
// When we call next with a parent level it,
// only iterates over lines inside the parent block
while (await next(objectLevel)) {
// tail() returns the part of the current line after the first space
if (match('string_property')) output.string_property = tail()
// parseFloat() here the string tail() to a numeric float value
if (match('numeric_property')) output.numeric_property = parseFloat(tail())
}
}
}
console.dir(output)
Markdown
Read *all* properties as strings from a Terrace block and write them to an object.
CodeBlock javascript
// Provides simple convenience functions over the core parser
// CommonJS: const { useDocument } = require('@terrace-lang/js/document')
import { useDocument } from '@terrace-lang/js/document'
// A helper for iterating over a string line-by-line
// CommonJS: const { createStringReader } = require('@terrace-lang/js/readers/js-string')
import { createStringReader } from '@terrace-lang/js/readers/js-string'
const input = `
object
property1 Value 1
property2 Value 2
random_property igazi3ii4quaC5OdoB5quohnah1beeNg
`
const output = {}
// useDocument returns convenience functions
const { next, level, head, tail, match } = useDocument(createStringReader(input))
// next() parses the next line in the document
while (await next()) {
// match('object') is equivalent to head() === 'object'
// Essentially: "If the current line starts with 'object'"
if (match('object')) {
const objectLevel = level()
// When we call next with a parent level it,
// only iterates over lines inside the parent block
while (await next(objectLevel)) {
// Skip empty lines
if (!line()) continue
// Add any properties to the object as strings using the
// line head() as the key and tail() as the value
output[head()] = tail()
}
}
}
console.dir(output)
Heading 2 Core API
class mt-12
Markdown
**TODO:** Document
**Note:** The Core API uses C-style conventions to optimize memory management
and improve portability to other environments and languages.
It is unwieldy and does not follow JavaScript best practices.
For most projects you'll want to use the [Document API](#document-api) instead.
It provides an ergonomic wrapper around the Core API and lets you focus on parsing
your documents.
Heading 3 LineData
class my-6
class mb-4 mt-12
CodeBlock typescript
// Type Definition
// Holds the parsed information from each line.
type LineData = {
line: string;
// Which character is being used for indentation. Avoids having to specify it on each parseLine call.
indent: string;
// How many indent characters are present in the current line before the first non-indent character.
level: number;
// The number of characters before the start of the line's "head" section.
// (Normally the same as `level`)
offsetHead: number;
// The number of characters before the start of the line's "tail" section.
offsetTail: number;
}
Heading 3 createLineData()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| indent | string | The character used for indentation in the document. Only a single character is permitted.
| **@returns** | [LineData](#line-data) | A LineData instance with the specified indent character and all other values initialized to 0.
Initialize a LineData instance with default values to pass to [parseLine()](#parse-line).
CodeBlock typescript
function createLineData(line: string = '', indent: string = ' '): LineData
CodeBlock javascript
// Type Definition
function createLineData(indent: string = ' '): LineData
// Import Path
import { createLineData } from '@terrace-lang/js/parser'
// Usage
const lineData = createLineData(' ')
console.dir(lineData)
// { indent: ' ', level: 0, offsetHead: 0, offsetTail: 0 }
// Use the same lineData object for all calls to parseLine in the same document.
Heading 3 parseLine()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| line | string | A string containing a line to parse. Shouldn't end with a newline.
| lineData | [LineData](#line-data) | A LineData object to store information about the current line, from [createLineData()](#create-line-data).<br/>**Mutated in-place!**
Core Terrace parser function, sets `level`, `offsetHead`, and `offsetTail` in a [LineData](#line-data) object based on the passed line.
Note that this is a C-style function, `lineData` is treated as a reference and mutated in-place.
CodeBlock typescript
// Type Definition
function parseLine(lineData: LineData): LineData
CodeBlock javascript
import { parseLine } from '@terrace-lang/js/parser'
// Import Path
import { createLineData, parseLine } from '@terrace-lang/js/parser'
// Usage
const lineData = createLineData(' ')
parseLine('title Example Title', lineData)
console.dir(lineData)
// { indent: ' ', level: 0, offsetHead: 0, offsetTail: 5 }
Heading 2 Document API
class mt-12
Heading 3 useDocument()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
@ -179,7 +131,7 @@ Section light
import { useDocument } from '@terrace-lang/js/document'
Heading 3 Document
class my-6
class mb-4 mt-12
Markdown
Container for a handful of convenience functions for parsing documents.
Obtained from [useDocument()](#usedocument) above
@ -195,7 +147,7 @@ Section light
}
Heading 3 Document.next()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
@ -230,7 +182,7 @@ Section light
}
Heading 3 Document.level()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
@ -254,7 +206,7 @@ Section light
const { level } = useDocument(...)
Heading 3 Document.line()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
@ -282,7 +234,7 @@ Section light
const { line } = useDocument(...)
Heading 3 Document.head()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
@ -305,7 +257,7 @@ Section light
const { head } = useDocument(...)
Heading 3 Document.tail()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
@ -327,7 +279,7 @@ Section light
const { tail } = useDocument(...)
Heading 3 Document.match()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
@ -355,25 +307,69 @@ Section light
Heading 2 Reader API
class mt-12
Markdown
**TODO:** Document
The [Document API](#document-api) requires `Reader` functions to iterate through lines
in a document. A reader function simply returns a string (or a promise resolving to a string).
Each time it is called, it returns the next line from whichever source it is pulling them.
Terrace provides a few built-in readers, but you are welcome to build your own instead.
Heading 3 Reader
class my-6
class mb-4 mt-12
Markdown
Any function (async included) that returns the next line in a document when called and null when the end of the document has been reached.
CodeBlock typescript
// Type Definition
type Reader = () => string|null|Promise<string|null>
Heading 3 createStringReader()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| source | string\|string[] | The lines to iterate over, as a multiline string or an array of line strings.
| index | number | Optional - which line to start from.
| **@returns** | [Reader](#reader) | A reader function that returns each line from the source document when called sequentially.
Get a simple [Reader](#reader) function that always returns the next line from a mutliline string or an array of line strings.
CodeBlock typescript
// Type Definition
function createStringReader(path: string): Reader
function createStringReader(source: string|string[], index: number = 0): Reader
// Import Path
import { createStringReader } from '@terrace-lang/js/readers/js-string'
Markdown
**Usage**
CodeBlock typescript
import { createStringReader, useDocument } from '@terrace-lang/js'
// Create a string reader with two lines
const reader = createStringReader('title Example Title\n line2')
// Also permitted:
// const reader = createStringReader(['title Example Title', ' line 2'])
const { next, level, line } = useDocument(reader)
await next()
console.log(level(), line())
// 0 title Example Title
await next()
console.log(level(), line())
// 1 line 2
Heading 3 createFileReader()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| path | string | A path to the file to read.
| **@returns** | [Reader](#reader) | A reader function that returns each line from the file when called sequentially
**Note:** Only available in Node.js environments.<br/>
Get a [Reader](#reader) function that returns the next line from the specified file when called sequentially.
CodeBlock typescript
// Type Definition
function createFileReader(path: string): Reader
@ -381,14 +377,199 @@ Section light
// Import Path
import { createFileReader } from '@terrace-lang/js/readers/node-readline'
Markdown
**Usage**
CodeExample
summary-class mb-[300px]
pre-class max-h-[300px]
javascript main.js
import { createFileReader, useDocument } from '@terrace-lang/js'
// Read the file ./example.tce
const { next, level, line } = useDocument(createFileReader('./example.tce'))
await next()
console.log(level(), line())
// 0 title Example Title
await next()
console.log(level(), line())
// 1 line 2
terrace example.tce
title Example Title
line 2
Heading 3 createStdinReader()
class my-6
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| **@returns** | [Reader](#reader) | A reader function that returns each line from `stdin` when called sequentially
**Note:** Only available in Node.js environments.<br/>
Get a [Reader](#reader) function that returns the next line from standard input when called sequentially. Does not block stdin to wait for input. If no input is present it returns null immediately.
CodeBlock typescript
// Type Definition
function createStdinReader(): Reader
// Import Path
import { createStdinReader } from '@terrace-lang/js/readers/node-readline'
Markdown
**Usage**
CodeExample
summary-class mb-[250px]
pre-class max-h-[250px]
javascript main.js
import { createStdinReader, useDocument } from '@terrace-lang/js'
// Read the contents of standard input
const { next, level, line } = useDocument(createStdinReader())
while(await next()) {
console.log(level(), line())
// See `shell` panel above for output
}
terrace example.tce
title Example Title
line 2
sh
# Run main.js with the contents of example.tce piped to stdin
$ cat example.tce > node ./main.js
0 title Example Title
1 line 2
Heading 3 createStreamReader()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| stream | NodeJS.ReadStream|fs.ReadStream | A ReadStream compatible with Node.js `readline` APIs
| **@returns** | [Reader](#reader) | A reader function that returns each line from `stdin` when called sequentially
**Note:** Only available in Node.js environments.<br/>
Get a [Reader](#reader) function that always returns the next line from a passed read stream when called sequentially.
CodeBlock typescript
// Type Definition
function createStreamReader(): Reader
// Import Path
import { createStreamReader } from '@terrace-lang/js/readers/node-readline'
Markdown
**Usage**
CodeExample
summary-class mb-[320px]
pre-class max-h-[320px]
javascript main.js
import fs from 'node:fs'
import { createStreamReader, useDocument } from '@terrace-lang/js'
// Read the file ./example.tce - equivalent to the `createFileReader` example above.
const reader = createStreamReader(fs.createReadStream('./example.tce'))
const { next, level, line } = useDocument(reader)
await next()
console.log(level(), line())
// 0 title Example Title
await next()
console.log(level(), line())
// 1 line 2
terrace example.tce
title Example Title
line 2
Heading 2 Recipes
class mt-12
Heading 3 Read object properties
class mb-2
Markdown
Read known properties from a Terrace block and write them to an object.
CodeBlock javascript
// Provides simple convenience functions over the core parser
// CommonJS: const { useDocument } = require('@terrace-lang/js/document')
import { useDocument } from '@terrace-lang/js/document'
// A helper for iterating over a string line-by-line
// CommonJS: const { createStringReader } = require('@terrace-lang/js/readers/js-string')
import { createStringReader } from '@terrace-lang/js/readers/js-string'
const input = `
object
string_property An example string
numeric_property 4
`
const output = {
string_property: null,
numeric_property: null
}
// useDocument returns convenience functions
const { next, level, head, tail, match } = useDocument(createStringReader(input))
// next() parses the next line in the document
while (await next()) {
// match('object') is equivalent to head() === 'object'
// Essentially: "If the current line starts with 'object'"
if (match('object')) {
const objectLevel = level()
// When we call next with a parent level it,
// only iterates over lines inside the parent block
while (await next(objectLevel)) {
// tail() returns the part of the current line after the first space
if (match('string_property')) output.string_property = tail()
// parseFloat() here the string tail() to a numeric float value
if (match('numeric_property')) output.numeric_property = parseFloat(tail())
}
}
}
console.dir(output)
// { string_property: 'An example string', numeric_property: 4 }
Markdown
Read *all* properties as strings from a Terrace block and write them to an object.
CodeBlock javascript
// Provides simple convenience functions over the core parser
// CommonJS: const { useDocument } = require('@terrace-lang/js/document')
import { useDocument } from '@terrace-lang/js/document'
// A helper for iterating over a string line-by-line
// CommonJS: const { createStringReader } = require('@terrace-lang/js/readers/js-string')
import { createStringReader } from '@terrace-lang/js/readers/js-string'
const input = `
object
property1 Value 1
property2 Value 2
random_property igazi3ii4quaC5OdoB5quohnah1beeNg
`
const output = {}
// useDocument returns convenience functions
const { next, level, head, tail, match } = useDocument(createStringReader(input))
// next() parses the next line in the document
while (await next()) {
// match('object') is equivalent to head() === 'object'
// Essentially: "If the current line starts with 'object'"
if (match('object')) {
const objectLevel = level()
// When we call next with a parent level,
// it only iterates over lines inside the parent block
while (await next(objectLevel)) {
// Skip empty lines
if (!line()) continue
// Add any properties to the object as strings using the
// line head() as the key and tail() as the value
output[head()] = tail()
}
}
}
console.dir(output)
// { property1: 'Value 1', property2: 'Value 2', random_property: 'igazi3ii4quaC5OdoB5quohnah1beeNg' }
Heading 2 Contributing
class mt-12

View File

@ -1,6 +1,6 @@
const { contentAsText } = require('../helpers')
const languages = ['terrace', 'json', 'yaml', 'toml', 'javascript', 'typescript', 'c', 'python']
const languages = ['terrace', 'json', 'yaml', 'toml', 'javascript', 'typescript', 'c', 'python', 'sh']
module.exports = async (doc, rootLevel) => {
const { next, level, line, head, tail, match } = doc
@ -23,7 +23,7 @@ module.exports = async (doc, rootLevel) => {
node.examples.push({
language: head(),
name: tail() || '',
code: await contentAsText(doc, exampleLevel)
code: (await contentAsText(doc, exampleLevel)).trimEnd('\n')
})
}
}

View File

@ -51,6 +51,13 @@ module.exports = {
fontFamily: {
sans: ['Fredoka', ...defaultTheme.fontFamily.sans],
},
typography: {
DEFAULT: {
css: {
maxWidth: '80ch'
}
}
}
},
},
variants: {},

View File

@ -1,6 +1,6 @@
// Holds the parsed information from each line.
export type LineData = {
// Which character is being used for indentation. Avoids having to specify it on each terrace_parse_line call.
// Which character is being used for indentation. Avoids having to specify it on each parseLine call.
indent: string;
// How many indent characters are present in the current line before the first non-indent character.
level: number;
@ -12,7 +12,7 @@ export type LineData = {
}
/**
* Initialize a LineData instance with default values.
* Initialize a LineData instance with default values to pass to parseLine()
* @param {string} indent The character to use for indenting lines. ONLY ONE CHARACTER IS CURRENTLY PERMITTED.
* @returns {LineData} A LineData instance with the specified indent character and all other values initialized to 0.
*/
@ -21,10 +21,10 @@ export function createLineData(indent: string = ' '): LineData {
}
/**
* Core Terrace parser function, sets level, offsetHead, and offsetTail in a LineData object based on the current line.
* Core Terrace parser function, sets level, offsetHead, and offsetTail in a LineData object based on the passed line.
* Note that this is a C-style function, lineData is treated as a reference and mutated in-place.
* @param {string} line A string containing a line to parse. Shouldn't end with a newline.
* @param {LineData} lineData A LineData object to store information about the current line in. **Mutated in-place!**
* @param {LineData} lineData A LineData object to store information about the current line, from `createLineData()` **Mutated in-place!**
*/
export function parseLine(line: string, lineData: LineData) {
if ((typeof lineData !== 'object' || !lineData) || typeof lineData.level !== 'number') throw new Error(`'lineData' must be an object with string line and numeric level properties`)

View File

@ -1,7 +1,15 @@
import type { Reader } from './reader'
export function createStringReader(doc: string|string[], index = 0): Reader {
const lines = Array.isArray(doc) ? doc : doc.split('\n')
/**
* Get a simple `Reader` function that always returns the next line
* from a multiline string or an array of line strings.
*
* @param {string|string[]} source The lines to iterate over, as a multiline string or an array of line strings.
* @param {number} index Optional - which line to start from.
* @returns {Reader} A reader function that returns each line from the source document when called sequentially.
*/
export function createStringReader(source: string|string[], index: number = 0): Reader {
const lines = Array.isArray(source) ? source : source.split('\n')
index--;

View File

@ -2,18 +2,36 @@ import fs from 'node:fs'
import readline from 'node:readline/promises'
import type { Reader } from './reader'
/**
* Get a `Reader` function that always returns the next line from a passed read stream when called sequentially.
* @param {NodeJS.ReadStream|fs.ReadStream} stream A ReadStream compatible with Node.js `readline` APIs
* @returns {Reader} A reader function that returns each line from the stream when called sequentially
*/
export function createStreamReader(stream: NodeJS.ReadStream|fs.ReadStream): Reader {
// A bit of a messy way of working with readline, but the most straightforward
// way I found that allowed pulling lines with a promise-style interface.
const iterator = readline.createInterface({
input: stream
})[Symbol.asyncIterator]()
return async () => (await iterator.next()).value
}
/**
* Get a `Reader` function that always returns the next line from the specified file when called sequentially.
* @param {string} path A path to the file to read.
* @returns {Reader} A reader function that returns each line from the file when called sequentially
*/
export function createFileReader(path: string): Reader {
const it = readline.createInterface({
input: fs.createReadStream(path, 'utf-8'),
})[Symbol.asyncIterator]()
return async () => (await it.next()).value
return createStreamReader(fs.createReadStream(path, 'utf-8'))
}
/**
* Get a `Reader` function that always returns the next line from `stdin` when called sequentially.
* Does not block stdin to wait for input. If no input is present it returns null immediately.
* @returns {Reader} A reader function that returns each line from the stdin when called sequentially.
*/
export function createStdinReader(): Reader {
const it = readline.createInterface({
input: process.stdin
})[Symbol.asyncIterator]()
return async () => (await it.next()).value
return createStreamReader(process.stdin)
}