Skip to content

Commit 5510d35

Browse files
committed
First commit
0 parents  commit 5510d35

18 files changed

+355
-0
lines changed

Diff for: .eslintrc.json

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"env": {
3+
"node": true,
4+
"es6": true
5+
},
6+
"extends": [
7+
"eslint:recommended",
8+
"plugin:@typescript-eslint/eslint-recommended",
9+
"plugin:@typescript-eslint/recommended",
10+
"prettier"
11+
],
12+
"plugins": ["import", "prettier"],
13+
"parserOptions": {
14+
"project": "./tsconfig.eslint.json"
15+
},
16+
"rules": {
17+
"prettier/prettier": "error",
18+
"import/order": [
19+
"error",
20+
{
21+
"groups": ["type", "builtin", ["sibling", "parent"], "index", "object"],
22+
"newlines-between": "never",
23+
"alphabetize": {
24+
"order": "asc",
25+
"caseInsensitive": true
26+
}
27+
}
28+
],
29+
"@typescript-eslint/consistent-type-imports": [
30+
"error",
31+
{
32+
"prefer": "type-imports"
33+
}
34+
],
35+
"@typescript-eslint/no-explicit-any": "off"
36+
}
37+
}

Diff for: .github/dependabot.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "npm"
4+
directory: "/"
5+
schedule:
6+
interval: "daily"

Diff for: .github/workflows/coverage.yml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: coverage
2+
on: [push, pull_request]
3+
jobs:
4+
coveralls:
5+
runs-on: ubuntu-latest
6+
steps:
7+
- uses: actions/checkout@v1
8+
- uses: actions/setup-node@v1
9+
with:
10+
node-version: 18
11+
- name: npm install
12+
run: npm i
13+
- name: npm run build
14+
run: npm run build
15+
- name: npm run coverage:ci
16+
run: npm run coverage:ci
17+
- name: coveralls
18+
uses: coverallsapp/github-action@master
19+
with:
20+
github-token: ${{ secrets.GITHUB_TOKEN }}

Diff for: .github/workflows/lint.yml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: lint
2+
on: [push, pull_request]
3+
jobs:
4+
eslint:
5+
runs-on: ubuntu-latest
6+
steps:
7+
- uses: actions/checkout@v1
8+
- uses: actions/setup-node@v1
9+
with:
10+
node-version: 18
11+
- name: npm install
12+
run: npm i
13+
- name: npm run build
14+
run: npm run build
15+
- name: npm run lint
16+
run: npm run lint

Diff for: .github/workflows/test.yml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: test
2+
on: [push, pull_request]
3+
jobs:
4+
test:
5+
name: Node ${{ matrix.node-version }} and ${{ matrix.os }}
6+
runs-on: ${{ matrix.os }}
7+
strategy:
8+
fail-fast: false
9+
matrix:
10+
node-version: [16.x, 17.x, 18.x]
11+
os: [ubuntu-latest, windows-latest, macos-latest]
12+
steps:
13+
- uses: actions/checkout@v1
14+
- name: Use Node ${{ matrix.node-version }}
15+
uses: actions/setup-node@v1
16+
with:
17+
node-version: ${{ matrix.node-version }}
18+
- name: npm install
19+
run: npm i
20+
- name: npm run build
21+
run: npm run build
22+
- name: npm test
23+
run: npm test

Diff for: .gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules
2+
package-lock.json
3+
coverage
4+
.nyc_output
5+
/lib
6+
*.tsbuildinfo

Diff for: .npmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false

Diff for: .prettierrc.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"arrowParens": "avoid",
3+
"bracketSpacing": false,
4+
"singleQuote": true,
5+
"printWidth": 120,
6+
"trailingComma": "none"
7+
}

Diff for: AUTHORS

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Authors ordered by first contribution:
2+
3+
Sebastian Riedel <[email protected]>

Diff for: CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
# Changelog
3+
4+
## v1.0.0 (2021-06-21)
5+
6+
First major release. This package strictly follows [Semantic Versioning](https://semver.org).

Diff for: LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2021 Sebastian Riedel
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be
12+
included in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Diff for: README.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<p align="center">
2+
<a href="https://mojojs.org">
3+
<picture>
4+
<source srcset="https://github.com/mojolicious/mojo.js/blob/main/docs/images/logo-dark.png?raw=true" media="(prefers-color-scheme: dark)">
5+
<img src="https://github.com/mojolicious/mojo.js/blob/main/docs/images/logo.png?raw=true" style="margin: 0 auto;">
6+
</picture>
7+
</a>
8+
</p>
9+
10+
[![](https://github.com/mojolicious/util.js/workflows/test/badge.svg)](https://github.com/mojolicious/util.js/actions)
11+
[![Coverage Status](https://coveralls.io/repos/github/mojolicious/util.js/badge.svg?branch=main)](https://coveralls.io/github/mojolicious/util.js?branch=main)
12+
[![npm](https://img.shields.io/npm/v/@mojojs/util.svg)](https://www.npmjs.com/package/@mojojs/util)
13+
14+
Just a bunsch of utility functions shared by mojo.js packages.
15+
16+
## Installation
17+
18+
All you need is Node.js 16.0.0 (or newer).
19+
20+
```
21+
$ npm install @mojojs/util
22+
```

Diff for: package.json

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"name": "@mojojs/util",
3+
"version": "0.0.1",
4+
"description": "Utilities for mojo.js packages",
5+
"author": "Sebastian Riedel <[email protected]>",
6+
"license": "MIT",
7+
"repository": {
8+
"type": "git",
9+
"url": "git+https://github.com/mojolicious/util.js.git"
10+
},
11+
"bugs": {
12+
"url": "https://github.com/mojolicious/util.js/issues"
13+
},
14+
"homepage": "https://mojojs.org",
15+
"scripts": {
16+
"build": "npx tsc --build ./",
17+
"build:clean": "npm run clean && npm run build",
18+
"build:coverage": "npm run build && npm run coverage",
19+
"build:lint": "npm run build && npm run lint",
20+
"build:test": "npm run build && npm test",
21+
"build:watch": "npm run build -- --watch",
22+
"clean": "rm -rf tsconfig.tsbuildinfo lib",
23+
"coverage": "c8 tap --no-coverage test/*.js",
24+
"coverage:ci": "c8 --reporter lcovonly tap --no-coverage test/*.js",
25+
"lint": "eslint \"test/*.js\" \"src/**/*.ts\" \"src/*.ts\"",
26+
"lint:fix": "npm run lint -- --fix",
27+
"prepublishOnly": "npm run build",
28+
"publish:minor": "npm version minor && npm publish",
29+
"publish:patch": "npm version patch && npm publish",
30+
"test": "tap --no-coverage test/*.js"
31+
},
32+
"exports": "./lib/util.js",
33+
"types": "./lib/util.d.ts",
34+
"type": "module",
35+
"files": [
36+
"lib/"
37+
],
38+
"devDependencies": {
39+
"@types/node": "^17.0.0",
40+
"@types/tap": "^15.0.3",
41+
"@typescript-eslint/eslint-plugin": "^5.1.0",
42+
"c8": "^7.11.3",
43+
"eslint": "^8.1.0",
44+
"eslint-config-prettier": "^8.3.0",
45+
"eslint-plugin-import": "^2.23.4",
46+
"eslint-plugin-node": "^11.1.0",
47+
"eslint-plugin-prettier": "^4.0.0",
48+
"prettier": "^2.3.2",
49+
"tap": "^16.0.0",
50+
"typescript": "^4.3.2"
51+
},
52+
"engines": {
53+
"node": ">= 16"
54+
}
55+
}

Diff for: src/util.ts

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
const XML_ESCAPE: Record<string, string> = {
2+
'&': '&amp;',
3+
'<': '&lt;',
4+
'>': '&gt;',
5+
'"': '&quot;',
6+
"'": '&#39;'
7+
};
8+
9+
const XML_UNESCAPE: Record<string, string> = {
10+
amp: '&',
11+
lt: '<',
12+
gt: '>',
13+
quot: '"',
14+
apos: "'",
15+
'#39': "'"
16+
};
17+
18+
export class SafeString extends String {}
19+
20+
export function cssUnescape(value: string): string {
21+
return value.replaceAll('\\n', '').replace(/\\([0-9a-fA-F]{1,6})\s?/g, cssUnescapeReplace);
22+
}
23+
24+
function cssUnescapeReplace(value: string): string {
25+
return String.fromCharCode(parseInt(value.replaceAll('\\', ''), 16));
26+
}
27+
28+
export function escapeRegExp(string: string) {
29+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
30+
}
31+
32+
export function stickyMatch(
33+
stringWithOffset: {offset: number; value: string},
34+
stickyRegex: RegExp
35+
): RegExpMatchArray | null {
36+
stickyRegex.lastIndex = stringWithOffset.offset;
37+
const match = stickyRegex.exec(stringWithOffset.value);
38+
if (match !== null) stringWithOffset.offset = stickyRegex.lastIndex;
39+
return match;
40+
}
41+
42+
export function xmlEscape(value: string | SafeString): string {
43+
if (value instanceof SafeString) return value.toString();
44+
if (typeof value !== 'string') value = `${value}`;
45+
return ('' + value).replace(/[&<>'"]/g, xmlEscapeReplace);
46+
}
47+
function xmlEscapeReplace(char: string): string {
48+
return XML_ESCAPE[char];
49+
}
50+
51+
export function xmlUnescape(value: string): string {
52+
return value.replace(/&(amp|lt|gt|quot|apos|#39);/g, xmlUnescapeReplace);
53+
}
54+
55+
function xmlUnescapeReplace(value: string, entity: string): string {
56+
return XML_UNESCAPE[entity];
57+
}

Diff for: test/util.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import {cssUnescape, escapeRegExp, SafeString, stickyMatch, xmlEscape, xmlUnescape} from '../lib/util.js';
2+
import t from 'tap';
3+
4+
t.test('Util', t => {
5+
t.test('cssUnescape', t => {
6+
t.equal(cssUnescape('#\\n\\002603x'), '#☃x');
7+
t.end();
8+
});
9+
10+
t.test('escapeRegExp', t => {
11+
t.equal(escapeRegExp('te*s?t'), 'te\\*s\\?t');
12+
t.equal(escapeRegExp('\\^$.*+?()[]{}|'), '\\\\\\^\\$\\.\\*\\+\\?\\(\\)\\[\\]\\{\\}\\|');
13+
t.end();
14+
});
15+
16+
t.test('stickyMatch', t => {
17+
const regex = /\s*(test\d)/y;
18+
const results = [];
19+
const sticky = {offset: 0, value: 'test1 test2 test3 test4'};
20+
while (sticky.value.length > sticky.offset) {
21+
const match = stickyMatch(sticky, regex);
22+
if (match === null) break;
23+
results.push(match[1]);
24+
}
25+
t.same(results, ['test1', 'test2', 'test3', 'test4']);
26+
t.end();
27+
});
28+
29+
t.test('xmlEscape', t => {
30+
t.same(xmlEscape('Hello World!'), 'Hello World!');
31+
t.same(xmlEscape('привет<foo>'), 'привет&lt;foo&gt;');
32+
t.same(xmlEscape('la<f>\nbar"baz"\'yada\n\'&lt;la'), 'la&lt;f&gt;\nbar&quot;baz&quot;&#39;yada\n&#39;&amp;lt;la');
33+
t.same(xmlEscape('<p>'), '&lt;p&gt;');
34+
t.same(xmlEscape(new SafeString('<p>')), '<p>');
35+
t.same(xmlEscape(undefined), 'undefined');
36+
t.same(xmlEscape(null), 'null');
37+
t.end();
38+
});
39+
40+
t.test('xmlUnescape', t => {
41+
t.same(xmlUnescape('Hello World!'), 'Hello World!');
42+
t.same(xmlUnescape('привет&lt;foo&gt;'), 'привет<foo>');
43+
t.same(xmlUnescape('la&lt;f&gt;\nbar&quot;baz&quot;&#39;yada\n&#39;&amp;lt;la'), 'la<f>\nbar"baz"\'yada\n\'&lt;la');
44+
t.same(xmlUnescape('&lt;p&gt;&apos;'), "<p>'");
45+
t.end();
46+
});
47+
48+
t.end();
49+
});

Diff for: tsconfig.base.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"compilerOptions": {
3+
"lib": ["ESNext", "DOM"],
4+
"target": "ES2020",
5+
"module": "ES2020",
6+
"sourceMap": true,
7+
"declaration": true,
8+
"incremental": true,
9+
"moduleResolution": "node",
10+
"esModuleInterop": true,
11+
"noErrorTruncation": true,
12+
"strict": true
13+
}
14+
}

Diff for: tsconfig.eslint.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"extends": "./tsconfig.base.json",
3+
"include": ["src/**/*", "test/**/*"]
4+
}

Diff for: tsconfig.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "./tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "lib",
5+
"rootDir": "src",
6+
"composite": true
7+
},
8+
"include": ["src/**/*"]
9+
}

0 commit comments

Comments
 (0)