Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/commands/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* @module commands
*/
import { ArrayExt } from '@lumino/algorithm';
import { hasTopLevelComma } from '@lumino/coreutils';

import {
JSONExt,
Expand Down Expand Up @@ -1687,7 +1688,7 @@ namespace Private {
function validateSelector(
options: CommandRegistry.IKeyBindingOptions
): string {
if (options.selector.indexOf(',') !== -1) {
if (hasTopLevelComma(options.selector)) {
throw new Error(`Selector cannot contain commas: ${options.selector}`);
}
if (!Selector.isValid(options.selector)) {
Expand Down
1 change: 1 addition & 0 deletions packages/coreutils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
export * from './index.common';
export * from './random.browser';
export * from './uuid.browser';
export * from './selector'
22 changes: 22 additions & 0 deletions packages/coreutils/src/selector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) Jupyter Development Team.
* Distributed under the terms of the Modified BSD License.
*/

/**
* Remove :is() and :where() functional pseudo-classes so that
* commas inside them do not count as top-level selector separators.
*/
export function stripIsWhere(selector: string): string {
return selector.replace(
/:(is|where)\(([^()]|\([^()]*\))*\)/g,
''
);
}

/**
* Returns true if the selector contains a top-level comma.
*/
export function hasTopLevelComma(selector: string): boolean {
return stripIsWhere(selector).indexOf(',') !== -1;
}
25 changes: 25 additions & 0 deletions packages/coreutils/tests/src/selector.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) Jupyter Development Team.
* Distributed under the terms of the Modified BSD License.
*/

import { hasTopLevelComma } from '@lumino/coreutils/src/selector';
import { expect } from 'chai';

describe('selector validation', () => {
it('allows commas inside :is()', () => {
expect(hasTopLevelComma('.a:is(.b,.c)')).to.equal(false);
});

it('allows commas inside :where()', () => {
expect(hasTopLevelComma('.a:where(.b,.c)')).to.equal(false);
});

it('rejects top-level commas', () => {
expect(hasTopLevelComma('.a, .b')).to.equal(true);
});

it('rejects mixed selectors', () => {
expect(hasTopLevelComma('.a:is(.b,.c), .d')).to.equal(true);
});
});
5 changes: 4 additions & 1 deletion packages/widgets/src/contextmenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import { ArrayExt } from '@lumino/algorithm';

import { CommandRegistry } from '@lumino/commands';

import { hasTopLevelComma } from '@lumino/coreutils';


import { DisposableDelegate, IDisposable } from '@lumino/disposable';

import { Selector } from '@lumino/domutils';
Expand Down Expand Up @@ -328,7 +331,7 @@ namespace Private {
* invalid or contains commas.
*/
function validateSelector(selector: string): string {
if (selector.indexOf(',') !== -1) {
if (hasTopLevelComma(selector)) {
throw new Error(`Selector cannot contain commas: ${selector}`);
}
if (!Selector.isValid(selector)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/widgets/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outDir": "lib",
"rootDir": "src"
},
"include": ["src/*"],
"include": ["src/*" ],
"references": [
{
"path": "../algorithm"
Expand Down
Loading