Skip to content

Commit

Permalink
feat: @crayon/literal 1.0 alpha release
Browse files Browse the repository at this point in the history
  • Loading branch information
Im-Beast committed Jun 28, 2024
0 parents commit 533baa3
Show file tree
Hide file tree
Showing 8 changed files with 337 additions and 0 deletions.
50 changes: 50 additions & 0 deletions .github/workflows/deno.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Deno

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
# Test for latest stable and canary deno versions
deno-version: [vx.x.x, canary]

steps:
- name: Setup repo
uses: actions/checkout@v2

- name: Setup Deno ${{ matrix.deno-version }}
uses: denoland/setup-deno@v1.1.4
with:
deno-version: ${{ matrix.deno-version }}

- name: Check typings
run: deno check main.ts

- name: Check formatting
run: deno fmt --check

- name: Check linting
run: deno lint

- name: Run tests
run: deno task test

- name: Run dry publish
run: deno publish --dry-run

- name: Run benchmarks
run: deno task bench

- name: Check license headers
run: |
deno run -A --no-check https://deno.land/x/anzu@1.0.2/src/cli.ts \
-i ./ "/.+\.ts/" \
-e "deps.ts" \
-l "// Copyright 2024 Im-Beast. All rights reserved. MIT license."
21 changes: 21 additions & 0 deletions .github/workflows/node.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Node.js

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
node-version: [18.x, 21.x]

steps:
- uses: actions/checkout@v3
- run: npx jsr add @cross/test @std/assert
- run: 'echo ''{ "type": "module" }'' > package.json' # Needed for tsx to work
- run: npx --yes tsx --test *.test.ts
20 changes: 20 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# The MIT License (MIT)

## Copyright © 2024 Im-Beast

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the “Software”), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# 📝 Crayon Literal Templates

## 📚 About

`@crayon/literal` is an extension for Crayon that adds support for styling using ES6 Literal
Templates.

## ⚙️ Usage

```ts
// Remember to replace "version" with semver version
import crayon from "@crayon/crayon";
import "@crayon/literal";

console.log(
crayon`{red I'm red! {blue I'm blue!} {bgBlue.bold I'm kind of both! But also bold!}}`,
);

// Methods are also supported
console.log(
crayon`{rgb(0,255,0) Im green {bgHex(0xFF0000) and I have red background}}`,
);
```

## 🤝 Contributing

**Crayon** is open for any contributions.\
If you feel like you can enhance this project - please open an issue and/or pull request.\
Code should be well document and easy to follow what's going on.

**Crayon 4.x** follows [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/).\
If your pull request's code could introduce understandability trouble, please add comments to it.

## 📝 Licensing

This project is available under **MIT** License conditions.
20 changes: 20 additions & 0 deletions deno.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@crayon/literal",
"version": "1.0.0-alpha.1",

"imports": {
"@crayon/crayon": "jsr:/@crayon/crayon@4.0.0-alpha.2",
// tests
"@cross/test": "jsr:@cross/test@0.0.9",
"@std/assert": "jsr:@std/assert@0.221.0"
},
"exports": "./main.ts",

"fmt": {
"lineWidth": 100
},

"compilerOptions": {
"lib": ["es2023", "dom"]
}
}
61 changes: 61 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions main.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { test } from "@cross/test";
import { assert, assertEquals, assertThrows } from "@std/assert";

import crayon from "@crayon/crayon";
import "./main.ts";

test("Literal", () => {
assert(crayon`{red {bold Hello} world!}`.endsWith("\x1b[0m"));
assertEquals(
crayon`{red {bold Hello} world!}`,
"\x1b[31m\x1b[1mHello\x1b[0m\x1b[31m world!\x1b[0m",
);
assertEquals(
crayon`{rgb(255,0,17) methods {bgRgb(127,255,0) work!}}`,
"\x1b[38;2;255;0;17mmethods \x1b[48;2;127;255;0mwork!\x1b[0m\x1b[38;2;255;0;17m\x1b[0m",
);
});

test("Errors", () => {
assertThrows(() => crayon`{inexistentStyle xyz}`);
});
108 changes: 108 additions & 0 deletions main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2024 Im-Beast. All rights reserved. MIT license.
import { ColorSupport, prototype } from "@crayon/crayon/raw";
import { replace, replaceAll } from "@crayon/crayon/utils";

import crayon from "@crayon/crayon/base";
import type { Attribute, FourBitColor } from "@crayon/crayon/styles";

type BaseStyle = FourBitColor | Attribute;
const literalStyleRegex = /{([^\s{}]+)\s([^{}]+)}/;

// Parse string to a type
// e.g. "0" -> 0
// "\"Hello\"" -> "Hello"
// "`Hello`" -> "Hello"
// "true" -> true
function compileType(string: string): string | number | boolean {
switch (string) {
case "true":
return true;
case "false":
return false;
default:
switch (string[0]) {
case '"':
case "'":
case "`":
return string.slice(1, -1);
default:
return Number(string);
}
}
}

// Parse string to crayon style method's styleBuffer
// e.g
// "rgb(123,50,30)" -> crayon.rgb(123, 50, 30).styleBuffer
// "bgHex(0xFF00FF)" -> crayon.bgHex(0xFF00FF).styleBuffer
export function parseStyleMethod(call: string): string {
let methodName = "";
let intermediate = "";
const args = [];

loop: for (let i = 0; i < call.length; i++) {
const char = call[i];
switch (char) {
case ")":
if (intermediate) args.push(compileType(intermediate));
break loop;
case "(":
methodName = intermediate;
intermediate = "";
continue;
case ",":
args.push(compileType(intermediate));
intermediate = "";
continue;
default:
intermediate += char;
}
}

// @ts-expect-error dynamic type
return crayon[methodName]?.(...args)?.styleBuffer;
}

export function parseStyle(style: string): string {
if (style.endsWith(")")) {
return parseStyleMethod(style);
}
return crayon[style as BaseStyle]?.styleBuffer;
}

/** Implementation for Crayon's `prototype.literal` call when using ES6 Literal Templates */
export function literal(
callSite: TemplateStringsArray,
...substitutions: unknown[]
): string {
let text = "";
for (let i = 0; i < callSite.length; ++i) {
text += callSite[i];
text += substitutions[i] ?? "";
}

if (prototype.$colorSupport === ColorSupport.NoColor) {
return text;
}

let matches = text.match(literalStyleRegex);
while (matches?.length) {
const [section, styles, body] = matches;

let styleBuffer = "";
for (const style of styles.split(".")) {
const parsedStyle = parseStyle(style);
if (!parsedStyle) throw new Error(`Invalid style: ${style}`);
styleBuffer += parsedStyle;
}

const matchedText = replaceAll(body, "\x1b[0m", "\x1b[0m" + styleBuffer);
text = replace(text, section, styleBuffer + matchedText + "\x1b[0m");

matches = text.match(literalStyleRegex);
}

return text;
}

prototype.literal = literal;

0 comments on commit 533baa3

Please sign in to comment.