diff --git a/CHANGELOG.md b/CHANGELOG.md index aa9a6e2..258e96f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) with some edits, and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +# 1.1.7 + +## What's Changed +* test: full code coverage w/ @mateonunez +* refactor: enforce code robustness + +## New Contributors +* @mateonunez made their first contribution in https://github.com/airscripts/analscript/pull/13 + +**Full Changelog**: https://github.com/airscripts/analscript/compare/1.1.6...1.1.7 + # 1.1.6 ## What's Changed diff --git a/README.md b/README.md index 5cbb853..150966f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@
- Analscript is an esoteric programming language, that takes inspiration from the fallen Anal Lang and serves, the purpose to be a modern approach for writing anally fast stuff. + Analscript is a joke esoteric programming language, that takes inspiration from the fallen AnalLang and serves, the purpose to be a modern approach for writing anally fast stuff.
@@ -14,6 +14,7 @@
## Contents
- [Installation](#installation)
- [Usage](#usage)
+- [Resources](#resources)
- [Contributing](#contributing)
- [Support](#support)
- [License](#license)
@@ -35,7 +36,7 @@ analscript help
This command will show you something like this:
```
-Analscript Version 1.1.6
+Analscript Version 1.1.7
Copyright (c) 2023 by Airscript
Usage:
@@ -58,17 +59,27 @@ Arguments:
As you can see, you can as of this latest version, have access to a variety of commands.
Use them to write or read your anally marvelous softwares!
+## Resources
+- [Esolang Wiki Page](https://esolangs.org/wiki/Analscript): the official Esolang Wiki page.
+- [GitHub Page](https://ghio.airscript.it/analscript): the GitHub page for this repository.
+
## Contributing
Contributions and suggestions about how to improve this project are welcome!
Just follow our [contributing guidelines](https://github.com/airscripts/analscript/blob/main/CONTRIBUTING.md).
## Support
-If you want to support my work you can do it with the links below.
-
+If you want to support my work you can do it following me, leaving a star, sharing my projects or also with the links below.
Choose what you find more suitable for you:
-- [Support me on GitHub](https://github.com/sponsors/Airscripts)
-- [Support me via ko-fi](https://ko-fi.com/airscript)
-- [Support me via linktr.ee](https://linktr.ee/airscript)
+
+
+
+
+
+
+
+
+
+
*As of my personal preference, I'do go with GitHub Sponsors.*
diff --git a/VERSION b/VERSION
index ab67981..a5ba932 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.6
\ No newline at end of file
+1.1.7
\ No newline at end of file
diff --git a/analscript.js b/analscript.js
index 3da3f4f..94001f5 100644
--- a/analscript.js
+++ b/analscript.js
@@ -1,4 +1,4 @@
-import { anallify, stringify } from './lib/stdlib.js';
+import { anallify, stringify } from './lib/std.js';
export { anallify, stringify };
export default { anallify, stringify };
diff --git a/assets/images/cover.png b/assets/images/cover.png
new file mode 100644
index 0000000..a0fda09
Binary files /dev/null and b/assets/images/cover.png differ
diff --git a/assets/images/github-sponsors.svg b/assets/images/github-sponsors.svg
new file mode 100644
index 0000000..7743dcb
--- /dev/null
+++ b/assets/images/github-sponsors.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/images/kofi.svg b/assets/images/kofi.svg
new file mode 100644
index 0000000..dae0275
--- /dev/null
+++ b/assets/images/kofi.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/images/linktree.svg b/assets/images/linktree.svg
new file mode 100644
index 0000000..92d03f0
--- /dev/null
+++ b/assets/images/linktree.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/cli.js b/cli.js
index 67a9e2a..6f21ee8 100644
--- a/cli.js
+++ b/cli.js
@@ -1,12 +1,13 @@
#!/usr/bin/env node
import help from './lib/help.js';
+import { graceful } from './lib/utils.js';
import {
run,
compile,
anallify,
stringify,
-} from './lib/stdlib.js';
+} from './lib/std.js';
import {
RUN,
@@ -33,4 +34,4 @@ function cli() {
process.stdout.write(`${output}\n`);
}
-cli();
+graceful(cli);
diff --git a/lib/constants.js b/lib/constants.js
index 355cbb1..837e157 100644
--- a/lib/constants.js
+++ b/lib/constants.js
@@ -4,3 +4,4 @@ export const COMPILE = 'compile';
export const ANALLIFY = 'anallify';
export const STRINGIFY = 'stringify';
export const ANAL_CHARACTERS = '🍑🍆';
+export const GRAMMAR = `${ANAL_CHARACTERS} `;
diff --git a/lib/dictionary.js b/lib/dictionary.js
index cdb4cad..bf7a9ad 100644
--- a/lib/dictionary.js
+++ b/lib/dictionary.js
@@ -2,6 +2,7 @@ export const ERROR = {
fileNotFound: 'File not found.',
missingArgument: 'Missing argument.',
notString: 'Only strings are accepted',
+ notAcceptedByGrammar: 'There are some characters not accepted by grammar.',
};
export const SUCCESS = {
diff --git a/lib/help.js b/lib/help.js
index f5b1bf4..41628c1 100644
--- a/lib/help.js
+++ b/lib/help.js
@@ -1,4 +1,4 @@
-const version = 'Analscript, version 1.1.6';
+const version = 'Analscript, version 1.1.7';
const copyright = '\nCopyright (c) 2023 by Airscript\n';
const usage = `
diff --git a/lib/regexp.js b/lib/regexp.js
new file mode 100644
index 0000000..214133b
--- /dev/null
+++ b/lib/regexp.js
@@ -0,0 +1,4 @@
+import { ANAL_CHARACTERS, GRAMMAR } from './constants.js';
+
+export const matcher = new RegExp(`^[${GRAMMAR}]+$`, 'u');
+export const sequence = new RegExp(`${ANAL_CHARACTERS}`, 'g');
diff --git a/lib/std.js b/lib/std.js
new file mode 100644
index 0000000..ea9c6d4
--- /dev/null
+++ b/lib/std.js
@@ -0,0 +1,83 @@
+import fs from 'node:fs';
+
+import { checker } from './utils.js';
+import { ERROR, SUCCESS } from './dictionary.js';
+import { ANAL_CHARACTERS } from './constants.js';
+import { matcher, sequence } from './regexp.js';
+
+export function anallify(string) {
+ if (!checker(string)) {
+ throw new Error(ERROR.notString);
+ }
+
+ if (!string) {
+ throw new Error(ERROR.missingArgument);
+ }
+
+ let anal = '';
+ const characters = string.split('');
+
+ for (let index = 0; index < characters.length; index += 1) {
+ const character = characters[index];
+ const fragment = ANAL_CHARACTERS.repeat(character.charCodeAt(0));
+ anal = anal.concat(fragment).concat(' ');
+ }
+
+ return anal.trimEnd();
+}
+
+export function stringify(anal) {
+ if (!checker(anal)) {
+ throw new Error(ERROR.notString);
+ }
+
+ if (!anal) {
+ throw new Error(ERROR.missingArgument);
+ }
+
+ if (!matcher.test(anal)) {
+ throw new Error(ERROR.notAcceptedByGrammar);
+ }
+
+ let string = '';
+ const fragments = anal.split(' ');
+
+ for (let index = 0; index < fragments.length; index += 1) {
+ const fragment = fragments[index];
+ const character = String.fromCharCode(((fragment.match(sequence)).length));
+ string = string.concat(character);
+ }
+
+ return string;
+}
+
+export function run(file) {
+ let contents = null;
+
+ try {
+ contents = fs.readFileSync(file, { encoding: 'utf-8' });
+ } catch (error) {
+ throw new Error(ERROR.fileNotFound);
+ }
+
+ return stringify(contents);
+}
+
+export function compile(file) {
+ let contents = null;
+ const fileOptions = { encoding: 'utf-8' };
+
+ try {
+ contents = fs.readFileSync(file, fileOptions);
+ } catch (error) {
+ throw new Error(ERROR.fileNotFound);
+ }
+
+ let filename = file.split('.');
+ filename = filename.filter((element, index) => index < filename.length - 1);
+ filename = filename.join('.');
+
+ fs.writeFileSync(`${filename}.anal`, anallify(contents), fileOptions);
+ process.stdout.write(`${SUCCESS.compileSuccess}`);
+ return true;
+}
diff --git a/lib/stdlib.js b/lib/stdlib.js
deleted file mode 100644
index 1a0e1c4..0000000
--- a/lib/stdlib.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import fs from 'node:fs';
-
-import checker from './utils.js';
-import { ERROR, SUCCESS } from './dictionary.js';
-import { ANAL_CHARACTERS } from './constants.js';
-
-export function anallify(string) {
- if (!checker(string)) {
- process.stderr.write(`${ERROR.notString}\n`);
- return process.exit(1);
- }
-
- if (!string) {
- process.stderr.write(`${ERROR.missingArgument}\n`);
- return process.exit(1);
- }
-
- let anal = '';
- const characters = string.split('');
-
- for (let index = 0; index < characters.length; index += 1) {
- const character = characters[index];
- const fragment = ANAL_CHARACTERS.repeat(character.charCodeAt(0));
- anal = anal.concat(fragment).concat(' ');
- }
-
- return anal.trimEnd();
-}
-
-export function stringify(anal) {
- if (!checker(anal)) {
- process.stderr.write(`${ERROR.notString}\n`);
- return process.exit(1);
- }
-
- if (!anal) {
- process.stderr.write(`${ERROR.missingArgument}\n`);
- return process.exit(1);
- }
-
- let string = '';
- const fragments = anal.split(' ');
- const rule = new RegExp(`${ANAL_CHARACTERS}`, 'g');
-
- for (let index = 0; index < fragments.length; index += 1) {
- const fragment = fragments[index];
- const character = String.fromCharCode(((fragment.match(rule) || []).length));
- string = string.concat(character);
- }
-
- return string;
-}
-
-export function run(file) {
- try {
- const contents = fs.readFileSync(file, { encoding: 'utf-8' });
- return stringify(contents);
- } catch (error) {
- process.stderr.write(`${ERROR.fileNotFound}\n`);
- return process.exit(1);
- }
-}
-
-export function compile(file) {
- try {
- const contents = fs.readFileSync(file, { encoding: 'utf-8' });
-
- let filename = file.split('.');
- filename = filename.filter((element, index) => index < filename.length - 1);
- filename = filename.join('.');
-
- fs.writeFileSync(`${filename}.anal`, anallify(contents), { encoding: 'utf-8' });
- process.stdout.write(`${SUCCESS.compileSuccess}`);
- } catch (error) {
- process.stderr.write(`${ERROR.fileNotFound}\n`);
- process.exit(1);
- }
-}
diff --git a/lib/utils.js b/lib/utils.js
index 526170d..ec47d2c 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -1,3 +1,12 @@
-export default function checker(input) {
+export function checker(input) {
return typeof input === 'string';
}
+
+export function graceful(fn) {
+ try {
+ fn();
+ } catch (error) {
+ process.stderr.write(`${error.message}\n`);
+ process.exit(1);
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index 86373e2..a0d88f9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,26 @@
{
"name": "analscript",
- "version": "1.1.5",
+ "version": "1.1.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "analscript",
- "version": "1.1.5",
+ "version": "1.1.7",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/airscripts"
+ },
+ {
+ "type": "ko-fi",
+ "url": "https://ko-fi.com/airscript"
+ },
+ {
+ "type": "linktree",
+ "url": "https://linktr.ee/airscript"
+ }
+ ],
"license": "MIT",
"bin": {
"analscript": "cli.js"
diff --git a/package.json b/package.json
index 51b1d4c..237d63c 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,15 @@
{
"type": "module",
- "version": "1.1.6",
+ "version": "1.1.7",
"name": "analscript",
+ "author": "Airscript",
"main": "analscript.js",
"description": "A modern approach for writing anally fast stuff.",
+ "keywords": ["analscript", "programming language", "esoteric", "cli", "anal"],
+ "homepage": "https://github.com/airscripts/analscript",
+ "bugs": {
+ "email": "support@airscript.it"
+ },
"scripts": {
"test:std": "vitest",
"test:ui": "vitest --ui",
@@ -12,7 +18,24 @@
"bin": {
"analscript": "cli.js"
},
- "author": "Airscript",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/airscripts/analscript.git"
+ },
+ "funding": [
+ {
+ "type" : "github",
+ "url" : "https://github.com/sponsors/airscripts"
+ },
+ {
+ "type" : "ko-fi",
+ "url" : "https://ko-fi.com/airscript"
+ },
+ {
+ "type": "linktree",
+ "url": "https://linktr.ee/airscript"
+ }
+ ],
"license": "MIT",
"devDependencies": {
"@vitest/coverage-v8": "^0.33.0",
@@ -22,5 +45,5 @@
"eslint-plugin-import": "^2.28.0",
"prettier": "^3.0.0",
"vitest": "^0.33.0"
- }
+ }
}
diff --git a/tests/hello.anus b/tests/hello.anus
new file mode 100644
index 0000000..99f615c
--- /dev/null
+++ b/tests/hello.anus
@@ -0,0 +1 @@
+Hello, Analscript!
\ No newline at end of file
diff --git a/tests/seeds.js b/tests/seeds.js
index 2d3d790..bae9e1a 100644
--- a/tests/seeds.js
+++ b/tests/seeds.js
@@ -1,3 +1,7 @@
+export const NUMERIC_INPUT = 1;
+export const EMPTY_STRING_INPUT = '';
+export const NOT_ACCEPTED_INPUT = '🍑🍆 a';
+
export const STRINGIFY_CORRECT_OUTPUT = 'B';
export const STRINGIFY_WRONG_OUTPUT = '🍑🍆🍑🍆';
export const STRINGIFY_INPUT = '🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆';
@@ -9,3 +13,7 @@ export const ANALLIFY_CORRECT_OUTPUT = '🍑🍆🍑🍆🍑🍆🍑🍆🍑🍆
export const ANAL_FILE_LOCATION = 'tests/script.anal';
export const RUN_CORRECT_OUTPUT = 'Welcome to Analscript!';
export const RUN_WRONG_OUTPUT = 'Welcome to Jurassic Park!';
+
+export const COMPILE_CORRECT_OUTPUT = true;
+export const FILE_LOCATION = 'tests/hello.anus';
+export const COMPILED_FILE_LOCATION = 'tests/hello.anal';
diff --git a/tests/std.test.js b/tests/std.test.js
new file mode 100644
index 0000000..b5ea901
--- /dev/null
+++ b/tests/std.test.js
@@ -0,0 +1,96 @@
+import fs from 'node:fs';
+import { test, expect, describe } from 'vitest';
+
+import {
+ FILE_LOCATION,
+ NUMERIC_INPUT,
+ ANALLIFY_INPUT,
+ STRINGIFY_INPUT,
+ RUN_WRONG_OUTPUT,
+ ANAL_FILE_LOCATION,
+ EMPTY_STRING_INPUT,
+ NOT_ACCEPTED_INPUT,
+ RUN_CORRECT_OUTPUT,
+ ANALLIFY_WRONG_OUTPUT,
+ STRINGIFY_WRONG_OUTPUT,
+ COMPILE_CORRECT_OUTPUT,
+ COMPILED_FILE_LOCATION,
+ ANALLIFY_CORRECT_OUTPUT,
+ STRINGIFY_CORRECT_OUTPUT,
+} from './seeds.js';
+
+import {
+ run,
+ anallify,
+ stringify,
+ compile,
+} from '../lib/std.js';
+import { ERROR } from '../lib/dictionary.js';
+
+describe('Anallify', () => {
+ test('Encode string to anal', () => {
+ expect(anallify(ANALLIFY_INPUT)).toBe(ANALLIFY_CORRECT_OUTPUT);
+ expect(anallify(ANALLIFY_INPUT)).not.toBe(ANALLIFY_WRONG_OUTPUT);
+ });
+
+ test('Throw error if argument is not a string', () => {
+ expect(() => anallify(1)).toThrowError(Error(ERROR.notString));
+ });
+
+ test('Throw error if argument is missing', () => {
+ expect(() => anallify(EMPTY_STRING_INPUT)).toThrowError(
+ Error(ERROR.missingArgument),
+ );
+ });
+});
+
+describe('Stringify', () => {
+ test('Decode anal to string', () => {
+ expect(stringify(STRINGIFY_INPUT)).toBe(STRINGIFY_CORRECT_OUTPUT);
+ expect(stringify(STRINGIFY_INPUT)).not.toBe(STRINGIFY_WRONG_OUTPUT);
+ });
+
+ test('Throw error if argument is not a string', () => {
+ expect(() => stringify(NUMERIC_INPUT)).toThrowError(
+ Error(ERROR.notString),
+ );
+ });
+
+ test('Throw error if argument is missing', () => {
+ expect(() => stringify(EMPTY_STRING_INPUT)).toThrowError(
+ Error(ERROR.missingArgument),
+ );
+ });
+
+ test('Throw error if there are grammar-refused characters', () => {
+ expect(() => stringify(NOT_ACCEPTED_INPUT)).toThrowError(
+ Error(ERROR.notAcceptedByGrammar),
+ );
+ });
+});
+
+describe('Run', () => {
+ test('Run .anal file', () => {
+ expect(run(ANAL_FILE_LOCATION)).toBe(RUN_CORRECT_OUTPUT);
+ expect(run(ANAL_FILE_LOCATION)).not.toBe(RUN_WRONG_OUTPUT);
+ });
+
+ test('Throw error if file is not found', () => {
+ expect(() => run(EMPTY_STRING_INPUT)).toThrowError(
+ Error(ERROR.fileNotFound),
+ );
+ });
+});
+
+describe('Compile', () => {
+ test('Compile file to .anal', () => {
+ expect(compile(FILE_LOCATION)).toBe(COMPILE_CORRECT_OUTPUT);
+ fs.rmSync(COMPILED_FILE_LOCATION);
+ });
+
+ test('Throw error if file is not found', () => {
+ expect(() => compile(EMPTY_STRING_INPUT)).toThrowError(
+ Error(ERROR.fileNotFound),
+ );
+ });
+});
diff --git a/tests/stdlib.test.js b/tests/stdlib.test.js
deleted file mode 100644
index b25089b..0000000
--- a/tests/stdlib.test.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import { test, expect } from 'vitest';
-
-import {
- ANALLIFY_INPUT,
- STRINGIFY_INPUT,
- RUN_WRONG_OUTPUT,
- ANAL_FILE_LOCATION,
- RUN_CORRECT_OUTPUT,
- ANALLIFY_WRONG_OUTPUT,
- STRINGIFY_WRONG_OUTPUT,
- ANALLIFY_CORRECT_OUTPUT,
- STRINGIFY_CORRECT_OUTPUT,
-} from './seeds.js';
-
-import {
- run,
- anallify,
- stringify,
-} from '../lib/stdlib.js';
-
-test('Encode string to anal', () => {
- expect(anallify(ANALLIFY_INPUT)).toBe(ANALLIFY_CORRECT_OUTPUT);
- expect(anallify(ANALLIFY_INPUT)).not.toBe(ANALLIFY_WRONG_OUTPUT);
-});
-
-test('Decode anal to string', () => {
- expect(stringify(STRINGIFY_INPUT)).toBe(STRINGIFY_CORRECT_OUTPUT);
- expect(stringify(STRINGIFY_INPUT)).not.toBe(STRINGIFY_WRONG_OUTPUT);
-});
-
-test('Run .anal file', () => {
- expect(run(ANAL_FILE_LOCATION)).toBe(RUN_CORRECT_OUTPUT);
- expect(run(ANAL_FILE_LOCATION)).not.toBe(RUN_WRONG_OUTPUT);
-});
diff --git a/tests/utils.test.js b/tests/utils.test.js
new file mode 100644
index 0000000..7f3d514
--- /dev/null
+++ b/tests/utils.test.js
@@ -0,0 +1,23 @@
+import {
+ vi,
+ test,
+ expect,
+ describe,
+} from 'vitest';
+
+import { graceful } from '../lib/utils.js';
+import { EMPTY_STRING_INPUT } from './seeds.js';
+
+describe('Graceful', () => {
+ test('Execute graceful', () => {
+ const fn = vi.fn();
+ graceful(fn);
+ expect(fn).toBeCalled();
+ });
+
+ test('Trigger graceful exit', () => {
+ const processExit = vi.spyOn(process, 'exit').mockImplementation(() => {});
+ graceful(EMPTY_STRING_INPUT);
+ expect(processExit).toHaveBeenCalled();
+ });
+});