style: Added and ran prettier.

This commit is contained in:
Spencer Brower
2023-05-25 17:31:52 -04:00
parent 2952a1cfef
commit 7f8ef72f19
11 changed files with 284 additions and 240 deletions

7
.prettierignore Normal file
View File

@@ -0,0 +1,7 @@
.direnv
docs
lib
node_modules
CHANGELOG.md
*.nix
*.lock

1
.prettierrc.json Normal file
View File

@@ -0,0 +1 @@
{}

View File

@@ -2,4 +2,4 @@
A small, simple, functional, and dependency-free library for JavaScript string manipulation.
You can view the docs [here](./docs/modules.md)
You can view the docs [here](./docs/modules.md)

View File

@@ -16,6 +16,7 @@
"devDependencies": {
"@types/ramda": "^0.29.1",
"fast-check": "^3.9.0",
"prettier": "^2.8.8",
"ramda": "^0.29.0",
"standard-version": "^9.5.0",
"typedoc": "^0.24.7",

View File

@@ -1,155 +1,172 @@
import { describe, expect, it } from 'vitest';
import fc from 'fast-check';
import { describe, expect, it } from "vitest";
import fc from "fast-check";
import {
/*afterFirstWord, beforeFirstWord, */ afterFirst, afterLast, endsWith, ltrim, rtrim, trim, startsWith, beforeFirst,
} from './index';
/*afterFirstWord, beforeFirstWord, */ afterFirst,
afterLast,
endsWith,
ltrim,
rtrim,
trim,
startsWith,
beforeFirst,
} from "./index";
describe('strings', () => {
describe('startsWith', () => {
it('returns true if haystack starts with needle', () => {
expect(startsWith('foo', 'foobar')).toBe(true);
})
it('returns true when haystack is needle', () => {
expect(startsWith('foo', 'foo')).toBe(true);
})
it('works', () => {
fc.assert(fc.property(fc.string(), fc.string(), (needle, haystack) => {
if (haystack.indexOf(needle) == 0) {
expect(startsWith(needle, haystack)).toBe(true);
}
}));
})
describe("strings", () => {
describe("startsWith", () => {
it("returns true if haystack starts with needle", () => {
expect(startsWith("foo", "foobar")).toBe(true);
});
describe('endsWith', () => {
it('returns true if haystack end with needle', () => {
expect(endsWith('bar', 'foobar')).toBe(true);
})
it('returns true when haystack is needle', () => {
expect(endsWith('foo', 'foo')).toBe(true);
})
it('works', () => {
fc.assert(fc.property(fc.string(), fc.string(), (needle, haystack) => {
if (haystack.substring(haystack.indexOf(needle)) == needle) {
expect(endsWith(needle, haystack)).toBe(true);
}
}));
})
it("returns true when haystack is needle", () => {
expect(startsWith("foo", "foo")).toBe(true);
});
describe('afterFirst', () => {
it('removes everything before the first needle when possible', () => {
expect(afterFirst(' ', 'foo bar bat')).toBe('bar bat');
})
it('removes nothing when needle is not present', () => {
expect(afterFirst('&', 'foo bar bat')).toBe('foo bar bat');
})
})
describe('afterLast', () => {
it('removes everything after the last needle when possible', () => {
expect(afterLast(' ', 'foo bar bat')).toBe('bat');
})
it('removes nothing when needle is not present', () => {
expect(afterLast('&', 'foo bar bat')).toBe('foo bar bat');
})
})
describe('beforeFirst', () => {
it('removes everything after the first needle when possible', () => {
expect(beforeFirst(' ', 'foo bar bat')).toBe('foo');
})
it('removes everythin when needle is not present', () => {
expect(beforeFirst('&', 'foo bar bat')).toBe('');
})
})
// describe('afterFirstWord', () => {
// it('removes the first word', () => {
// fc.assert(fc.property(fc.string(), (str) => {
// const got = afterFirstWord(str);
// if (got !== '') {
// expect(endsWith(got, str)).toBe(true);
// if (str.indexOf(' ') !== -1) {
// expect(`${beforeFirstWord(str)} ${got}`).toBe(str);
// }
// }
// }));
// });
// });
describe('ltrim', () => {
it('returns input when cutset is empty', () => {
expect(ltrim('', 'foo')).toBe('foo');
});
it('returns empty when input is empty', () => {
expect(ltrim('foo', '')).toBe('');
});
it('can be curried', () => {
expect(ltrim('foo', '')).toBe(ltrim('foo')(''));
expect(ltrim(' ', ' foo')).toBe(ltrim(' ')(' foo'));
});
it('trims cutset', () => {
fc.assert(fc.property(fc.string(), fc.string(), (cutset, str) => {
const got = ltrim(cutset, str);
if (cutset === '') {
expect(got).toBe(str);
} else if (str === '') {
expect(got).toBe('');
} else {
if (got === '') {
for (const char of str) {
expect(cutset).contains(char);
}
it("works", () => {
fc.assert(
fc.property(fc.string(), fc.string(), (needle, haystack) => {
if (haystack.indexOf(needle) == 0) {
expect(startsWith(needle, haystack)).toBe(true);
}
for (const char of cutset) {
expect(startsWith(char, got)).toBe(false);
})
);
});
});
describe("endsWith", () => {
it("returns true if haystack end with needle", () => {
expect(endsWith("bar", "foobar")).toBe(true);
});
it("returns true when haystack is needle", () => {
expect(endsWith("foo", "foo")).toBe(true);
});
it("works", () => {
fc.assert(
fc.property(fc.string(), fc.string(), (needle, haystack) => {
if (haystack.substring(haystack.indexOf(needle)) == needle) {
expect(endsWith(needle, haystack)).toBe(true);
}
}
}));
})
);
});
});
describe("afterFirst", () => {
it("removes everything before the first needle when possible", () => {
expect(afterFirst(" ", "foo bar bat")).toBe("bar bat");
});
it("removes nothing when needle is not present", () => {
expect(afterFirst("&", "foo bar bat")).toBe("foo bar bat");
});
});
describe("afterLast", () => {
it("removes everything after the last needle when possible", () => {
expect(afterLast(" ", "foo bar bat")).toBe("bat");
});
it("removes nothing when needle is not present", () => {
expect(afterLast("&", "foo bar bat")).toBe("foo bar bat");
});
});
describe('rtrim', () => {
it('returns input when cutset is empty', () => {
expect(rtrim('', 'foo')).toBe('foo');
describe("beforeFirst", () => {
it("removes everything after the first needle when possible", () => {
expect(beforeFirst(" ", "foo bar bat")).toBe("foo");
});
it('returns empty when input is empty', () => {
expect(rtrim('foo', '')).toBe('');
});
it('can be curried', () => {
expect(rtrim('foo', '')).toBe(rtrim('foo')(''));
expect(rtrim(' ', ' foo')).toBe(rtrim(' ')(' foo'));
});
it('trims cutset', () => {
fc.assert(fc.property(fc.string(), fc.string(), (cutset, str) => {
const got = rtrim(cutset, str);
if (cutset === '') {
expect(got).toBe(str);
} else if (str === '') {
expect(got).toBe('');
} else {
if (got === '') {
for (const char of str) {
expect(cutset).contains(char);
it("removes everythin when needle is not present", () => {
expect(beforeFirst("&", "foo bar bat")).toBe("");
});
});
// describe('afterFirstWord', () => {
// it('removes the first word', () => {
// fc.assert(fc.property(fc.string(), (str) => {
// const got = afterFirstWord(str);
// if (got !== '') {
// expect(endsWith(got, str)).toBe(true);
// if (str.indexOf(' ') !== -1) {
// expect(`${beforeFirstWord(str)} ${got}`).toBe(str);
// }
// }
// }));
// });
// });
describe("ltrim", () => {
it("returns input when cutset is empty", () => {
expect(ltrim("", "foo")).toBe("foo");
});
it("returns empty when input is empty", () => {
expect(ltrim("foo", "")).toBe("");
});
it("can be curried", () => {
expect(ltrim("foo", "")).toBe(ltrim("foo")(""));
expect(ltrim(" ", " foo")).toBe(ltrim(" ")(" foo"));
});
it("trims cutset", () => {
fc.assert(
fc.property(fc.string(), fc.string(), (cutset, str) => {
const got = ltrim(cutset, str);
if (cutset === "") {
expect(got).toBe(str);
} else if (str === "") {
expect(got).toBe("");
} else {
if (got === "") {
for (const char of str) {
expect(cutset).contains(char);
}
}
for (const char of cutset) {
expect(startsWith(char, got)).toBe(false);
}
}
for (const char of cutset) {
expect(endsWith(char, got)).toBe(false);
}
}
}));
})
);
});
});
describe('trim', () => {
it("composes 'ltrim' and 'rtrim'", function() {
fc.assert(fc.property(fc.string(), fc.string(), (cutset, str) => {
expect(trim(cutset, str)).toBe(ltrim(cutset, rtrim(cutset, str)));
}));
describe("rtrim", () => {
it("returns input when cutset is empty", () => {
expect(rtrim("", "foo")).toBe("foo");
});
})
});
it("returns empty when input is empty", () => {
expect(rtrim("foo", "")).toBe("");
});
it("can be curried", () => {
expect(rtrim("foo", "")).toBe(rtrim("foo")(""));
expect(rtrim(" ", " foo")).toBe(rtrim(" ")(" foo"));
});
it("trims cutset", () => {
fc.assert(
fc.property(fc.string(), fc.string(), (cutset, str) => {
const got = rtrim(cutset, str);
if (cutset === "") {
expect(got).toBe(str);
} else if (str === "") {
expect(got).toBe("");
} else {
if (got === "") {
for (const char of str) {
expect(cutset).contains(char);
}
}
for (const char of cutset) {
expect(endsWith(char, got)).toBe(false);
}
}
})
);
});
});
describe("trim", () => {
it("composes 'ltrim' and 'rtrim'", function () {
fc.assert(
fc.property(fc.string(), fc.string(), (cutset, str) => {
expect(trim(cutset, str)).toBe(ltrim(cutset, rtrim(cutset, str)));
})
);
});
});
});

View File

@@ -1,29 +1,33 @@
import { curry } from "./utils";
export * from './trim';
export * from "./trim";
function escapeRegExp(str: string) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}
export const startsWith = curry((needle: string, haystack: string) => haystack.indexOf(needle) === 0);
export const endsWith = curry((needle: string, haystack: string) => (new RegExp(`${escapeRegExp(needle)}$`)).test(haystack));
export const afterFirst = curry(
(separator: string, str: string) => str.substring(str.indexOf(separator) + 1, str.length),
export const startsWith = curry(
(needle: string, haystack: string) => haystack.indexOf(needle) === 0
);
export const afterLast = curry(
(separator: string, str: string) => str.substring(str.lastIndexOf(separator) + 1, str.length),
export const endsWith = curry((needle: string, haystack: string) =>
new RegExp(`${escapeRegExp(needle)}$`).test(haystack)
);
export const beforeFirst = curry(
(separator: string, str: string) => str.substring(0, str.indexOf(separator)),
export const afterFirst = curry((separator: string, str: string) =>
str.substring(str.indexOf(separator) + 1, str.length)
);
export const afterLast = curry((separator: string, str: string) =>
str.substring(str.lastIndexOf(separator) + 1, str.length)
);
export const beforeFirst = curry((separator: string, str: string) =>
str.substring(0, str.indexOf(separator))
);
// @todo Test
export const beforeFirstWord = beforeFirst(' ');
export const beforeFirstWord = beforeFirst(" ");
// /**
// * @param {String} str

View File

@@ -4,80 +4,86 @@ import { describe, expect, it } from "vitest";
import { ltrim, rtrim, trim } from "./trim";
describe('trim', () => {
describe('ltrim', () => {
it('returns input when cutset is empty', () => {
expect(ltrim('', 'foo')).toBe('foo');
describe("trim", () => {
describe("ltrim", () => {
it("returns input when cutset is empty", () => {
expect(ltrim("", "foo")).toBe("foo");
});
it('returns empty when input is empty', () => {
expect(ltrim('foo', '')).toBe('');
it("returns empty when input is empty", () => {
expect(ltrim("foo", "")).toBe("");
});
it('can be curried', () => {
expect(ltrim('foo', '')).toBe(ltrim('foo')(''));
expect(ltrim(' ', ' foo')).toBe(ltrim(' ')(' foo'));
it("can be curried", () => {
expect(ltrim("foo", "")).toBe(ltrim("foo")(""));
expect(ltrim(" ", " foo")).toBe(ltrim(" ")(" foo"));
});
it('trims cutset', () => {
fc.assert(fc.property(fc.string(), fc.string(), (cutset, str) => {
const got = ltrim(cutset, str);
it("trims cutset", () => {
fc.assert(
fc.property(fc.string(), fc.string(), (cutset, str) => {
const got = ltrim(cutset, str);
if (cutset === '') {
expect(got).toBe(str);
} else if (str === '') {
expect(got).toBe('');
} else {
if (got === '') {
for (const char of str) {
expect(cutset).contains(char);
if (cutset === "") {
expect(got).toBe(str);
} else if (str === "") {
expect(got).toBe("");
} else {
if (got === "") {
for (const char of str) {
expect(cutset).contains(char);
}
}
for (const char of cutset) {
expect(startsWith(char, got)).toBe(false);
}
}
for (const char of cutset) {
expect(startsWith(char, got)).toBe(false);
}
}
}));
})
);
});
});
describe('rtrim', () => {
it('returns input when cutset is empty', () => {
expect(rtrim('', 'foo')).toBe('foo');
describe("rtrim", () => {
it("returns input when cutset is empty", () => {
expect(rtrim("", "foo")).toBe("foo");
});
it('returns empty when input is empty', () => {
expect(rtrim('foo', '')).toBe('');
it("returns empty when input is empty", () => {
expect(rtrim("foo", "")).toBe("");
});
it('can be curried', () => {
expect(rtrim('foo', '')).toBe(rtrim('foo')(''));
expect(rtrim(' ', ' foo')).toBe(rtrim(' ')(' foo'));
it("can be curried", () => {
expect(rtrim("foo", "")).toBe(rtrim("foo")(""));
expect(rtrim(" ", " foo")).toBe(rtrim(" ")(" foo"));
});
it('trims cutset', () => {
fc.assert(fc.property(fc.string(), fc.string(), (cutset, str) => {
const got = rtrim(cutset, str);
it("trims cutset", () => {
fc.assert(
fc.property(fc.string(), fc.string(), (cutset, str) => {
const got = rtrim(cutset, str);
if (cutset === '') {
expect(got).toBe(str);
} else if (str === '') {
expect(got).toBe('');
} else {
if (got === '') {
for (const char of str) {
expect(cutset).contains(char);
if (cutset === "") {
expect(got).toBe(str);
} else if (str === "") {
expect(got).toBe("");
} else {
if (got === "") {
for (const char of str) {
expect(cutset).contains(char);
}
}
for (const char of cutset) {
expect(endsWith(char, got)).toBe(false);
}
}
for (const char of cutset) {
expect(endsWith(char, got)).toBe(false);
}
}
}));
})
);
});
});
describe('trim', () => {
it("composes 'ltrim' and 'rtrim'", function() {
fc.assert(fc.property(fc.string(), fc.string(), (cutset, str) => {
expect(trim(cutset, str)).toBe(ltrim(cutset, rtrim(cutset, str)));
}));
describe("trim", () => {
it("composes 'ltrim' and 'rtrim'", function () {
fc.assert(
fc.property(fc.string(), fc.string(), (cutset, str) => {
expect(trim(cutset, str)).toBe(ltrim(cutset, rtrim(cutset, str)));
})
);
});
})
});
});
});

View File

@@ -7,22 +7,25 @@ import { curry, isEmpty, tail, when } from "./utils";
export const ltrim = curry((cutset: string, str: string) => {
const _trim = (x: string) => ltrim(cutset)(tail(x));
// const _trim = compose(ltrim(cutset), tail);
const trimmed: () => string = () => when((x: string = '') => cutset.includes(x.charAt(0)), _trim)(str);
const trimmed: () => string = () =>
when((x: string = "") => cutset.includes(x.charAt(0)), _trim)(str);
return isEmpty(cutset) || isEmpty(str)
? str
: trimmed();
return isEmpty(cutset) || isEmpty(str) ? str : trimmed();
});
export const rtrim = curry((cutset: string, str: string) => {
const _trim = (x: string) => rtrim(cutset)(x.substring(0, x.length - 1));
// const _trim = compose(rtrim(cutset), init);
const trimmed: () => string = () => when((x: string = '') => cutset.includes(x.charAt(x.length - 1)), _trim)(str);
const trimmed: () => string = () =>
when(
(x: string = "") => cutset.includes(x.charAt(x.length - 1)),
_trim
)(str);
return isEmpty(cutset) || isEmpty(str)
? str
: trimmed();
return isEmpty(cutset) || isEmpty(str) ? str : trimmed();
});
// const trim = curry((cutset: string, str: string) => compose(ltrim(cutset), rtrim(cutset))(str));
export const trim = curry((cutset: string, str: string) => ltrim(cutset)(rtrim(cutset, str)));
export const trim = curry((cutset: string, str: string) =>
ltrim(cutset)(rtrim(cutset, str))
);

View File

@@ -1,20 +1,20 @@
import type { curry as _curry, when as _when } from 'ramda';
import type { curry as _curry, when as _when } from "ramda";
export const curry = function(fn) {
return (...args) => {
if (args.length >= fn.length) {
return fn(...args);
}
// @ts-ignore
return (...more) => curry(fn)(...args, ...more);
export const curry = function (fn) {
return (...args) => {
if (args.length >= fn.length) {
return fn(...args);
}
} as typeof _curry;
export const isEmpty = (str: string) => str == null || str === '';
// @ts-ignore
return (...more) => curry(fn)(...args, ...more);
};
} as typeof _curry;
export const isEmpty = (str: string) => str == null || str === "";
export const tail = (str: string) => str.substring(1);
export const when = curry((predicate, whenTrueFn, arg) => {
return predicate(arg) ? whenTrueFn(arg) : arg;
}) as typeof _when;
return predicate(arg) ? whenTrueFn(arg) : arg;
}) as typeof _when;

View File

@@ -11,7 +11,7 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
@@ -25,7 +25,7 @@
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "NodeNext", /* Specify what module code is generated. */
"module": "NodeNext" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
@@ -49,13 +49,13 @@
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
"declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
"outDir": "./lib", /* Specify an output folder for all emitted files. */
"outDir": "./lib" /* Specify an output folder for all emitted files. */,
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
@@ -77,12 +77,12 @@
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
@@ -104,7 +104,7 @@
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"exclude": ["src/**/*.spec.ts", "lib"]
}

View File

@@ -1336,6 +1336,11 @@ postcss@^8.4.23:
picocolors "^1.0.0"
source-map-js "^1.0.2"
prettier@^2.8.8:
version "2.8.8"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
pretty-format@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"