Skip to content

Commit 7f94253

Browse files
Copilotjoelmartinez
andcommitted
Address code review comments: fix require path, improve documentation, extract common regex pattern
Co-authored-by: joelmartinez <90380+joelmartinez@users.noreply.github.com>
1 parent aee4a12 commit 7f94253

2 files changed

Lines changed: 16 additions & 8 deletions

File tree

examples/advanced.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const foresta = require('../dist/foresta');
1+
const foresta = require('../src/foresta');
22
const esprima = require('esprima');
33

44
console.log('=== Advanced Foresta.js Selector Examples ===\n');

src/foresta.js

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,12 @@ function foresta(query) {
192192
// Parse attribute selector: [property operator value]
193193
// Operators: =, ^=, $=, *=, ~= (regex)
194194
var match;
195+
var PROPERTY_PATTERN = '([a-zA-Z._]+)'; // Matches property names including dot notation
195196

196197
// Regex pattern: [property~/pattern/]
197-
if ((match = attrStr.match(/^([a-zA-Z._]+)~\/(.+)\/$/))) {
198+
// Note: User-provided regex patterns are executed as-is. In a production environment,
199+
// consider adding validation or timeout mechanisms to prevent ReDoS attacks.
200+
if ((match = attrStr.match(new RegExp('^' + PROPERTY_PATTERN + '~\\/(.+)\\/$')))) {
198201
return {
199202
property: match[1],
200203
operator: '~=',
@@ -203,7 +206,7 @@ function foresta(query) {
203206
}
204207

205208
// Starts with: [property^="value"]
206-
if ((match = attrStr.match(/^([a-zA-Z._]+)\^=["']?([^"']*)["']?$/))) {
209+
if ((match = attrStr.match(new RegExp('^' + PROPERTY_PATTERN + '\\^=["\']{0,1}([^"\']*)["\']{0,1}$')))) {
207210
return {
208211
property: match[1],
209212
operator: '^=',
@@ -212,7 +215,7 @@ function foresta(query) {
212215
}
213216

214217
// Ends with: [property$="value"]
215-
if ((match = attrStr.match(/^([a-zA-Z._]+)\$=["']?([^"']*)["']?$/))) {
218+
if ((match = attrStr.match(new RegExp('^' + PROPERTY_PATTERN + '\\$=["\']{0,1}([^"\']*)["\']{0,1}$')))) {
216219
return {
217220
property: match[1],
218221
operator: '$=',
@@ -221,7 +224,7 @@ function foresta(query) {
221224
}
222225

223226
// Contains: [property*="value"]
224-
if ((match = attrStr.match(/^([a-zA-Z._]+)\*=["']?([^"']*)["']?$/))) {
227+
if ((match = attrStr.match(new RegExp('^' + PROPERTY_PATTERN + '\\*=["\']{0,1}([^"\']*)["\']{0,1}$')))) {
225228
return {
226229
property: match[1],
227230
operator: '*=',
@@ -230,7 +233,7 @@ function foresta(query) {
230233
}
231234

232235
// Exact match: [property=value] or [property="value"]
233-
if ((match = attrStr.match(/^([a-zA-Z._]+)=(.+)$/))) {
236+
if ((match = attrStr.match(new RegExp('^' + PROPERTY_PATTERN + '=(.+)$')))) {
234237
var value = match[2];
235238
// Remove quotes if present
236239
if ((value.startsWith('"') && value.endsWith('"')) ||
@@ -605,8 +608,13 @@ function foresta(query) {
605608

606609
switch (prevCombinator) {
607610
case ' ':
608-
// Space in legacy mode: consecutive parent (not descendant!)
609-
// For backward compatibility with original implementation
611+
// IMPORTANT: Space combinator behavior differs from CSS!
612+
// In CSS: space means "descendant at any level"
613+
// In Foresta: space means "consecutive parent chain"
614+
// Example: "Program VariableDeclaration VariableDeclarator" requires:
615+
// - VariableDeclarator whose parent is VariableDeclaration
616+
// - whose parent is Program
617+
// This matches the original Foresta.js behavior for backward compatibility
610618
currentExpression = currentExpression.parent;
611619
break;
612620
case '>':

0 commit comments

Comments
 (0)