diff --git a/package.json b/package.json index 32733a4..624faf8 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "dev": "npm run dev -w @penpot-export/cli", "build": "npm run build -w @penpot-export/core -w @penpot-export/cli", + "test": "npm run test --workspaces --if-present", "demo": "npm run generate-css -w demo" } } diff --git a/packages/core/package.json b/packages/core/package.json index 828f1ef..caf1446 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -9,6 +9,8 @@ ], "scripts": { "build": "tsc", + "pretest": "npm run build", + "test": "node --test", "format": "prettier -w ." }, "dependencies": { diff --git a/packages/core/src/lib/css/helpers.test.ts b/packages/core/src/lib/css/helpers.test.ts new file mode 100644 index 0000000..5b4f739 --- /dev/null +++ b/packages/core/src/lib/css/helpers.test.ts @@ -0,0 +1,47 @@ +import assert from 'node:assert' +import { describe, it } from 'node:test' + +import { textToCssIdentToken } from './helpers' + +describe('CSS helpers', () => { + describe('Transforming text to CSS ident tokens', () => { + describe('when input text includes ASCII printable characters', () => { + it('escapes all ASCII printable characters except ident code points (-, 0-9, A-Z, _, a-z)', () => { + const allAsciiPrintableCharacters = + '!"#$%&' + + "'" + + '()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[' + + '\\' + + ']^_`abcdefghijklmnopqrtuvwxyz{|}~' + + const expect = + '\\!\\"\\#\\$\\%\\&' + + "\\'" + + '\\(\\)\\*\\+\\,-\\.\\/0123456789\\:\\;\\<\\=\\>\\?\\@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\[' + + '\\\\' + + '\\]\\^_\\`abcdefghijklmnopqrtuvwxyz\\{\\|\\}\\~' + + assert.ok(/^[\x20-\x7E]*$/.test(allAsciiPrintableCharacters)) + assert.equal(textToCssIdentToken(allAsciiPrintableCharacters), expect) + }) + }) + + describe('when input text does NOT start with a ident-start code point', () => { + it('escapes starting number', () => { + const expect = '\\0123456789' + + assert.equal(textToCssIdentToken('0123456789'), expect) + }) + }) + + describe('when input text starts with a hyphen', () => { + describe('when the following character is NOT an ident-start code point', () => { + it('escapes first number following a hyphen', () => { + const expect = '-\\0123456789' + + assert.equal(textToCssIdentToken('-0123456789'), expect) + }) + }) + }) + }) +}) diff --git a/packages/core/src/lib/css/helpers.ts b/packages/core/src/lib/css/helpers.ts index 8475b3f..9435adf 100644 --- a/packages/core/src/lib/css/helpers.ts +++ b/packages/core/src/lib/css/helpers.ts @@ -23,7 +23,7 @@ function escapeCssCharacter(char: string) { * letter: An uppercase letter or a lowercase letter. * non-ASCII code point: A code point with a value equal to or greater than U+0080 . */ -function textToCssIdentToken(str: string) { +export function textToCssIdentToken(str: string) { const normalizedString = str.trim().replace(/\s/g, '_') const escapedString = normalizedString