@jsenv/core 40.0.5 → 40.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/js/build.js CHANGED
@@ -1859,11 +1859,10 @@ const jsenvPluginSubbuilds = (
1859
1859
  },
1860
1860
  fetchUrlContent: async (urlInfo) => {
1861
1861
  if (!entryPointBuildUrlSet.has(urlInfo.url)) {
1862
- return null;
1862
+ return;
1863
1863
  }
1864
1864
  await buildPromise;
1865
1865
  urlInfo.typeHint = "asset"; // this ensure the rest of jsenv do not scan or modify the content of this file
1866
- return null;
1867
1866
  },
1868
1867
  };
1869
1868
  });
@@ -54,6 +54,13 @@ const applyPattern = ({ url, pattern }) => {
54
54
  };
55
55
  };
56
56
 
57
+ /**
58
+ * Core pattern matching function that processes patterns against strings
59
+ * @param {string} pattern - The pattern with special syntax (*,**,/) to match against
60
+ * @param {string} string - The string to test against the pattern
61
+ * @returns {Object} Result containing match status and capture groups
62
+ * @private
63
+ */
57
64
  const applyMatching = (pattern, string) => {
58
65
  const groups = [];
59
66
  let patternIndex = 0;
@@ -78,22 +85,6 @@ const applyMatching = (pattern, string) => {
78
85
  return consumeString(remainingString.length);
79
86
  };
80
87
 
81
- let matched;
82
- const iterate = () => {
83
- const patternIndexBefore = patternIndex;
84
- const indexBefore = index;
85
- matched = matchOne();
86
- if (matched === undefined) {
87
- consumePattern(1);
88
- consumeString(1);
89
- iterate();
90
- return;
91
- }
92
- if (matched === false && restoreIndexes) {
93
- patternIndex = patternIndexBefore;
94
- index = indexBefore;
95
- }
96
- };
97
88
  const matchOne = () => {
98
89
  // pattern consumed
99
90
  if (remainingPattern === "") {
@@ -103,12 +94,11 @@ const applyMatching = (pattern, string) => {
103
94
  if (remainingString[0] === "?") {
104
95
  // match search params
105
96
  consumeRemainingString();
106
-
107
97
  return true;
108
98
  }
109
- // if remainingString
110
99
  return false; // fails because string longer than expect
111
100
  }
101
+
112
102
  // -- from this point pattern is not consumed --
113
103
  // string consumed, pattern not consumed
114
104
  if (remainingString === "") {
@@ -122,6 +112,7 @@ const applyMatching = (pattern, string) => {
122
112
  }
123
113
  return false; // fail because string shorter than expect
124
114
  }
115
+
125
116
  // -- from this point pattern and string are not consumed --
126
117
  // fast path trailing slash
127
118
  if (remainingPattern === "/") {
@@ -133,25 +124,30 @@ const applyMatching = (pattern, string) => {
133
124
  }
134
125
  return false;
135
126
  }
127
+
136
128
  // fast path trailing '**'
137
129
  if (remainingPattern === "**") {
138
130
  consumePattern(2);
139
131
  consumeRemainingString();
140
132
  return true;
141
133
  }
134
+
142
135
  if (remainingPattern.slice(0, 4) === "/**/") {
143
136
  consumePattern(3); // consumes "/**/"
144
- const skipResult = skipUntilMatch({
137
+ const skipResult = skipUntilMatchIterative({
145
138
  pattern: remainingPattern,
146
139
  string: remainingString,
147
140
  canSkipSlash: true,
148
141
  });
149
- groups.push(...skipResult.groups);
142
+ for (let i = 0; i < skipResult.groups.length; i++) {
143
+ groups.push(skipResult.groups[i]);
144
+ }
150
145
  consumePattern(skipResult.patternIndex);
151
146
  consumeRemainingString();
152
147
  restoreIndexes = false;
153
148
  return skipResult.matched;
154
149
  }
150
+
155
151
  // pattern leading **
156
152
  if (remainingPattern.slice(0, 2) === "**") {
157
153
  consumePattern(2); // consumes "**"
@@ -161,7 +157,7 @@ const applyMatching = (pattern, string) => {
161
157
  // when remainingPattern was preceeded by "**/"
162
158
  // and remainingString have no "/"
163
159
  // then skip is not allowed, a regular match will be performed
164
- if (!remainingString.includes("/")) {
160
+ if (remainingString.includes("/")) {
165
161
  skipAllowed = false;
166
162
  }
167
163
  }
@@ -171,18 +167,21 @@ const applyMatching = (pattern, string) => {
171
167
  return true;
172
168
  }
173
169
  if (skipAllowed) {
174
- const skipResult = skipUntilMatch({
170
+ const skipResult = skipUntilMatchIterative({
175
171
  pattern: remainingPattern,
176
172
  string: remainingString,
177
173
  canSkipSlash: true,
178
174
  });
179
- groups.push(...skipResult.groups);
175
+ for (let i = 0; i < skipResult.groups.length; i++) {
176
+ groups.push(skipResult.groups[i]);
177
+ }
180
178
  consumePattern(skipResult.patternIndex);
181
179
  consumeRemainingString();
182
180
  restoreIndexes = false;
183
181
  return skipResult.matched;
184
182
  }
185
183
  }
184
+
186
185
  if (remainingPattern[0] === "*") {
187
186
  consumePattern(1); // consumes "*"
188
187
  if (remainingPattern === "") {
@@ -202,23 +201,53 @@ const applyMatching = (pattern, string) => {
202
201
  patternIndex = patternIndex - 1;
203
202
  return false;
204
203
  }
205
- const skipResult = skipUntilMatch({
204
+ const skipResult = skipUntilMatchIterative({
206
205
  pattern: remainingPattern,
207
206
  string: remainingString,
208
207
  canSkipSlash: false,
209
208
  });
210
- groups.push(skipResult.group, ...skipResult.groups);
209
+ groups.push(skipResult.group);
210
+ for (let i = 0; i < skipResult.groups.length; i++) {
211
+ groups.push(skipResult.groups[i]);
212
+ }
211
213
  consumePattern(skipResult.patternIndex);
212
214
  consumeString(skipResult.index);
213
215
  restoreIndexes = false;
214
216
  return skipResult.matched;
215
217
  }
218
+
216
219
  if (remainingPattern[0] !== remainingString[0]) {
217
220
  return false;
218
221
  }
222
+
219
223
  return undefined;
220
224
  };
221
- iterate();
225
+
226
+ // Replace recursive iterate() with iterative approach
227
+ let matched;
228
+ let continueIteration = true;
229
+
230
+ while (continueIteration) {
231
+ const patternIndexBefore = patternIndex;
232
+ const indexBefore = index;
233
+
234
+ matched = matchOne();
235
+
236
+ if (matched === undefined) {
237
+ consumePattern(1);
238
+ consumeString(1);
239
+ // Continue the loop instead of recursion
240
+ continue;
241
+ }
242
+
243
+ if (matched === false && restoreIndexes) {
244
+ patternIndex = patternIndexBefore;
245
+ index = indexBefore;
246
+ }
247
+
248
+ // End the loop
249
+ continueIteration = false;
250
+ }
222
251
 
223
252
  return {
224
253
  matched,
@@ -228,7 +257,15 @@ const applyMatching = (pattern, string) => {
228
257
  };
229
258
  };
230
259
 
231
- const skipUntilMatch = ({ pattern, string, canSkipSlash }) => {
260
+ /**
261
+ * Iterative version of skipUntilMatch that avoids recursion
262
+ * @param {Object} params
263
+ * @param {string} params.pattern - The pattern to match
264
+ * @param {string} params.string - The string to test against
265
+ * @param {boolean} params.canSkipSlash - Whether slash characters can be skipped
266
+ * @returns {Object} Result of the matching attempt
267
+ */
268
+ const skipUntilMatchIterative = ({ pattern, string, canSkipSlash }) => {
232
269
  let index = 0;
233
270
  let remainingString = string;
234
271
  let longestAttemptRange = null;
@@ -246,8 +283,10 @@ const skipUntilMatch = ({ pattern, string, canSkipSlash }) => {
246
283
  };
247
284
  };
248
285
 
249
- const tryToMatch = () => {
286
+ // Loop until a match is found or all attempts fail
287
+ while (true) {
250
288
  const matchAttempt = applyMatching(pattern, remainingString);
289
+
251
290
  if (matchAttempt.matched) {
252
291
  return {
253
292
  matched: true,
@@ -262,6 +301,7 @@ const skipUntilMatch = ({ pattern, string, canSkipSlash }) => {
262
301
  },
263
302
  };
264
303
  }
304
+
265
305
  const attemptIndex = matchAttempt.index;
266
306
  const attemptRange = {
267
307
  patternIndex: matchAttempt.patternIndex,
@@ -269,19 +309,23 @@ const skipUntilMatch = ({ pattern, string, canSkipSlash }) => {
269
309
  length: attemptIndex,
270
310
  groups: matchAttempt.groups,
271
311
  };
312
+
272
313
  if (
273
314
  !longestAttemptRange ||
274
315
  longestAttemptRange.length < attemptRange.length
275
316
  ) {
276
317
  longestAttemptRange = attemptRange;
277
318
  }
319
+
278
320
  if (isLastAttempt) {
279
321
  return failure();
280
322
  }
323
+
281
324
  const nextIndex = attemptIndex + 1;
282
325
  if (nextIndex >= remainingString.length) {
283
326
  return failure();
284
327
  }
328
+
285
329
  if (remainingString[0] === "/") {
286
330
  if (!canSkipSlash) {
287
331
  return failure();
@@ -291,12 +335,11 @@ const skipUntilMatch = ({ pattern, string, canSkipSlash }) => {
291
335
  isLastAttempt = true;
292
336
  }
293
337
  }
338
+
294
339
  // search against the next unattempted string
295
340
  index += nextIndex;
296
341
  remainingString = remainingString.slice(nextIndex);
297
- return tryToMatch();
298
- };
299
- return tryToMatch();
342
+ }
300
343
  };
301
344
 
302
345
  const applyPatternMatching = ({ url, pattern }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "40.0.5",
3
+ "version": "40.0.7",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -79,25 +79,26 @@
79
79
  "@financial-times/polyfill-useragent-normaliser": "1.10.2",
80
80
  "@jsenv/abort": "4.3.1",
81
81
  "@jsenv/ast": "6.6.5",
82
- "@jsenv/filesystem": "4.14.2",
82
+ "@jsenv/filesystem": "4.14.3",
83
83
  "@jsenv/humanize": "1.3.1",
84
84
  "@jsenv/importmap": "1.2.2",
85
85
  "@jsenv/integrity": "0.0.2",
86
86
  "@jsenv/js-module-fallback": "1.4.3",
87
87
  "@jsenv/node-esm-resolution": "1.1.0",
88
- "@jsenv/plugin-bundling": "2.8.3",
88
+ "@jsenv/plugin-bundling": "2.8.4",
89
89
  "@jsenv/plugin-minification": "1.6.2",
90
90
  "@jsenv/plugin-supervisor": "1.6.10",
91
91
  "@jsenv/plugin-transpilation": "1.5.6",
92
92
  "@jsenv/runtime-compat": "1.3.4",
93
- "@jsenv/server": "16.0.3",
93
+ "@jsenv/server": "16.0.4",
94
94
  "@jsenv/sourcemap": "1.3.2",
95
- "@jsenv/url-meta": "8.5.4",
95
+ "@jsenv/url-meta": "8.5.5",
96
96
  "@jsenv/urls": "2.6.3",
97
97
  "@jsenv/utils": "2.2.1",
98
98
  "string-width": "7.2.0"
99
99
  },
100
100
  "devDependencies": {
101
+ "@babel/plugin-syntax-decorators": "7.25.9",
101
102
  "@babel/plugin-syntax-import-attributes": "7.26.0",
102
103
  "@babel/plugin-syntax-optional-chaining-assign": "7.25.9",
103
104
  "@jsenv/assert": "workspace:*",
@@ -60,11 +60,10 @@ export const jsenvPluginSubbuilds = (
60
60
  },
61
61
  fetchUrlContent: async (urlInfo) => {
62
62
  if (!entryPointBuildUrlSet.has(urlInfo.url)) {
63
- return null;
63
+ return;
64
64
  }
65
65
  await buildPromise;
66
66
  urlInfo.typeHint = "asset"; // this ensure the rest of jsenv do not scan or modify the content of this file
67
- return null;
68
67
  },
69
68
  };
70
69
  });