feat(filter): add isExcluded helper with unit tests
Glob-based entity_id matcher used by the upcoming exclude-filter feature. Single wildcard `*` (matches any sequence including dots), all other characters matched literally with regex metacharacters escaped. Case-sensitive, anchored. Empty pattern array always returns false, so the helper is a no-op when the adapter is not configured to filter anything. New mocha unit-test suite invoked via `npm run test:unit` (separate from the existing js-controller-backed test:integration).
This commit is contained in:
@@ -50,6 +50,7 @@
|
||||
"scripts": {
|
||||
"test:integration": "mocha --exit",
|
||||
"test:package": "mocha test/testPackageFiles.js --exit",
|
||||
"test:unit": "mocha test/testEntityFilter.js --exit",
|
||||
"test": "npm run test:integration",
|
||||
"build:tsc": "tsc -p tsconfig.build.json",
|
||||
"build": "npm run build:tsc",
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Returns true if entityId matches any of the supplied glob patterns.
|
||||
* Glob syntax: `*` is the only wildcard and matches any sequence of characters
|
||||
* (including dots). All other characters are matched literally (regex
|
||||
* metacharacters are escaped). Matching is case-sensitive and anchored to
|
||||
* the full entity_id.
|
||||
*
|
||||
* An empty patterns array always returns false.
|
||||
*/
|
||||
export function isExcluded(entityId: string, patterns: string[]): boolean {
|
||||
if (!patterns || patterns.length === 0) {
|
||||
return false;
|
||||
}
|
||||
for (const pattern of patterns) {
|
||||
if (globToRegex(pattern).test(entityId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function globToRegex(pattern: string): RegExp {
|
||||
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
|
||||
return new RegExp(`^${escaped}$`);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
const { expect } = require('chai');
|
||||
const { isExcluded } = require('../build/lib/entityFilter');
|
||||
|
||||
describe('entityFilter.isExcluded', () => {
|
||||
it('returns false for an empty pattern list', () => {
|
||||
expect(isExcluded('switch.iob_anything', [])).to.equal(false);
|
||||
});
|
||||
|
||||
it('matches a simple glob with leading wildcard', () => {
|
||||
expect(isExcluded('switch.iob_shelly_xyz', ['*.iob_*'])).to.equal(true);
|
||||
});
|
||||
|
||||
it('matches the bridge mirror naming pattern', () => {
|
||||
expect(isExcluded('light.iob_ha_eg_wz1__e_licht_decke', ['*.iob_*__*'])).to.equal(true);
|
||||
});
|
||||
|
||||
it('handles entities that miss a required literal segment', () => {
|
||||
// *.iob_*__* requires the literal `__` segment — entities without it do not match
|
||||
expect(isExcluded('switch.iob_', ['*.iob_*__*'])).to.equal(false);
|
||||
expect(isExcluded('switch.iob_foo', ['*.iob_*__*'])).to.equal(false);
|
||||
// Naming-Convention safety: similarly named entities without `__` are safe
|
||||
expect(isExcluded('sensor.scheune_temperatur', ['*.sc_*__*'])).to.equal(false);
|
||||
});
|
||||
|
||||
it('matches multiple patterns (OR semantic)', () => {
|
||||
const patterns = ['*.iob_*__*', '*.knx_*', '*.ha_*__*'];
|
||||
expect(isExcluded('switch.knx_foo', patterns)).to.equal(true);
|
||||
expect(isExcluded('switch.ha_eg_wz1__e_licht_decke', patterns)).to.equal(true);
|
||||
expect(isExcluded('switch.something_else', patterns)).to.equal(false);
|
||||
});
|
||||
|
||||
it('is case sensitive', () => {
|
||||
expect(isExcluded('switch.IOB_foo', ['*.iob_*'])).to.equal(false);
|
||||
expect(isExcluded('switch.iob_foo', ['*.IOB_*'])).to.equal(false);
|
||||
});
|
||||
|
||||
it('treats * as matching any characters including dots', () => {
|
||||
// We use full entity_id including the leading domain, so this is fine.
|
||||
expect(isExcluded('switch.iob_foo', ['*foo*'])).to.equal(true);
|
||||
});
|
||||
|
||||
it('escapes regex metacharacters in patterns', () => {
|
||||
// `.` in pattern matches literal `.`, not "any char"
|
||||
expect(isExcluded('switch.iob_foo', ['switch.iob_foo'])).to.equal(true);
|
||||
expect(isExcluded('switchXiob_foo', ['switch.iob_foo'])).to.equal(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user