Skip to content

Commit

Permalink
Merge pull request #1 from eemeli/unique-symbols
Browse files Browse the repository at this point in the history
Add unique symbols
  • Loading branch information
eemeli authored May 9, 2023
2 parents a8ed06f + 8d14368 commit ba21d2c
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 13 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ const re = parse('!re /fo./g', { customTags: [regexp] })

- `regexp` (`!re`) - [RegExp] values,
using their default `/foo/flags` string representation.
- `symbol` (`!symbol`) - [Shared Symbols], i.e. ones created with `Symbol.for()`
- `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 { symbol } from './symbol.js'
export { sharedSymbol, symbol } from './symbol.js'
48 changes: 41 additions & 7 deletions src/symbol.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,56 @@
import { test } from 'tap'
import { parse, stringify } from 'yaml'
import { Document, type Scalar, parse, stringify } from 'yaml'

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

test('parse', t => {
const res: symbol = parse(`!symbol foo`, { customTags: [symbol] })
test('parse shared', t => {
const res: symbol = parse(`!symbol/shared foo`, {
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: [symbol] })
t.equal(res, '!symbol |-\nsome\nsymbol\n')
const doc = new Document<Scalar, false>(Symbol.for('some\nsymbol'), {
customTags: [sharedSymbol, symbol]
})
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' })

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 => {
t.throws(() => stringify(Symbol('some\nsymbol'), { customTags: [symbol] }))
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()
})
24 changes: 20 additions & 4 deletions src/symbol.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
import type { Scalar, ScalarTag } from 'yaml'
import { StringifyContext, stringifyString } from 'yaml/util'

export const symbol = {
identify: value => value?.constructor === Symbol,
tag: '!symbol',
export const sharedSymbol = {
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 ba21d2c

Please sign in to comment.