From fbcfff53b64c99e5365667d25e2588d19c73d209 Mon Sep 17 00:00:00 2001 From: Ido Rosenthal Date: Tue, 19 Sep 2023 13:01:10 +0300 Subject: [PATCH] feat: validate custom state selector --- packages/core/src/helpers/custom-state.ts | 16 +++++- .../test/features/css-pseudo-class.spec.ts | 50 ++++++++++++++++--- packages/schema-extract/test/test.spec.ts | 2 +- 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/packages/core/src/helpers/custom-state.ts b/packages/core/src/helpers/custom-state.ts index f365c6b590..e166de8773 100644 --- a/packages/core/src/helpers/custom-state.ts +++ b/packages/core/src/helpers/custom-state.ts @@ -338,7 +338,21 @@ function defineTemplateState( const template = stripQuotation(postcssValueParser.stringify(templateDef)); if (argsFullValue.length === 1) { // simple template with no params - mappedStates[stateName] = template.trim().replace(/\\["']/g, '"'); + const selectorStr = template.trim().replace(/\\["']/g, '"'); + const selectorAst = parseSelectorWithCache(selectorStr, { clone: true }); + if ( + !validateTemplateSelector({ + stateName, + selectorStr, + selectorAst, + cssNode: decl, + diagnostics, + }) + ) { + return; + } else { + mappedStates[stateName] = selectorStr; + } } else if (argsFullValue.length === 2) { // single parameter template if (!template.includes('$0')) { diff --git a/packages/core/test/features/css-pseudo-class.spec.ts b/packages/core/test/features/css-pseudo-class.spec.ts index 299335807a..a57ab0e63b 100644 --- a/packages/core/test/features/css-pseudo-class.spec.ts +++ b/packages/core/test/features/css-pseudo-class.spec.ts @@ -459,6 +459,50 @@ describe('features/css-pseudo-class', () => { .root:static(unknown-param) {} `); }); + it('should report invalid template selector', () => { + testStylableCore(` + .a { + /* + @analyze-error(not-compound) ${stCustomStateDiagnostics.UNSUPPORTED_COMPLEX_SELECTOR( + 'notCompound', + '.x .y' + )} + */ + -st-states: notCompound(".x .y"); + } + .b { + /* + @analyze-error(multi) ${stCustomStateDiagnostics.UNSUPPORTED_MULTI_SELECTOR( + 'multi', + '.x, .y' + )} + */ + -st-states: multi(".x, .y"); + } + .c { + /* + @analyze-error(invalid) ${stCustomStateDiagnostics.INVALID_SELECTOR( + 'invalid', + ':unclosed(' + )} + */ + -st-states: invalid(":unclosed("); + } + .d { + /* + @analyze-error(invalidStart) ${stCustomStateDiagnostics.UNSUPPORTED_INITIAL_SELECTOR( + 'invalidStartElement', + 'div.x' + )} + @analyze-error(invalidStart) ${stCustomStateDiagnostics.UNSUPPORTED_INITIAL_SELECTOR( + 'invalidStartWildcard', + '*.x' + )} + */ + -st-states: invalidStartElement("div.x"), invalidStartWildcard("*.x"); + } + `); + }); }); describe('custom mapped parameter', () => { it('should transform mapped state (quoted)', () => { @@ -517,12 +561,6 @@ describe('features/css-pseudo-class', () => { shouldReportNoDiagnostics(meta); }); it('should report invalid template selector', () => { - /** - * currently only checks template with parameter - * for backwards compatibility standalone template can accept - * any kind of selector - we might want to limit this in a future - * major version. - */ testStylableCore(` .root { -st-states: classAndThenParam(".x$0", string), diff --git a/packages/schema-extract/test/test.spec.ts b/packages/schema-extract/test/test.spec.ts index 53479fe96a..949f646a05 100644 --- a/packages/schema-extract/test/test.spec.ts +++ b/packages/schema-extract/test/test.spec.ts @@ -259,7 +259,7 @@ describe('Stylable JSON Schema Extractor', () => { it('schema with mapped states', () => { const css = `.root{ - -st-states: state("custom"); + -st-states: state(".custom"); }`; const res = extractSchema(css, '/entry.st.css', '/', path);