From 4954e47f0e47d0899200124854f0be6b6ab635cc Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Sat, 16 May 2020 11:26:26 +0100 Subject: [PATCH] Better enforce symbol naming [fix] --- README.md | 4 ++++ lib/index.js | 12 +++++++++--- test/index.test.js | 18 +++++++++++++----- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 292734e..a22f6aa 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,10 @@ symbols.FOO // => Symbol(FOO) symbols.BAR // => Symbol(BAR) ``` +### Naming + +Names must only contain upper case letters (`A-Z`), digits (`0-9`), `_` or `$`. They must be valid JS identifiers (i.e. not start with a digit). + ### Symbol store You can cache all Symbols by passing a `store` option. `store` should be a plain object. diff --git a/lib/index.js b/lib/index.js index 1512df7..291996e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -6,10 +6,12 @@ 'use strict'; // Modules -const {isObject, isFullString, isArray} = require('is-it-type'); +const {isObject, isString, isFullString, isArray} = require('is-it-type'); // Exports +const NAME_REGEX = /^[A-Z_$][A-Z_$\d]*$/; + module.exports = function makeSymbols(namespace, names, options) { // Conform args if (isArray(namespace)) { @@ -26,8 +28,12 @@ module.exports = function makeSymbols(namespace, names, options) { // Validate names const namesSet = new Set(); for (const name of names) { - if (!isFullString(name)) throw new TypeError('names must be an array of strings'); - if (name.toUpperCase() !== name) throw new Error('symbol names must be all capitalized'); + if (!isString(name)) throw new TypeError('names must be an array of strings'); + if (!NAME_REGEX.test(name)) { + throw new Error( + `'${name}' is not a valid symbol name - must be in SNAKE_CASE and a valid JS identifier` + ); + } if (namesSet.has(name)) { throw new Error(`symbol names must be unique - '${name}' was duplicated`); } diff --git a/test/index.test.js b/test/index.test.js index d40ba6b..8c45830 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -95,13 +95,21 @@ describe('throws error if', () => { it('contains empty string', () => { expect(() => { makeSymbols('foo', ['BAR', '']); - }).toThrowWithMessage(TypeError, 'names must be an array of strings'); + }).toThrowWithMessage(Error, "'' is not a valid symbol name - must be in SNAKE_CASE and a valid JS identifier"); }); - it('contains a non-capitalized string', () => { - expect(() => { - makeSymbols('foo', ['BAR', 'Qux']); - }).toThrowWithMessage(Error, 'symbol names must be all capitalized'); + describe('contains invalid string', () => { + it.each([ + 'qux', + 'QUx', + 'Q.UX', + 'Q-UX', + '1QUX' + ])('%s', (name) => { + expect(() => { + makeSymbols('foo', ['BAR', name]); + }).toThrowWithMessage(Error, `'${name}' is not a valid symbol name - must be in SNAKE_CASE and a valid JS identifier`); + }); }); it('contains duplicates', () => {