Skip to content

Commit ffff530

Browse files
committed
feat(util): unassert
Signed-off-by: Lexus Drumgold <[email protected]>
1 parent 1fb494f commit ffff530

31 files changed

+738
-35
lines changed

.commitlintrc.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const config: UserConfig = {
2121
'scope-enum': [Severity.Error, 'always', scopes([
2222
'chore',
2323
'handlers',
24+
'util',
2425
'visitors'
2526
])]
2627
}

.dictionary.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@ shfmt
3232
unassert
3333
unstub
3434
vates
35+
vfile
3536
vitest
3637
yarnrc

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
**/node_modules/
1717
**/tsconfig*temp.json
1818
Brewfile
19+
__fixtures__/modules/*.cjs
1920
yarn.lock
2021

2122
# NEGATED PATTERNS

.eslintrc.cjs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,27 @@
1010
*/
1111
const config = {
1212
extends: ['./.eslintrc.base.cjs'],
13-
overrides: [...require('./.eslintrc.base.cjs').overrides],
13+
overrides: [
14+
...require('./.eslintrc.base.cjs').overrides,
15+
{
16+
files: ['__fixtures__/modules/*.mjs'],
17+
rules: {
18+
'@typescript-eslint/no-confusing-void-expression': 0,
19+
'@typescript-eslint/no-unsafe-argument': 0,
20+
'@typescript-eslint/no-unsafe-call': 0,
21+
'@typescript-eslint/no-unsafe-member-access': 0,
22+
'@typescript-eslint/no-unsafe-return': 0,
23+
'@typescript-eslint/require-await': 0,
24+
'@typescript-eslint/restrict-plus-operands': 0,
25+
'@typescript-eslint/restrict-template-expressions': 0,
26+
'@typescript-eslint/strict-boolean-expressions': 0,
27+
'jsdoc/require-file-overview': 0,
28+
'jsdoc/require-jsdoc': 0,
29+
'unicorn/prefer-math-trunc': 0,
30+
'unicorn/prefer-node-protocol': 0
31+
}
32+
}
33+
],
1434
root: true
1535
}
1636

.lintstagedrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
"src/**/*.ts": [
1010
"vitest run --changed --coverage",
1111
"yarn build",
12-
"bash -c tsc -p tsconfig.build.json"
12+
"bash -c tsc -p tsconfig.json"
1313
]
1414
}

__fixtures__/modules/add.mjs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { deprecate, equal, ok } from 'devlop'
2+
3+
function add(a, b) {
4+
ok(typeof a === 'number', 'expected `a` to be a number')
5+
ok(typeof b === 'number', 'expected `b` to be a number')
6+
7+
if (process.env.NODE_ENV !== 'production') {
8+
equal(Number.isNaN(a), false, 'expected `a` not to equal NaN')
9+
equal(Number.isNaN(b), false, 'expected `b` not to equal NaN')
10+
} else {
11+
ok(!Number.isNaN(a), 'expected `a` not to be NaN')
12+
ok(!Number.isNaN(b), 'expected `b` not to be NaN')
13+
}
14+
15+
return a + b
16+
}
17+
18+
export default deprecate(add)

__fixtures__/modules/assert.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function assert(value, message, ...params) {
2+
return void console.assert(value, message, ...params)
3+
}
4+
5+
export default assert
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import {
2+
DOT,
3+
at,
4+
define,
5+
set
6+
} from '@flex-development/tutils'
7+
import { ok, unreachable } from 'devlop'
8+
import { CONTINUE } from 'estree-util-visit'
9+
import { is } from 'unist-util-is'
10+
11+
function CallExpression(node, key, index) {
12+
if (
13+
(
14+
is(node.callee, 'Identifier') &&
15+
this.identifiers.has(node.callee.name)
16+
) ||
17+
(
18+
is(node.callee, 'MemberExpression') &&
19+
is(node.callee.object, 'Identifier') &&
20+
this.identifiers.has(node.callee.object.name)
21+
) ||
22+
(
23+
is(node.callee, 'MemberExpression') &&
24+
is(node.callee.object, 'Identifier') &&
25+
is(node.callee.property, 'Identifier') &&
26+
node.callee.object.name === 'console' &&
27+
node.callee.property.name === 'assert'
28+
)
29+
) {
30+
ok(this.parent, 'expected `parent`')
31+
ok(key, 'expected `key`')
32+
ok(key in this.parent, `expected \`parent.${key}\``)
33+
const zero = { raw: '0', type: 'Literal', value: 0 }
34+
const void0 = {
35+
argument: zero,
36+
operator: 'void',
37+
prefix: true,
38+
type: 'UnaryExpression'
39+
}
40+
switch (this.parent.type) {
41+
case 'ArrayExpression':
42+
case 'CallExpression':
43+
ok(typeof index === 'number', 'expected `index` to be a number')
44+
set(this.parent, key + DOT + index, void0)
45+
break
46+
case 'AssignmentExpression':
47+
if (is(this.grandparent, 'ExpressionStatement')) {
48+
this.trash.add(this.grandparent)
49+
} else {
50+
define(this.parent, key, { value: void0 })
51+
}
52+
break
53+
case 'ArrowFunctionExpression':
54+
case 'AssignmentPattern':
55+
case 'ConditionalExpression':
56+
case 'LogicalExpression':
57+
case 'Property':
58+
define(this.parent, key, { value: void0 })
59+
break
60+
case 'AwaitExpression':
61+
if (is(this.grandparent, 'ExpressionStatement')) {
62+
this.trash.add(this.grandparent)
63+
} else {
64+
define(this.parent, key, { value: void0 })
65+
}
66+
break
67+
case 'ExpressionStatement':
68+
this.trash.add(this.parent)
69+
break
70+
case 'ExportDefaultDeclaration':
71+
define(this.parent, key, { value: at(node.arguments, 0, void0) })
72+
break
73+
case 'ReturnStatement':
74+
case 'YieldExpression':
75+
define(this.parent, key, { value: null })
76+
break
77+
case 'UnaryExpression':
78+
if (is(this.grandparent, 'ExpressionStatement')) {
79+
this.trash.add(this.grandparent)
80+
} else {
81+
define(this.parent, key, {
82+
value: this.parent.operator === 'void' ? zero : void0
83+
})
84+
}
85+
break
86+
default:
87+
console.dir(this.parent, { depth: 10 })
88+
void unreachable(`unexpected parent: ${this.parent.type}`)
89+
}
90+
}
91+
return CONTINUE
92+
}
93+
94+
var call_expression_default = CallExpression
95+
export {
96+
call_expression_default as default
97+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const { ok } = await import('devlop')
2+
const assert = await import('node:assert/strict')
3+
4+
const centuryFromYear = year => {
5+
ok(typeof year === 'number', 'expected `year` to be a number')
6+
assert.notEqual(Number.isNaN(year), true, 'expected `year` not to be NaN')
7+
return Math.ceil(year / 100)
8+
}
9+
10+
export default centuryFromYear

__fixtures__/modules/digitize.mjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ok } from 'devlop'
2+
import * as assert from 'node:assert/strict'
3+
4+
function digitize(n) {
5+
ok(typeof n === 'number', 'expected `n` to be a number')
6+
7+
if (process.env.NODE_ENV !== 'production') {
8+
assert.notEqual(Number.isNaN(n), true, 'expected `n` not to be NaN')
9+
} else ok(n >= 0, 'expected `n` to be a non-negative number')
10+
11+
if (n <= 9) return [n]
12+
const digits = []
13+
while (n > 0) digits.push(n % 10 | 0) && (n = n / 10 | 0)
14+
return digits
15+
}
16+
17+
export default digitize

__fixtures__/modules/divide.cjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
'use strict'
2+
3+
let assert = require('assert'), bar = 'BAR', foo = 'FOO'
4+
5+
function divide(a, b) {
6+
assert.equal(typeof a, 'number')
7+
assert(!isNaN(a))
8+
assert.equal(typeof b, 'number')
9+
assert.ok(!isNaN(b))
10+
return a / b
11+
}
12+
13+
module.exports = module.exports.default = divide

__fixtures__/modules/gemoji-html.mjs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { ok } from 'devlop'
2+
import { nameToEmoji } from 'gemoji'
3+
import { codes } from 'micromark-util-symbol'
4+
function gemojiHtml() {
5+
return {
6+
enter: {
7+
gemoji() {
8+
return void this.tag('<span>')
9+
}
10+
},
11+
exit: {
12+
gemoji(token) {
13+
const val = this.sliceSerialize(token)
14+
ok(val.codePointAt(0) === codes.colon, 'expected `:` start')
15+
ok(val.codePointAt(val.length - 1) === codes.colon, 'expected `:` end')
16+
this.raw(nameToEmoji[val.slice(1, -1)] ?? val)
17+
return void this.tag('</span>')
18+
}
19+
}
20+
}
21+
}
22+
var html_default = gemojiHtml
23+
export {
24+
html_default as default
25+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { ok as assert } from 'devlop'
2+
import { asciiAlphanumeric } from 'micromark-util-character'
3+
import { codes } from 'micromark-util-symbol'
4+
function previous(code) {
5+
return code !== codes.backslash && code !== codes.colon
6+
}
7+
var shortcode_default = {
8+
name: 'gemoji',
9+
previous,
10+
tokenize(effects, ok, nok) {
11+
function inside(code) {
12+
switch (true) {
13+
case code === codes.colon:
14+
effects.consume(code)
15+
effects.exit('gemoji')
16+
return ok
17+
case asciiAlphanumeric(code):
18+
case code === codes.dash:
19+
case code === codes.plusSign:
20+
case code === codes.underscore:
21+
effects.consume(code)
22+
return inside
23+
default:
24+
return nok(code)
25+
}
26+
}
27+
function begin(code) {
28+
switch (code) {
29+
case codes.eof:
30+
case codes.colon:
31+
return nok(code)
32+
default:
33+
effects.consume(code)
34+
return inside
35+
}
36+
}
37+
const start = code => {
38+
assert(code === codes.colon, 'expected `:`')
39+
assert(previous.call(this, this.previous), 'expected correct previous')
40+
effects.enter('gemoji')
41+
effects.consume(code)
42+
return begin
43+
}
44+
return start
45+
}
46+
}
47+
export {
48+
shortcode_default as default
49+
}

__fixtures__/modules/http-assert.cjs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
'use strict'
2+
3+
const assert = require('http-assert')
4+
const { ok, equal: eq, deepEqual: deq } = require('node:assert')
5+
6+
module.exports = module.exports.default = function(username, check) {
7+
try {
8+
assert(username == check, 401, 'authentication failed')
9+
} catch (err) {
10+
eq(err.status, 401)
11+
deq(err.message, 'authentication failed')
12+
ok(err.expose)
13+
}
14+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ok } from 'devlop'
2+
import * as assert from 'node:assert/strict'
3+
4+
async function humanReadable(seconds) {
5+
ok(typeof seconds === 'number', 'expected `seconds` to be a number')
6+
await assert.doesNotReject(async () => seconds.toFixed(2))
7+
8+
return new Promise(resolve => {
9+
let formatted = ''
10+
11+
for (const converter of [3600, 60, 1]) {
12+
const time = seconds / converter | 0
13+
formatted += time < 10 ? `0${time}` : time
14+
if (converter !== 1) formatted += ':'
15+
seconds -= time * converter
16+
}
17+
18+
return resolve(formatted)
19+
})
20+
}
21+
22+
export default humanReadable

__fixtures__/modules/multiply.cjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
'use strict'
2+
3+
const { strict: assert } = require('assert')
4+
5+
const multiply = function(a, b) {
6+
console.assert(typeof a === 'number')
7+
assert(!isNaN(a))
8+
assert.equal(typeof b, 'number')
9+
assert.ok(!isNaN(b))
10+
return a * b
11+
}
12+
13+
module.exports = module.exports.default = multiply

__fixtures__/modules/noop.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { ok } from 'devlop'
2+
3+
export default () => ok(true)

__fixtures__/modules/subtract.mjs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as assert from 'node:assert'
2+
3+
function subtract(a, b) {
4+
assert.ok(typeof a === 'number', 'expected a to be a number')
5+
assert.ok(typeof b === 'number', 'expected b to be a number')
6+
return a - b
7+
}
8+
9+
export default subtract

0 commit comments

Comments
 (0)