elit 3.6.3 → 3.6.5

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/cli.mjs CHANGED
@@ -1997,8 +1997,8 @@ var require_chance = __commonJS({
1997
1997
  return i;
1998
1998
  });
1999
1999
  }
2000
- function testRange(test2, errorMessage) {
2001
- if (test2) {
2000
+ function testRange(test, errorMessage) {
2001
+ if (test) {
2002
2002
  throw new RangeError(errorMessage);
2003
2003
  }
2004
2004
  }
@@ -54905,12 +54905,126 @@ ${k.ValidationErrorsFormatter.format(i2)}`);
54905
54905
  // src/test-runtime.ts
54906
54906
  import { transformSync } from "esbuild";
54907
54907
  import { SourceMapConsumer } from "source-map";
54908
- function escapeRegex(str) {
54908
+ function escapeRegex2(str) {
54909
54909
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
54910
54910
  }
54911
+ function resolveTestLoader(filePath) {
54912
+ return /\.(?:ts|tsx|mts|cts)$/i.test(filePath) ? "ts" : "js";
54913
+ }
54914
+ function createTestTransformOptions(filePath, format2, sourcemap) {
54915
+ return {
54916
+ loader: resolveTestLoader(filePath),
54917
+ format: format2,
54918
+ sourcemap,
54919
+ sourcefile: filePath,
54920
+ target: "es2020",
54921
+ tsconfigRaw: {
54922
+ compilerOptions: {
54923
+ jsx: "react",
54924
+ jsxFactory: "h",
54925
+ jsxFragmentFactory: "Fragment"
54926
+ }
54927
+ }
54928
+ };
54929
+ }
54930
+ function resolveExistingTestModulePath(basePath) {
54931
+ const nodePath = __require("path");
54932
+ if (existsSync(basePath) && statSync(basePath).isFile()) {
54933
+ return basePath;
54934
+ }
54935
+ for (const extension of TEST_MODULE_EXTENSIONS) {
54936
+ const candidatePath = `${basePath}${extension}`;
54937
+ if (existsSync(candidatePath) && statSync(candidatePath).isFile()) {
54938
+ return candidatePath;
54939
+ }
54940
+ }
54941
+ if (existsSync(basePath) && statSync(basePath).isDirectory()) {
54942
+ const packageJsonPath = nodePath.join(basePath, "package.json");
54943
+ if (existsSync(packageJsonPath) && statSync(packageJsonPath).isFile()) {
54944
+ try {
54945
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
54946
+ for (const candidateEntry of [packageJson.main, packageJson.module]) {
54947
+ if (typeof candidateEntry !== "string" || candidateEntry.trim().length === 0) {
54948
+ continue;
54949
+ }
54950
+ try {
54951
+ return resolveExistingTestModulePath(nodePath.resolve(basePath, candidateEntry));
54952
+ } catch {
54953
+ continue;
54954
+ }
54955
+ }
54956
+ } catch {
54957
+ }
54958
+ }
54959
+ for (const extension of TEST_MODULE_EXTENSIONS) {
54960
+ const candidatePath = nodePath.join(basePath, `index${extension}`);
54961
+ if (existsSync(candidatePath) && statSync(candidatePath).isFile()) {
54962
+ return candidatePath;
54963
+ }
54964
+ }
54965
+ }
54966
+ return basePath;
54967
+ }
54968
+ function resolveTestModulePath(fromFilePath, specifier) {
54969
+ if (!specifier.startsWith(".") && !specifier.startsWith("/")) {
54970
+ return specifier;
54971
+ }
54972
+ const nodePath = __require("path");
54973
+ const basePath = specifier.startsWith(".") ? nodePath.resolve(dirname(fromFilePath), specifier) : specifier;
54974
+ return resolveExistingTestModulePath(basePath);
54975
+ }
54976
+ function shouldTranspileTestModule(filePath) {
54977
+ return /\.(?:ts|tsx|mts|cts|js|jsx|mjs|cjs)$/i.test(filePath);
54978
+ }
54979
+ function createTestModuleRequire(fromFilePath, moduleCache) {
54980
+ return (specifier) => {
54981
+ if (specifier.startsWith("elit/") || specifier === "elit") {
54982
+ return __require(specifier);
54983
+ }
54984
+ const resolvedPath = resolveTestModulePath(fromFilePath, specifier);
54985
+ if (resolvedPath === specifier) {
54986
+ return __require(specifier);
54987
+ }
54988
+ if (!existsSync(resolvedPath) || !statSync(resolvedPath).isFile()) {
54989
+ return __require(resolvedPath);
54990
+ }
54991
+ if (!shouldTranspileTestModule(resolvedPath)) {
54992
+ return __require(resolvedPath);
54993
+ }
54994
+ return loadTranspiledTestModule(resolvedPath, moduleCache);
54995
+ };
54996
+ }
54997
+ function loadTranspiledTestModule(modulePath, moduleCache) {
54998
+ const cached = moduleCache.get(modulePath);
54999
+ if (cached) {
55000
+ return cached.exports;
55001
+ }
55002
+ const source = readFileSync(modulePath, "utf-8");
55003
+ let transpiled;
55004
+ try {
55005
+ transpiled = transformSync(source, createTestTransformOptions(modulePath, "cjs", false));
55006
+ } catch (error) {
55007
+ throw new Error(`Failed to transpile test dependency ${modulePath}: ${error instanceof Error ? error.message : String(error)}`);
55008
+ }
55009
+ const moduleRecord = { exports: {} };
55010
+ const moduleObj = { exports: moduleRecord.exports };
55011
+ moduleCache.set(modulePath, moduleRecord);
55012
+ try {
55013
+ const fn = new Function("module", "exports", "require", "__filename", "__dirname", transpiled.code);
55014
+ const requireFn = createTestModuleRequire(modulePath, moduleCache);
55015
+ fn(moduleObj, moduleObj.exports, requireFn, modulePath, dirname(modulePath));
55016
+ } catch (error) {
55017
+ throw new Error(`Failed to execute test dependency ${modulePath}: ${error instanceof Error ? error.message : String(error)}`);
55018
+ }
55019
+ moduleRecord.exports = moduleObj.exports;
55020
+ if (!modulePath.includes(".test.") && !modulePath.includes(".spec.")) {
55021
+ coveredFiles.add(modulePath);
55022
+ }
55023
+ return moduleRecord.exports;
55024
+ }
54911
55025
  function createTestFunction(defaultTimeout = 5e3) {
54912
55026
  const testFn = function(name, fn, timeout) {
54913
- const test2 = {
55027
+ const test = {
54914
55028
  name,
54915
55029
  fn,
54916
55030
  skip: currentSuite.skip,
@@ -54919,10 +55033,10 @@ function createTestFunction(defaultTimeout = 5e3) {
54919
55033
  timeout: timeout ?? defaultTimeout,
54920
55034
  suite: currentSuite
54921
55035
  };
54922
- currentSuite.tests.push(test2);
55036
+ currentSuite.tests.push(test);
54923
55037
  };
54924
55038
  testFn.skip = (name, fn, timeout) => {
54925
- const test2 = {
55039
+ const test = {
54926
55040
  name,
54927
55041
  fn,
54928
55042
  skip: true,
@@ -54931,11 +55045,11 @@ function createTestFunction(defaultTimeout = 5e3) {
54931
55045
  timeout: timeout ?? defaultTimeout,
54932
55046
  suite: currentSuite
54933
55047
  };
54934
- currentSuite.tests.push(test2);
55048
+ currentSuite.tests.push(test);
54935
55049
  };
54936
55050
  testFn.only = (name, fn, timeout) => {
54937
55051
  hasOnly = true;
54938
- const test2 = {
55052
+ const test = {
54939
55053
  name,
54940
55054
  fn,
54941
55055
  skip: false,
@@ -54944,10 +55058,10 @@ function createTestFunction(defaultTimeout = 5e3) {
54944
55058
  timeout: timeout ?? defaultTimeout,
54945
55059
  suite: currentSuite
54946
55060
  };
54947
- currentSuite.tests.push(test2);
55061
+ currentSuite.tests.push(test);
54948
55062
  };
54949
55063
  testFn.todo = (name, fn, timeout) => {
54950
- const test2 = {
55064
+ const test = {
54951
55065
  name,
54952
55066
  fn,
54953
55067
  skip: false,
@@ -54956,7 +55070,7 @@ function createTestFunction(defaultTimeout = 5e3) {
54956
55070
  timeout: timeout ?? defaultTimeout,
54957
55071
  suite: currentSuite
54958
55072
  };
54959
- currentSuite.tests.push(test2);
55073
+ currentSuite.tests.push(test);
54960
55074
  };
54961
55075
  return testFn;
54962
55076
  }
@@ -55066,29 +55180,7 @@ async function runTests(options) {
55066
55180
  try {
55067
55181
  const source = await readFile(file, "utf-8");
55068
55182
  const testFileDir = dirname(file);
55069
- const importRegex = /import\s+{\s*([^}]+)\s*}\s+from\s+['"]([^'"]+)['"]/g;
55070
- const imports = {};
55071
- let importIndex = 0;
55072
- let codeWithoutImports = source.replace(importRegex, (_, named, path) => {
55073
- const varName = `__import_${importIndex++}`;
55074
- const trimmedNamed = named.trim();
55075
- imports[varName] = { path, named: trimmedNamed };
55076
- return `// ${trimmedNamed} import injected later
55077
- `;
55078
- });
55079
- const result2 = transformSync(codeWithoutImports, {
55080
- loader: file.endsWith(".ts") || file.endsWith(".tsx") ? "ts" : "js",
55081
- format: "iife",
55082
- sourcemap: "inline",
55083
- target: "es2020",
55084
- tsconfigRaw: {
55085
- compilerOptions: {
55086
- jsx: "react",
55087
- jsxFactory: "h",
55088
- jsxFragmentFactory: "Fragment"
55089
- }
55090
- }
55091
- });
55183
+ const result2 = transformSync(source, createTestTransformOptions(file, "cjs", "inline"));
55092
55184
  let code = result2.code;
55093
55185
  const sourceMapMatch = code.match(/\/\/# sourceMappingURL=data:application\/json;base64,(.+)/);
55094
55186
  if (sourceMapMatch) {
@@ -55099,99 +55191,15 @@ async function runTests(options) {
55099
55191
  } else {
55100
55192
  currentSourceMapConsumer = void 0;
55101
55193
  }
55102
- const importedValues = {};
55103
- const importParamNames = [];
55104
- const importAssignments = [];
55105
- if (Object.keys(imports).length > 0) {
55106
- for (const [, { path, named }] of Object.entries(imports)) {
55107
- let resolvedPath = path;
55108
- if (path.startsWith(".")) {
55109
- const nodePath = __require("path");
55110
- resolvedPath = nodePath.resolve(testFileDir, path);
55111
- }
55112
- if (!resolvedPath.endsWith(".ts") && !resolvedPath.endsWith(".js") && !resolvedPath.endsWith(".mjs") && !resolvedPath.endsWith(".cjs")) {
55113
- resolvedPath += ".ts";
55114
- }
55115
- if (resolvedPath.endsWith(".ts")) {
55116
- try {
55117
- const importSource = await readFile(resolvedPath, "utf-8");
55118
- const transpiled = transformSync(importSource, {
55119
- loader: "ts",
55120
- format: "cjs",
55121
- target: "es2020",
55122
- tsconfigRaw: {
55123
- compilerOptions: {
55124
- jsx: "react",
55125
- jsxFactory: "h",
55126
- jsxFragmentFactory: "Fragment"
55127
- }
55128
- }
55129
- });
55130
- const moduleExports = {};
55131
- const moduleObj = { exports: moduleExports };
55132
- const fn2 = new Function("module", "exports", "require", "__filename", "__dirname", transpiled.code);
55133
- const requireFn = (id) => {
55134
- if (id.startsWith("elit/") || id === "elit") {
55135
- return __require(id);
55136
- }
55137
- if (id.startsWith(".")) {
55138
- const nodePath = __require("path");
55139
- const absPath = nodePath.resolve(dirname(resolvedPath), id);
55140
- return __require(absPath);
55141
- }
55142
- return __require(id);
55143
- };
55144
- fn2(moduleObj, moduleExports, requireFn, resolvedPath, dirname(resolvedPath));
55145
- if (!resolvedPath.includes(".test.") && !resolvedPath.includes(".spec.")) {
55146
- coveredFiles.add(resolvedPath);
55147
- }
55148
- let exportedValue = moduleObj.exports[named];
55149
- if (exportedValue === void 0 && moduleObj.exports.default) {
55150
- exportedValue = moduleObj.exports.default[named];
55151
- }
55152
- if (exportedValue === void 0 && typeof moduleObj.exports === "object") {
55153
- exportedValue = moduleObj.exports[named];
55154
- }
55155
- const paramKey = `__import_${Math.random().toString(36).substring(2, 11)}`;
55156
- importedValues[paramKey] = exportedValue;
55157
- importParamNames.push(paramKey);
55158
- importAssignments.push(`const ${named} = ${paramKey};`);
55159
- } catch (err) {
55160
- const paramKey = `__import_${Math.random().toString(36).substring(2, 11)}`;
55161
- importedValues[paramKey] = null;
55162
- importParamNames.push(paramKey);
55163
- importAssignments.push(`const ${named} = ${paramKey}; /* Error importing ${resolvedPath}: ${err} */`);
55164
- }
55165
- } else {
55166
- const requiredModule = __require(resolvedPath);
55167
- const exportedValue = requiredModule[named];
55168
- const paramKey = `__import_${Math.random().toString(36).substring(2, 11)}`;
55169
- importedValues[paramKey] = exportedValue;
55170
- importParamNames.push(paramKey);
55171
- importAssignments.push(`const ${named} = ${paramKey};`);
55172
- }
55173
- }
55174
- }
55175
- let preamble = "";
55176
- if (Object.keys(imports).length > 0) {
55177
- const iifeStartMatch = code.match(/^(\s*(?:var\s+\w+\s*=\s*)?\(\(\)\s*=>\s*\{\n)/);
55178
- if (iifeStartMatch) {
55179
- const iifePrefix = iifeStartMatch[1];
55180
- const assignments = `${importAssignments.join("\n")}
55181
- `;
55182
- preamble = iifePrefix;
55183
- code = iifePrefix + assignments + code.slice(iifeStartMatch[1].length);
55184
- } else {
55185
- preamble = importAssignments.join("\n") + "\n";
55186
- code = preamble + code;
55187
- }
55188
- }
55189
- wrapperLineOffset = preamble.split("\n").length;
55194
+ wrapperLineOffset = 0;
55190
55195
  setupGlobals();
55191
- const allParams = ["describe", "it", "test", "expect", "beforeAll", "afterAll", "beforeEach", "afterEach", "vi", "require", "module", "__filename", "__dirname", ...importParamNames];
55192
- const allArgs = [describe, it, test, expect, beforeAll, afterAll, beforeEach, afterEach, vi, __require, module, file, testFileDir, ...importParamNames.map((p) => importedValues[p])];
55193
- const fn = new Function(...allParams, code);
55194
- await fn(...allArgs);
55196
+ const moduleCache = /* @__PURE__ */ new Map();
55197
+ const moduleRecord = { exports: {} };
55198
+ const moduleObj = { exports: moduleRecord.exports };
55199
+ moduleCache.set(file, moduleRecord);
55200
+ const fn = new Function("module", "exports", "require", "__filename", "__dirname", code);
55201
+ const requireFn = createTestModuleRequire(file, moduleCache);
55202
+ await fn(moduleObj, moduleObj.exports, requireFn, file, testFileDir);
55195
55203
  await executeSuite(currentSuite, timeout, bail);
55196
55204
  if (currentSourceMapConsumer) {
55197
55205
  currentSourceMapConsumer.destroy();
@@ -55226,13 +55234,13 @@ async function runTests(options) {
55226
55234
  async function executeSuite(suite, timeout, bail, parentMatched = false) {
55227
55235
  let directMatch = false;
55228
55236
  if (describePattern) {
55229
- const escapedPattern = escapeRegex(describePattern);
55237
+ const escapedPattern = escapeRegex2(describePattern);
55230
55238
  const regex = new RegExp(escapedPattern, "i");
55231
55239
  directMatch = regex.test(suite.name);
55232
55240
  }
55233
55241
  function suiteOrDescendantMatches(s) {
55234
55242
  if (!describePattern) return true;
55235
- const escapedPattern = escapeRegex(describePattern);
55243
+ const escapedPattern = escapeRegex2(describePattern);
55236
55244
  const regex = new RegExp(escapedPattern, "i");
55237
55245
  if (regex.test(s.name)) return true;
55238
55246
  for (const child of s.suites) {
@@ -55256,22 +55264,22 @@ async function executeSuite(suite, timeout, bail, parentMatched = false) {
55256
55264
  for (const hook of beforeAllHooks) {
55257
55265
  await hook();
55258
55266
  }
55259
- for (const test2 of suite.tests) {
55260
- if (hasOnly && !test2.only && !suite.only) {
55267
+ for (const test of suite.tests) {
55268
+ if (hasOnly && !test.only && !suite.only) {
55261
55269
  continue;
55262
55270
  }
55263
55271
  let testMatches = true;
55264
55272
  if (testPattern) {
55265
- const escapedPattern = escapeRegex(testPattern);
55273
+ const escapedPattern = escapeRegex2(testPattern);
55266
55274
  const regex = new RegExp(escapedPattern, "i");
55267
- testMatches = regex.test(test2.name);
55275
+ testMatches = regex.test(test.name);
55268
55276
  }
55269
55277
  if (!testMatches) {
55270
55278
  continue;
55271
55279
  }
55272
- if (test2.skip || suite.skip) {
55280
+ if (test.skip || suite.skip) {
55273
55281
  testResults.push({
55274
- name: test2.name,
55282
+ name: test.name,
55275
55283
  status: "skip",
55276
55284
  duration: 0,
55277
55285
  suite: suite.name,
@@ -55279,9 +55287,9 @@ async function executeSuite(suite, timeout, bail, parentMatched = false) {
55279
55287
  });
55280
55288
  continue;
55281
55289
  }
55282
- if (test2.todo) {
55290
+ if (test.todo) {
55283
55291
  testResults.push({
55284
- name: test2.name,
55292
+ name: test.name,
55285
55293
  status: "todo",
55286
55294
  duration: 0,
55287
55295
  suite: suite.name,
@@ -55295,13 +55303,13 @@ async function executeSuite(suite, timeout, bail, parentMatched = false) {
55295
55303
  const startTime = Date.now();
55296
55304
  try {
55297
55305
  await Promise.race([
55298
- test2.fn(),
55306
+ test.fn(),
55299
55307
  new Promise(
55300
- (_, reject) => setTimeout(() => reject(new Error(`Test timed out after ${test2.timeout}ms`)), test2.timeout)
55308
+ (_, reject) => setTimeout(() => reject(new Error(`Test timed out after ${test.timeout}ms`)), test.timeout)
55301
55309
  )
55302
55310
  ]);
55303
55311
  testResults.push({
55304
- name: test2.name,
55312
+ name: test.name,
55305
55313
  status: "pass",
55306
55314
  duration: Date.now() - startTime,
55307
55315
  suite: suite.name,
@@ -55315,7 +55323,7 @@ async function executeSuite(suite, timeout, bail, parentMatched = false) {
55315
55323
  codeSnippet = error.codeSnippet;
55316
55324
  }
55317
55325
  testResults.push({
55318
- name: test2.name,
55326
+ name: test.name,
55319
55327
  status: "fail",
55320
55328
  duration: Date.now() - startTime,
55321
55329
  error,
@@ -55364,7 +55372,7 @@ function getCoveredFiles() {
55364
55372
  function resetCoveredFiles() {
55365
55373
  coveredFiles.clear();
55366
55374
  }
55367
- var AssertionError, currentSuite, testResults, hasOnly, coveredFiles, describePattern, testPattern, currentTestFile, currentSourceMapConsumer, wrapperLineOffset, Expect, vi, beforeAllHooks, afterAllHooks, beforeEachHooks, afterEachHooks, beforeAll, afterAll, beforeEach, afterEach, globals;
55375
+ var AssertionError, currentSuite, testResults, hasOnly, coveredFiles, describePattern, testPattern, currentTestFile, currentSourceMapConsumer, wrapperLineOffset, TEST_MODULE_EXTENSIONS, Expect, vi, beforeAllHooks, afterAllHooks, beforeEachHooks, afterEachHooks, beforeAll, afterAll, beforeEach, afterEach, globals;
55368
55376
  var init_test_runtime = __esm({
55369
55377
  "src/test-runtime.ts"() {
55370
55378
  "use strict";
@@ -55395,6 +55403,7 @@ var init_test_runtime = __esm({
55395
55403
  currentTestFile = void 0;
55396
55404
  currentSourceMapConsumer = void 0;
55397
55405
  wrapperLineOffset = 0;
55406
+ TEST_MODULE_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
55398
55407
  Expect = class _Expect {
55399
55408
  constructor(actual, isNot = false, isAsync = false) {
55400
55409
  this.actual = actual;
@@ -74860,7 +74869,7 @@ function readLineIgnorePatterns(filePath) {
74860
74869
  if (!existsSync2(filePath)) {
74861
74870
  return [];
74862
74871
  }
74863
- return readFileSync2(filePath, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
74872
+ return readFileSync2(filePath, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && (!line.startsWith("#") || line.startsWith("\\#")));
74864
74873
  }
74865
74874
  function normalizePackageEntry(value) {
74866
74875
  const normalized = normalizeNonEmptyString(value)?.replace(/^[.][\\/]/, "").split("\\").join("/");
@@ -75041,23 +75050,103 @@ function resolveLinkedDependencyArchivePrefix(archivePrefix, dependencyName) {
75041
75050
  }
75042
75051
  return `${normalizedPrefix.slice(0, markerIndex + marker.length)}${dependencyName}`;
75043
75052
  }
75044
- function shouldIgnore(relativePath2, ignorePatterns) {
75045
- const pathParts = relativePath2.split("/");
75046
- for (const pattern of ignorePatterns) {
75047
- if (relativePath2 === pattern || pathParts.includes(pattern)) {
75048
- return true;
75049
- }
75050
- if (pattern.endsWith("*")) {
75051
- const prefix = pattern.slice(0, -1);
75052
- if (relativePath2.startsWith(prefix) || pathParts.some((part) => part.startsWith(prefix))) {
75053
- return true;
75053
+ function escapeRegex(text) {
75054
+ return text.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
75055
+ }
75056
+ function globPatternToRegex(pattern, options = {}) {
75057
+ let regex = "";
75058
+ for (let index = 0; index < pattern.length; index++) {
75059
+ const char = pattern[index];
75060
+ if (char === "*") {
75061
+ const nextChar = pattern[index + 1];
75062
+ const nextNextChar = pattern[index + 2];
75063
+ if (nextChar === "*") {
75064
+ if (nextNextChar === "/") {
75065
+ regex += "(?:.*?/)?";
75066
+ index += 2;
75067
+ continue;
75068
+ }
75069
+ regex += ".*";
75070
+ index += 1;
75071
+ continue;
75054
75072
  }
75073
+ regex += "[^/]*";
75074
+ continue;
75055
75075
  }
75056
- if (pattern.startsWith("*.") && relativePath2.endsWith(pattern.slice(1))) {
75057
- return true;
75076
+ if (char === "?") {
75077
+ regex += "[^/]";
75078
+ continue;
75058
75079
  }
75080
+ regex += escapeRegex(char);
75059
75081
  }
75060
- return false;
75082
+ const suffix = options.directoryOnly ? "(?:$|/.*)" : "$";
75083
+ const prefix = options.matchSegmentsOnly ? "^(?:.*?/)?" : "^";
75084
+ return new RegExp(`${prefix}${regex}${suffix}`);
75085
+ }
75086
+ function normalizeIgnorePattern(pattern) {
75087
+ let normalizedPattern = pattern.trim();
75088
+ if (!normalizedPattern) {
75089
+ return void 0;
75090
+ }
75091
+ let negate = false;
75092
+ if (normalizedPattern.startsWith("\\!") || normalizedPattern.startsWith("\\#")) {
75093
+ normalizedPattern = normalizedPattern.slice(1);
75094
+ } else if (normalizedPattern.startsWith("!")) {
75095
+ negate = true;
75096
+ normalizedPattern = normalizedPattern.slice(1).trim();
75097
+ }
75098
+ if (!normalizedPattern) {
75099
+ return void 0;
75100
+ }
75101
+ const directoryOnly = normalizedPattern.endsWith("/");
75102
+ if (directoryOnly) {
75103
+ normalizedPattern = normalizedPattern.replace(/\/+$/, "");
75104
+ }
75105
+ normalizedPattern = normalizedPattern.replace(/^\.\//, "").replace(/^\//, "").replace(/\\/g, "/");
75106
+ if (!normalizedPattern) {
75107
+ return void 0;
75108
+ }
75109
+ return {
75110
+ directoryOnly,
75111
+ matchSegmentsOnly: !normalizedPattern.includes("/"),
75112
+ negate,
75113
+ pattern: normalizedPattern
75114
+ };
75115
+ }
75116
+ function matchesIgnorePattern(relativePath2, pattern, isDirectory) {
75117
+ const normalizedRule = normalizeIgnorePattern(pattern);
75118
+ if (!normalizedRule) {
75119
+ return false;
75120
+ }
75121
+ if (normalizedRule.directoryOnly && !isDirectory) {
75122
+ return false;
75123
+ }
75124
+ const hasGlob = /[*?]/.test(normalizedRule.pattern);
75125
+ if (!hasGlob) {
75126
+ if (normalizedRule.matchSegmentsOnly) {
75127
+ return relativePath2 === normalizedRule.pattern || relativePath2.split("/").includes(normalizedRule.pattern);
75128
+ }
75129
+ return relativePath2 === normalizedRule.pattern;
75130
+ }
75131
+ if (normalizedRule.matchSegmentsOnly) {
75132
+ const segmentRegex = globPatternToRegex(normalizedRule.pattern);
75133
+ return relativePath2.split("/").some((segment) => segmentRegex.test(segment));
75134
+ }
75135
+ return globPatternToRegex(normalizedRule.pattern, { directoryOnly: normalizedRule.directoryOnly }).test(relativePath2);
75136
+ }
75137
+ function shouldIgnore(relativePath2, ignorePatterns, isDirectory) {
75138
+ let ignored = false;
75139
+ for (const pattern of ignorePatterns) {
75140
+ const normalizedRule = normalizeIgnorePattern(pattern);
75141
+ if (!normalizedRule) {
75142
+ continue;
75143
+ }
75144
+ if (!matchesIgnorePattern(relativePath2, pattern, isDirectory)) {
75145
+ continue;
75146
+ }
75147
+ ignored = !normalizedRule.negate;
75148
+ }
75149
+ return ignored;
75061
75150
  }
75062
75151
  function collectFiles(directory, baseDirectory, ignorePatterns) {
75063
75152
  const files = [];
@@ -75065,7 +75154,7 @@ function collectFiles(directory, baseDirectory, ignorePatterns) {
75065
75154
  for (const entry of entries) {
75066
75155
  const fullPath = join2(directory, entry.name);
75067
75156
  const relativePath2 = relative2(baseDirectory, fullPath).split("\\").join("/");
75068
- if (shouldIgnore(relativePath2, ignorePatterns)) {
75157
+ if (shouldIgnore(relativePath2, ignorePatterns, entry.isDirectory())) {
75069
75158
  continue;
75070
75159
  }
75071
75160
  if (entry.isSymbolicLink()) {
@@ -76468,7 +76557,7 @@ function printWapkHelp() {
76468
76557
  "",
76469
76558
  "Notes:",
76470
76559
  " - Pack reads wapk from elit.config.* and falls back to package.json.",
76471
- " - Pack includes node_modules by default; use .wapkignore if you need to exclude them.",
76560
+ " - Pack includes node_modules by default; use .wapkignore if you need to exclude them, and !pattern to re-include later matches.",
76472
76561
  " - Run never installs dependencies automatically; archives must include the runtime dependencies they need.",
76473
76562
  " - Run mode can read config.wapk.run for default file/runtime/live-sync options.",
76474
76563
  " - Browser-style archives with scripts.start or wapk.script.start run that start script automatically.",