npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@yomua/y-screw

v0.1.3

Published

为 JavaScript 提供额外的功能

Downloads

17

Readme

描述

提供轻便好用的 JavaScript 功能的库.

环境

除了依赖浏览器环境的包, 其余都是浏览器或 node 环境下都可使用.

依赖浏览器环境 API

  • urlChange

node + browser 环境

addBigNumbers

import assert from '@yomua/y-assert'
import { addBigNumbers } from '@yomua/y-screw'

const { expect } = assert

const v1 = '11111111111.11111111111111111111111111111111111111111111111'
const v2 = '22222222222.33333333333333333333333333333333333333333333333'
const v3 = '33333333333.44444444444444444444444444444444444444444444444'

expect(addBigNumbers(v1).add(v2).get()).equal(v3)
expect(addBigNumbers('123').get()).equal('123')

debounce

import { debounce } from '@yomua/y-screw'

// 延迟 0ms, 若当前使用 debounce 的上下文被刷新, 则会生成新的计时器
// => 在 React 组件中使用 debounce, 若当前组件刷新, 则会执行 2 次回调函数.
debounce(() => {}, 0, { isRefreshItself: false })

// 延迟 1000ms, 若当前使用 debounce 的上下文被刷新, 则不会生成新的计时器
// => 在 React 组件中使用 debounce, 若当前组件刷新, 则只会执行 1 次回调函数.
// => 即: debounce 生成的 timer, 将拥有自己的上下文
debounce(() => {}, 1000, { isRefreshItself: true })

getType

import assert from '@yomua/y-assert'
import { getType } from '@yomua/y-screw'

const { expect } = assert

expect(getType([])).equal('array')
expect(getType({})).equal('object')

expect(getType(1)).equal('number')
expect(getType('yomua')).equal('string')
expect(getType(true)).equal('boolean')
expect(getType(Symbol(1))).equal('symbol')
expect(getType(null)).equal('null')
expect(getType(undefined)).equal('undefined')
expect(getType(BigInt(1))).equal('bigInt')

expect(getType(function () {})).equal('function')

isEmptyObject

会校验对象中是否存在 Symbol 值.

import assert from '@yomua/y-assert'
import { isEmptyObject } from '@yomua/y-screw'

const { expect } = assert

expect(isEmptyObject({})).equal(true)
expect(isEmptyObject({ a: 1 })).equal(false)
expect(
  isEmptyObject({
    [Symbol(1)]: 1,
  }),
).equal(false)

isNil

import assert from '@yomua/y-assert'
import { isNil } from '@yomua/y-screw'

const { expect } = assert

expect(isNil(null)).equal(true)
expect(isNil(undefined)).equal(true)
expect(isNil({})).equal(false)

isType

import assert from '@yomua/y-assert'
import { isType } from '@yomua/y-screw'

const { expect } = assert

// 在 ts 中, 可以传入指定的类型, 从而约束传入数据的类型.
expect(isType<any[]>([], 'array')).equal(true)
expect(isType<object>({}, 'object')).equal(true)

expect(isType(1, 'number')).equal(true)
expect(isType('yomua', 'string')).equal(true)
expect(isType(true, 'boolean')).equal(true)
expect(isType(Symbol(1), 'symbol')).equal(true)
expect(isType(null, 'null')).equal(true)
expect(isType(undefined, 'undefined')).equal(true)
expect(isType(BigInt(1), 'bigInt')).equal(true)

expect(isType(function () {}, 'function')).equal(true)

limitPromise

对一次性发送的请求次数进行限制.

术语称之为请求并发的限制.

简单来说: 当你限制一次性只能发送 2 个请求时, 若此时有 5 个请求要被发送, 则会先取前 2 个, 后 3 个则是放入一个数组进行等待, 当前面请求完成时, 再从数组中取出新请求, 再发送; 如此往复, 直到所有请求完成.

TIP: limitPromise 并不保证请求的顺序性, 即: 不保证先发出的请求先完成, 这取决于请求处理时间.

import { limitPromise } from '@yomua/y-screw'

const limit = limitPromise(2)

function job(name) {
  console.log(`started: ${name}`)

  return new Promise((resolve, reject) => {
    // 当作异步任务
    setTimeout(
      () => {
        console.log(`    finished: ${name}`)
        resolve(name)
      },
      Math.floor(Math.random() * 1000),
    )
  })
}

for (let i = 0; i <= 4; i++) {
  limit(() => job(i))
}

// 输出
// started: 0
// started: 1
//   finished: 0
// started: 2
//  finished: 2
// started: 3
//  finished: 3
// started: 4
//  finished: 1
//  finished: 4

memoizeFn

import assert from '@yomua/y-assert'
import { memoizeFn } from '@yomua/y-screw'

const { expect } = assert

let i = 0
let j = 0

function increasing1() {
  return ++i // 先自增再作为值返回;
}

function increasing2() {
  return ++j // 先自增再作为值返回;
}

// memoizeFn 返回的函数指向的是你传进来的函数 increasing1
const memo1 = memoizeFn(increasing1, { resolver: '123' })
const memo2 = memoizeFn(increasing1, { resolver: '456' })

// 只对函数进行缓存, 不会对值进行缓存; 若想要对值进行缓存, Refer: memoizeFnValue
expect(memo1(1, 2, 3)).equal(1)
expect(memo1(1, 2, 3)).equal(2)

// 即使 key 不一样, 但是由于 memo 的是同一个函数, memoizeFn 返回函数就是这同一个函数, 所以返回 true
expect(memo1).equal(memo2)

/**
 * 由于 cache 是声明在全局内存中, 所以调用 memoizeFn 时, cache 都指向同一个
 * 所以若有相同的 key, 则后面出现的一样的 key 将会被忽略
 * 所以 memoizeFn 返回的函数将指向 cache.get(resolver) => 这里就是 increasing1
 */
const memo3 = memoizeFn(increasing2, { resolver: '123' })
const memo4 = memoizeFn(increasing2, { resolver: '456' })

// memo3, memo4 是 increasing1, 不是 increasing2
// 所以不是使用 j 进行计算
expect(memo3()).equal(3)
expect(memo4()).equal(4)

// 相同而 key, 只会记录第一个出现的 key
expect(memo3).equal(memo1)
expect(memo4).equal(memo2)
// 不指定 key, 自动使用 hashString 进行计算,
// 这会使得缓存不同函数时, 后面出现的函数不会被忽略, 将会单独保存
// 但是相同函数, 得到的 hash key 仍然是一样的
let y = 0
function increasing3() {
  return ++y
}
const memo5 = memoizeFn(increasing3)
const memo6 = memoizeFn(increasing3)
expect(memo5()).equal(1)
expect(memo6()).equal(2)

let z = 0
function increasing4() {
  return ++z
}
// 这里和 memo5, memo6 一样没有使用 key, 但是新函数会被单独缓存
// 因为 key 不同, 由  memoizeFn 自动计算
const memo7 = memoizeFn(increasing4)
const memo8 = memoizeFn(increasing4)
expect(memo7()).equal(1)
expect(memo8()).equal(2)

memoizeFnValue

import assert from '@yomua/y-assert'
import { memoizeFnValue } from '@yomua/y-screw'

const { expect } = assert

let i = 0

function increasing() {
  i += 1

  return i
}

const increasing1 = memoizeFnValue(increasing)

// 连续调用 3 次, 仍然和第一次计算的值
expect(increasing1()).equal(1)
expect(increasing1()).equal(1)
expect(increasing1()).equal(1)

// 具有有效期, 且为 0s
const increasing2 = memoizeFnValue(increasing, { maxAge: 0 })
expect(increasing2()).equal(2)
expect(increasing2()).equal(3)
expect(increasing2()).equal(4)

// 具有有效期, 且为 1s;
// 注意: 这是持续性的缓存, 即: 每 maxAge 秒后, 都会重新计算值, 并缓存 maxAge 秒, 直到过期, 如此反复
;(async function () {
  const increasing3 = memoizeFnValue(increasing, { maxAge: 1 })
  expect(increasing3()).equal(5) // 得到新值后, 缓存函数值
  expect(increasing3()).equal(5) // 使用缓存值

  await new Promise((resolve) => {
    return setTimeout(() => {
      // 1秒后缓存到期, 重新计算函数值并缓存, 这里新值为: 6
      // TIP: 当缓存到期, 得到新值后, 又会重新以当前时间戳 + maxAge 计算缓存时间.
      expect(increasing3()).equal(6)
      resolve()
    }, 1000)
  })

  expect(increasing3()).equal(6) // 使用新缓存值: 6

  await new Promise((resolve) => {
    return setTimeout(() => {
      // 1秒后缓存又到期, 又重新计算函数值并缓存, 这里新值为: 7
      expect(increasing3()).equal(7)
      resolve()
    }, 1000)
  })

  expect(increasing3()).equal(7) // 在没有过期之前, 这里将一直会使用缓存值: 7
})()

throttle

import { throttle } from '@yomua/y-screw'

throttle(() => {
  console.log('throttled')
}, 1000)

toJSON

和 JSON.stringify 类似, 但是特殊处理以下值:

  • 防止循环引用, 若循环引用, 则对循环引用值返回 Circular

  • null 视为 null

  • undefined 视为 null

  • function, symbol, bigInt: 做 toString() 处理

  • Date: 做 toISOString() 处理

  • 在对象, 数组中, 含以上值, 也对其做以上处理.

其他未特殊处理的值都和 JSON.stringify() 保持一致

示例

以下示例的 equal(value) 就是最终 toJSON(data) 得到的数据

import assert from '@yomua/y-assert'
import { toJSON } from '@yomua/y-screw'
const { expect } = assert
// 原始值测试
expect(toJSON(1)).equal('1')
expect(toJSON('1')).equal('"1"')

expect(toJSON([1])).equal('[1]')
expect(toJSON(['1'])).equal('["1"]')

expect(toJSON({ a: 1 })).equal('{"a":1}')
expect(toJSON({ a: '1' })).equal('{"a":"1"}')
// Symbol, BigInt (也是原始值, 不过在这里将它们独立书写, 以便阅读)
const symbol1 = Symbol(1)
expect(toJSON(symbol1)).equal('Symbol(1)')
expect(toJSON([symbol1])).equal('["Symbol(1)"]')
expect(toJSON({ [symbol1]: '1' })).equal('{"Symbol(1)":"1"}')
expect(toJSON(BigInt(1111111111111111))).equal('1111111111111111n')
expect(toJSON([BigInt(1111111111111111)])).equal('["1111111111111111n"]')
expect(toJSON({ bigInt: BigInt(1111111111111111) })).equal(
  '{"bigInt":"1111111111111111n"}',
)
// NaN
expect(toJSON(NaN)).equal('null')
expect(toJSON([NaN])).equal('[null]')
expect(toJSON({ name: NaN })).equal('{"name":null}')
// undefined (所有 undefined, 最后都会被转为 null 显示)
expect(toJSON()).equal(null)
expect(toJSON(undefined)).equal(null)
expect(toJSON([undefined])).equal('[null]')
expect(toJSON({ name: undefined })).equal('{"name":null}')
expect(toJSON([[undefined]])).equal('[[null]]')
expect(toJSON([{ name: undefined }])).equal('[{"name":null}]')
// null
expect(toJSON(null)).equal(null)
expect(toJSON([null])).equal('[null]')
expect(toJSON({ name: null })).equal('{"name":null}')
expect(toJSON({ obj: { name: null } })).equal('{"obj":{"name":null}}')
// 日期
const date = new Date()
expect(toJSON(date)).equal(date.toISOString())
expect(toJSON([date])).equal(`["${date.toISOString()}"]`)
expect(toJSON({ date })).equal(`{"date":"${date.toISOString()}"}`)
// 函数
expect(toJSON(function () {})).equal('function () {}')
expect(toJSON([function () {}])).equal('["function () {}"]')
expect(toJSON({ func: function () {} })).equal('{"func":"function () {}"}')
expect(toJSON([{ func: function () {} }])).equal('[{"func":"function () {}"}]')
// 数组
expect(toJSON([1, 2, 3])).equal(JSON.stringify([1, 2, 3]))
expect(toJSON([null])).equal(JSON.stringify([null]))
expect(toJSON([undefined])).equal(JSON.stringify([undefined]))
expect(toJSON([null, undefined])).equal(JSON.stringify([null, undefined]))
expect(toJSON([[1, 2, 3]])).equal(JSON.stringify([[1, 2, 3]]))
expect(toJSON([{ name: 'yomua' }])).equal(JSON.stringify([{ name: 'yomua' }]))
expect(toJSON([{ obj: { name: 'yomua' } }])).equal(
  JSON.stringify([{ obj: { name: 'yomua' } }]),
)
// 对象
expect(toJSON({ name: 'yomua' })).equal(JSON.stringify({ name: 'yomua' }))
expect(toJSON({ obj: { age: '18' } })).equal(
  JSON.stringify({ obj: { age: '18' } }),
)
expect(toJSON({ arr: ['yomua'] })).equal(JSON.stringify({ arr: ['yomua'] }))
expect(toJSON({ arr: [{ name: 'yomua' }] })).equal(
  JSON.stringify({ arr: [{ name: 'yomua' }] }),
)
// 循环引用数组
const arrCircular = ['yomua']
arrCircular.push(arrCircular)
expect(toJSON(arrCircular)).equal('["yomua","[Circular]"]')

// 对象自身循环引用
const objCircular = { name: 'yomua' }
objCircular.data = objCircular
expect(toJSON({ objCircular })).equal(
  '{"objCircular":{"name":"yomua","data":"[Circular]"}}',
)

// 两个对象相互引用
const obj1 = { name: 'obj1' }
const obj2 = { name: 'obj2' }
obj1.obj2 = obj2
obj2.obj1 = obj1
expect(toJSON(obj1)).equal(
  '{"name":"obj1","obj2":{"name":"obj2","obj1":"[Circular]"}}',
)
expect(toJSON(obj2)).equal(
  '{"name":"obj2","obj1":{"name":"obj1","obj2":"[Circular]"}}',
)

// 对象和数组的相互引用
const obj3 = { name: 'obj3' }
const arr3 = [obj3]
obj3.arr3 = arr3
expect(toJSON(obj3)).equal('{"name":"obj3","arr3":["[Circular]"]}')
expect(toJSON(arr3)).equal('[{"name":"obj3","arr3":"[Circular]"}]')
// 各种值混合测试
const date2 = new Date()
const symbol2 = Symbol(1)
const obj = {
  name: 'yomua',
}
const arr = [
  1,
  '2',
  'true',
  true,
  'null',
  'undefined',
  null, // null
  undefined, // null
  NaN, // nul
  symbol2, // 保留 symbol 值:  Symbol(1)
  BigInt(1),
  '2n',
  function () {},
  { name: 'yomua', value1: null, value2: undefined },
  [1, 2, 3, { name: 'yomua' }],
  date2,
  obj, // 循环引用
]
obj.arr = arr // 循环引用

expect(toJSON(arr)).equal(
  `[1,"2","true",true,"null","undefined",null,null,null,"Symbol(1)","1n","2n","function () {}",{"name":"yomua","value1":null,"value2":null},[1,2,3,{"name":"yomua"}],"${date2.toISOString()}",{"name":"yomua","arr":"[Circular]"}]`,
)
expect(toJSON(obj)).equal(
  `{"name":"yomua","arr":[1,"2","true",true,"null","undefined",null,null,null,"Symbol(1)","1n","2n","function () {}",{"name":"yomua","value1":null,"value2":null},[1,2,3,{"name":"yomua"}],"${date2.toISOString()}","[Circular]"]}`,
)

toParse

专用来解析使用 toJSON 生成的 JSON 字符串

特殊处理以下值 (非对象字符串和数组字符串中的值):

  • 'null': 还原为 null

  • 'undefined': 还原为 null

  • 'NaN': 还原为 null

  • function, Symbol 字符串: 不做任何处理

    'function () {}' => 'function () {}'

    'Symbol(1)' => 'Symbol(1)'

  • BigInt 字符串: 还原为 BigInt 类型值. 如: '1111n' => 1111n

  • Date 字符串: 还原为对象. 如: '2020-01-01T00:00:00.000Z' => new Date('2020-01-01T00:00:00.000Z')

对字符串数组 '[...]' 和对象数组 '{...}', 单独使用另一套进行递归解析, 规则如下:

  • 将对象字符串和数组字符串中的 Circular 的值还原为 null

    因为只有对象和数组中, 才会存在循环引用

  • 其他格式值不做任何处理

其他未特殊处理的值都和 JSON.parse() 保持一致, 包括对象字符串和数组字符串中的其他未特殊处理的值.

示例

此示例和 toJson() 示例一一对应, 直接 toParse 解析 toJson 的示例

equal(value) 就是最终 toParse(data) 得到的数据

import assert from '@yomua/y-assert'
import { toJSON, toParse } from '#test/index.mjs'
const { expect } = assert
// 原始值测试
expect(toParse(toJSON(1))).equal(1)
expect(toParse(toJSON('1'))).equal('1')

expect(toParse(toJSON([1]))).equal([1])
expect(toParse(toJSON(['1']))).equal(['1'])

expect(toParse(toJSON({ a: 1 }))).equal({ a: 1 })
expect(toParse(toJSON({ a: '1' }))).equal({ a: '1' })
// Symbol, BigInt (也是原始值, 不过在这里将它们独立书写, 以便阅读)
const symbol1 = Symbol(1)
expect(toParse(toJSON(symbol1))).equal('Symbol(1)')
expect(toParse(toJSON([symbol1]))).equal(['Symbol(1)'])
expect(toParse(toJSON({ [symbol1]: '1' }))).equal({ 'Symbol(1)': '1' })
expect(toParse(toJSON(BigInt(1111111111111111)))).equal(1111111111111111n)
expect(toParse(toJSON([BigInt(1111111111111111)]))).equal(['1111111111111111n'])
expect(toParse(toJSON({ bigInt: BigInt(1111111111111111) }))).equal({
  bigInt: '1111111111111111n',
})
// NaN
expect(toParse(toJSON(NaN))).equal(null)
expect(toParse(toJSON([NaN]))).equal([null])
expect(toParse(toJSON({ name: NaN }))).equal({ name: null })
// undefined (所有 undefined, 最后都会被转为 null 显示)
expect(toParse(toJSON(undefined))).equal(null)
expect(toParse(toJSON())).equal(null)
expect(toParse(toJSON({ name: undefined }))).equal({ name: null })
expect(toParse(toJSON([undefined]))).equal([null])
expect(toParse(toJSON([[undefined]]))).equal([[null]])
expect(toParse(toJSON([{ name: undefined }]))).equal([{ name: null }])
// null
expect(toParse(toJSON(null))).equal(null)
expect(toParse(toJSON([null]))).equal([null])
expect(toParse(toJSON({ name: null }))).equal({ name: null })
expect(toParse(toJSON({ obj: { name: null } }))).equal({ obj: { name: null } })
// 日期
const date = new Date()
expect(toParse(toJSON(date))?.getTime?.()).equal(date?.getTime())
expect(toParse(toJSON([date]))).equal([date.toISOString()])
expect(toParse(toJSON({ date }))).equal({ date: date.toISOString() })
// 函数
expect(toParse(toJSON(function () {}))).equal('function () {}')
expect(toParse(toJSON([function () {}]))).equal(['function () {}'])
expect(toParse(toJSON({ func: function () {} }))).equal({
  func: 'function () {}',
})
expect(toParse(toJSON([{ func: function () {} }]))).equal([
  { func: 'function () {}' },
])
// 数组
expect(toParse(toJSON([1, 2, 3]))).equal(JSON.parse(JSON.stringify([1, 2, 3])))
expect(toParse(toJSON([null]))).equal(JSON.parse(JSON.stringify([null])))
expect(toParse(toJSON([undefined]))).equal(
  JSON.parse(JSON.stringify([undefined])),
)
expect(toParse(toJSON([null, undefined]))).equal(
  JSON.parse(JSON.stringify([null, undefined])),
)
expect(toParse(toJSON([[1, 2, 3]]))).equal(
  JSON.parse(JSON.stringify([[1, 2, 3]])),
)
expect(toParse(toJSON([{ name: 'yomua' }]))).equal(
  JSON.parse(JSON.stringify([{ name: 'yomua' }])),
)
expect(toParse(toJSON([{ obj: { name: 'yomua' } }]))).equal(
  JSON.parse(JSON.stringify([{ obj: { name: 'yomua' } }])),
)
// 对象
expect(toParse(toJSON({ name: 'yomua' }))).equal(
  JSON.parse(JSON.stringify({ name: 'yomua' })),
)
expect(toParse(toJSON({ obj: { age: '18' } }))).equal(
  JSON.parse(JSON.stringify({ obj: { age: '18' } })),
)
expect(toParse(toJSON({ arr: ['yomua'] }))).equal(
  JSON.parse(JSON.stringify({ arr: ['yomua'] })),
)
expect(toParse(toJSON({ arr: [{ name: 'yomua' }] }))).equal(
  JSON.parse(JSON.stringify({ arr: [{ name: 'yomua' }] })),
)
// 对象自身循环引用
const objCircular = { name: 'yomua' }
objCircular.data = objCircular
expect(toParse(toJSON({ objCircular }))).equal({
  objCircular: { name: 'yomua', data: null },
})

// 两个对象相互引用
const obj1 = { name: 'obj1' }
const obj2 = { name: 'obj2' }
obj1.obj2 = obj2
obj2.obj1 = obj1
expect(toParse(toJSON(obj1))).equal({
  name: 'obj1',
  obj2: { name: 'obj2', obj1: null },
})
expect(toParse(toJSON(obj2))).equal({
  name: 'obj2',
  obj1: { name: 'obj1', obj2: null },
})

// 对象和数组的相互引用
const obj3 = { name: 'obj3' }
const arr3 = [obj3]
obj3.arr3 = arr3
expect(toParse(toJSON(obj3))).equal({ name: 'obj3', arr3: [null] })
expect(toParse(toJSON(arr3))).equal([{ name: 'obj3', arr3: null }])
// 各种值混合测试
const symbol2 = Symbol(1)
const date2 = new Date()
const obj = {
  name: 'yomua',
}
const arr = [
  1,
  '2',
  'true',
  true,
  'null',
  'undefined',
  null, // null
  undefined, // null
  NaN, // nul
  symbol2, // 保留 symbol 值:  Symbol(1)
  BigInt(1),
  '2n',
  function () {},
  { name: 'yomua', value1: null, value2: undefined },
  [1, 2, 3, { name: 'yomua' }],
  date2,
  obj, // 循环引用
]
obj.arr = arr // 循环引用

expect(toParse(toJSON(arr))).equal([
  1,
  '2',
  'true',
  true,
  'null',
  'undefined',
  null,
  null,
  null,
  'Symbol(1)',
  '1n',
  '2n',
  'function () {}',
  { name: 'yomua', value1: null, value2: null },
  [1, 2, 3, { name: 'yomua' }],
  date2.toISOString(),
  { name: 'yomua', arr: null },
])
expect(toParse(toJSON(obj))).equal({
  name: 'yomua',
  arr: [
    1,
    '2',
    'true',
    true,
    'null',
    'undefined',
    null,
    null,
    null,
    'Symbol(1)',
    '1n',
    '2n',
    'function () {}',
    { name: 'yomua', value1: null, value2: null },
    [1, 2, 3, { name: 'yomua' }],
    date2.toISOString(),
    null,
  ],
})

conditionalChain

类似三元表达式, 但对多条件判断时, 语义更清晰

  • 支持链式调用

  • 对每个 cond(condition)r(result) 实行位置上的一对一匹配

import assert from '@yomua/y-assert'
import { conditionalChain } from '@yomua/y-screw'
const { expect } = assert

// 对字符串进行判断
expect(conditionalChain().cond('a').cond('b').cond('c').get()).equal(undefined)
expect(conditionalChain().cond('a').r('r1').get()).equal('r1')

// 对布尔值进行判断
expect(conditionalChain().cond(false).cond(true).r('r1').r('r2').get()).equal(
  'r2',
)

// 对表达式进行判断
expect(
  conditionalChain()
    .cond(1 === 0)
    .r('r1')
    .cond(1 === 1)
    .r('r2')
    .get(),
).equal('r2')

// 对函数表达式进行判断
expect(
  conditionalChain()
    .cond(() => true)
    .r('r1')
    .cond(() => false)
    .r('r2')
    .get(),
).equal('r1')

// 使用默认值
expect(
  conditionalChain()
    .default('default1')
    .cond(false)
    .default('default2')
    .r('r1')
    .get(),
).equal('default2')

expect(conditionalChain().cond(true).get()).equal(undefined)

// 条件全为 true, 则返回第一个 true 对应的值
expect(conditionalChain().cond(true).r('r1').cond(true).r('r2').get()).equal(
  'r1',
)

hashString

import assert from '@yomua/y-assert'
import { hashString } from '@yomua/y-screw'

const { expect } = assert
;(async function () {
  // 将一个字符串转为 hash 值
  // 支持各种环境: node, browser(新版浏览器), browser(旧版浏览器)
  const value = await hashString('yomua')

  expect(value).equal(
    'e80789d2f56d544c268e51bccb69ae9d0650f77b4646467fc9ea51c3874ebec6',
  )

  expect(value).typeOf('string')
})

browser 环境

urlChange

import { toJSON } from '@yomua/y-screw'

// 更改浏览器 url
urlChange(window.location.origin + '/yomua')

// 修改 url 时是否直接跳转过去
urlChange(window.location.origin + '/yomua', {
  go: true,
})
// 携带 state
window.addEventListener('popstate', (event) => {
  console.log(event.state) // {name: 'yhw'}
})

// 当使用者监听 popstate 时,要传给 event.state 的数据
// TIP: 仅当 go: true 时才有用.
urlChange(window.location.origin + '/yomua', {
  state: { name: 'ywh' },
  go: true,
})