Skip to content

Commit

Permalink
feat: Add unique symbols
Browse files Browse the repository at this point in the history
  • Loading branch information
eemeli committed May 6, 2023
1 parent 95d653c commit 8d14368
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 13 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ const re = parse('!re /fo./g', { customTags: [regexp] })
- `regexp` (`!re`) - [RegExp] values,
using their default `/foo/flags` string representation.
- `sharedSymbol` (`!symbol/shared`) - [Shared Symbols], i.e. ones created with `Symbol.for()`
- `symbol` (`!symbol`) - [Unique Symbols]

[RegExp]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions
[Shared Symbols]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#shared_symbols_in_the_global_symbol_registry
[Unique Symbols]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

## Customising Tag Names

Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { regexp } from './regexp.js'
export { sharedSymbol } from './symbol.js'
export { sharedSymbol, symbol } from './symbol.js'
48 changes: 38 additions & 10 deletions src/symbol.test.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,56 @@
import { test } from 'tap'
import { parse, stringify } from 'yaml'
import { Document, type Scalar, parse, stringify } from 'yaml'

import { sharedSymbol } from '.'
import { sharedSymbol, symbol } from '.'

test('parse', t => {
test('parse shared', t => {
const res: symbol = parse(`!symbol/shared foo`, {
customTags: [sharedSymbol]
customTags: [sharedSymbol, symbol]
})
t.type(res, 'symbol')
t.same(Symbol.keyFor(res), 'foo')
t.end()
})

test('stringify shared', t => {
const res = stringify(Symbol.for('some\nsymbol'), {
customTags: [sharedSymbol]
const doc = new Document<Scalar, false>(Symbol.for('some\nsymbol'), {
customTags: [sharedSymbol, symbol]
})
t.equal(res, '!symbol/shared |-\nsome\nsymbol\n')
t.end()
})
t.equal(doc.toString(), '!symbol/shared |-\nsome\nsymbol\n')

doc.contents.value = Symbol('foo')
t.throws(() => doc.toString(), { name: 'TypeError' })

doc.contents.value = 42
t.throws(() => doc.toString(), { name: 'TypeError' })

test('stringify private', t => {
t.throws(() =>
stringify(Symbol('some\nsymbol'), { customTags: [sharedSymbol] })
)

t.end()
})

test('parse private', t => {
const res: symbol = parse(`!symbol foo`, {
customTags: [sharedSymbol, symbol]
})
t.type(res, 'symbol')
t.notOk(Symbol.keyFor(res))
t.end()
})

test('stringify private', t => {
const doc = new Document<Scalar, false>(Symbol('some\nsymbol'), {
customTags: [sharedSymbol, symbol]
})
t.equal(doc.toString(), '!symbol |-\nsome\nsymbol\n')

doc.contents.value = Symbol.for('foo')
t.equal(doc.toString(), '!symbol foo\n')

doc.contents.value = 'foo'
t.throws(() => doc.toString(), { name: 'TypeError' })

t.end()
})
20 changes: 18 additions & 2 deletions src/symbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,28 @@ import type { Scalar, ScalarTag } from 'yaml'
import { StringifyContext, stringifyString } from 'yaml/util'

export const sharedSymbol = {
identify: value => value?.constructor === Symbol,
identify: value =>
value?.constructor === Symbol && typeof Symbol.keyFor(value) === 'string',
tag: '!symbol/shared',
resolve: str => Symbol.for(str),
stringify(item: Scalar, ctx: StringifyContext, onComment, onChompKeep) {
const key = Symbol.keyFor(item.value as symbol)
if (key === undefined) throw new Error('Only shared symbols are supported')
if (key === undefined) {
throw new TypeError('Only shared symbols are supported')
}
return stringifyString({ value: key }, ctx, onComment, onChompKeep)
}
} satisfies ScalarTag

export const symbol = {
identify: value =>
value?.constructor === Symbol && Symbol.keyFor(value) === undefined,
tag: '!symbol',
resolve: str => Symbol(str),
stringify(item: Scalar, ctx: StringifyContext, onComment, onChompKeep) {
const sym = item.value
if (typeof sym !== 'symbol') throw new TypeError(`${sym} is not a symbol`)
const value = String(sym).replace(/^Symbol\(|\)$/g, '')
return stringifyString({ value }, ctx, onComment, onChompKeep)
}
} satisfies ScalarTag

0 comments on commit 8d14368

Please sign in to comment.