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/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "elit-desktop"
3
- version = "3.6.3"
3
+ version = "3.6.5"
4
4
  edition = "2021"
5
5
  build = "desktop/build.rs"
6
6
 
package/README.md CHANGED
@@ -866,6 +866,9 @@ createWindow({
866
866
  });
867
867
  ```
868
868
 
869
+ For a runnable minimal file in this repo, see `examples/desktop-simple-example.ts`.
870
+ For a runnable project-style repo, see `examples/desktop-typescript-example/`.
871
+
869
872
  Run it:
870
873
 
871
874
  ```bash
@@ -955,7 +958,7 @@ The package also exports `elit/test`, `elit/test-runtime`, and `elit/test-report
955
958
 
956
959
  Latest release notes live in [CHANGELOG.md](CHANGELOG.md).
957
960
 
958
- Highlights in `v3.6.3`:
961
+ Highlights in `v3.6.5`:
959
962
 
960
963
  - Added `elit pm` for detached background process management of shell commands, file targets, and WAPK apps.
961
964
  - Added `pm.apps[]` and `pm.dataDir` in `elit.config.*` for config-first process manager workflows.
@@ -992,6 +995,8 @@ If you are working in this repository, these locations matter most:
992
995
  - `examples/full-db`: larger full-stack example with database usage
993
996
  - `examples/universal-app-example`: one repo covering web, desktop, and Android mobile smoke flows
994
997
  - `examples/android-native-example`: Android-first native mobile validation flow
998
+ - `examples/desktop-typescript-example`: project-style desktop app with `package.json`, `elit.config.ts`, and a TypeScript desktop entry
999
+ - `examples/desktop-simple-example.ts`: minimal desktop window example with inline HTML + IPC buttons
995
1000
  - `examples/desktop-example.ts`: desktop smoke test and runtime example
996
1001
  - `packages/create-elit`: scaffold templates used by `npm create elit@latest`
997
1002
  - `docs/`: the documentation site built with Elit itself
@@ -1008,6 +1013,8 @@ If you are working in this repository, these locations matter most:
1008
1013
  - `examples/correct-config` for the cleanest SSR + API setup
1009
1014
  - `examples/universal-app-example` for a single repo exercising web, desktop, and Android mobile together
1010
1015
  - `examples/android-native-example` for Android-native mobile validation
1016
+ - `examples/desktop-typescript-example` for a small desktop project you can install and run directly
1017
+ - `examples/desktop-simple-example.ts` for the smallest desktop window example
1011
1018
  - `examples/desktop-example.ts` for desktop runtime usage
1012
1019
  - `USAGE_EXAMPLES.md` for more import combinations
1013
1020
  - `docs/API.md` for broader API detail
package/dist/cli.cjs CHANGED
@@ -1992,8 +1992,8 @@ var require_chance = __commonJS({
1992
1992
  return i;
1993
1993
  });
1994
1994
  }
1995
- function testRange(test2, errorMessage) {
1996
- if (test2) {
1995
+ function testRange(test, errorMessage) {
1996
+ if (test) {
1997
1997
  throw new RangeError(errorMessage);
1998
1998
  }
1999
1999
  }
@@ -54898,12 +54898,126 @@ ${k.ValidationErrorsFormatter.format(i2)}`);
54898
54898
  });
54899
54899
 
54900
54900
  // src/test-runtime.ts
54901
- function escapeRegex(str) {
54901
+ function escapeRegex2(str) {
54902
54902
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
54903
54903
  }
54904
+ function resolveTestLoader(filePath) {
54905
+ return /\.(?:ts|tsx|mts|cts)$/i.test(filePath) ? "ts" : "js";
54906
+ }
54907
+ function createTestTransformOptions(filePath, format2, sourcemap) {
54908
+ return {
54909
+ loader: resolveTestLoader(filePath),
54910
+ format: format2,
54911
+ sourcemap,
54912
+ sourcefile: filePath,
54913
+ target: "es2020",
54914
+ tsconfigRaw: {
54915
+ compilerOptions: {
54916
+ jsx: "react",
54917
+ jsxFactory: "h",
54918
+ jsxFragmentFactory: "Fragment"
54919
+ }
54920
+ }
54921
+ };
54922
+ }
54923
+ function resolveExistingTestModulePath(basePath) {
54924
+ const nodePath = require("path");
54925
+ if (existsSync(basePath) && statSync(basePath).isFile()) {
54926
+ return basePath;
54927
+ }
54928
+ for (const extension of TEST_MODULE_EXTENSIONS) {
54929
+ const candidatePath = `${basePath}${extension}`;
54930
+ if (existsSync(candidatePath) && statSync(candidatePath).isFile()) {
54931
+ return candidatePath;
54932
+ }
54933
+ }
54934
+ if (existsSync(basePath) && statSync(basePath).isDirectory()) {
54935
+ const packageJsonPath = nodePath.join(basePath, "package.json");
54936
+ if (existsSync(packageJsonPath) && statSync(packageJsonPath).isFile()) {
54937
+ try {
54938
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
54939
+ for (const candidateEntry of [packageJson.main, packageJson.module]) {
54940
+ if (typeof candidateEntry !== "string" || candidateEntry.trim().length === 0) {
54941
+ continue;
54942
+ }
54943
+ try {
54944
+ return resolveExistingTestModulePath(nodePath.resolve(basePath, candidateEntry));
54945
+ } catch {
54946
+ continue;
54947
+ }
54948
+ }
54949
+ } catch {
54950
+ }
54951
+ }
54952
+ for (const extension of TEST_MODULE_EXTENSIONS) {
54953
+ const candidatePath = nodePath.join(basePath, `index${extension}`);
54954
+ if (existsSync(candidatePath) && statSync(candidatePath).isFile()) {
54955
+ return candidatePath;
54956
+ }
54957
+ }
54958
+ }
54959
+ return basePath;
54960
+ }
54961
+ function resolveTestModulePath(fromFilePath, specifier) {
54962
+ if (!specifier.startsWith(".") && !specifier.startsWith("/")) {
54963
+ return specifier;
54964
+ }
54965
+ const nodePath = require("path");
54966
+ const basePath = specifier.startsWith(".") ? nodePath.resolve(dirname(fromFilePath), specifier) : specifier;
54967
+ return resolveExistingTestModulePath(basePath);
54968
+ }
54969
+ function shouldTranspileTestModule(filePath) {
54970
+ return /\.(?:ts|tsx|mts|cts|js|jsx|mjs|cjs)$/i.test(filePath);
54971
+ }
54972
+ function createTestModuleRequire(fromFilePath, moduleCache) {
54973
+ return (specifier) => {
54974
+ if (specifier.startsWith("elit/") || specifier === "elit") {
54975
+ return require(specifier);
54976
+ }
54977
+ const resolvedPath = resolveTestModulePath(fromFilePath, specifier);
54978
+ if (resolvedPath === specifier) {
54979
+ return require(specifier);
54980
+ }
54981
+ if (!existsSync(resolvedPath) || !statSync(resolvedPath).isFile()) {
54982
+ return require(resolvedPath);
54983
+ }
54984
+ if (!shouldTranspileTestModule(resolvedPath)) {
54985
+ return require(resolvedPath);
54986
+ }
54987
+ return loadTranspiledTestModule(resolvedPath, moduleCache);
54988
+ };
54989
+ }
54990
+ function loadTranspiledTestModule(modulePath, moduleCache) {
54991
+ const cached = moduleCache.get(modulePath);
54992
+ if (cached) {
54993
+ return cached.exports;
54994
+ }
54995
+ const source = readFileSync(modulePath, "utf-8");
54996
+ let transpiled;
54997
+ try {
54998
+ transpiled = (0, import_esbuild3.transformSync)(source, createTestTransformOptions(modulePath, "cjs", false));
54999
+ } catch (error) {
55000
+ throw new Error(`Failed to transpile test dependency ${modulePath}: ${error instanceof Error ? error.message : String(error)}`);
55001
+ }
55002
+ const moduleRecord = { exports: {} };
55003
+ const moduleObj = { exports: moduleRecord.exports };
55004
+ moduleCache.set(modulePath, moduleRecord);
55005
+ try {
55006
+ const fn = new Function("module", "exports", "require", "__filename", "__dirname", transpiled.code);
55007
+ const requireFn = createTestModuleRequire(modulePath, moduleCache);
55008
+ fn(moduleObj, moduleObj.exports, requireFn, modulePath, dirname(modulePath));
55009
+ } catch (error) {
55010
+ throw new Error(`Failed to execute test dependency ${modulePath}: ${error instanceof Error ? error.message : String(error)}`);
55011
+ }
55012
+ moduleRecord.exports = moduleObj.exports;
55013
+ if (!modulePath.includes(".test.") && !modulePath.includes(".spec.")) {
55014
+ coveredFiles.add(modulePath);
55015
+ }
55016
+ return moduleRecord.exports;
55017
+ }
54904
55018
  function createTestFunction(defaultTimeout = 5e3) {
54905
55019
  const testFn = function(name, fn, timeout) {
54906
- const test2 = {
55020
+ const test = {
54907
55021
  name,
54908
55022
  fn,
54909
55023
  skip: currentSuite.skip,
@@ -54912,10 +55026,10 @@ function createTestFunction(defaultTimeout = 5e3) {
54912
55026
  timeout: timeout ?? defaultTimeout,
54913
55027
  suite: currentSuite
54914
55028
  };
54915
- currentSuite.tests.push(test2);
55029
+ currentSuite.tests.push(test);
54916
55030
  };
54917
55031
  testFn.skip = (name, fn, timeout) => {
54918
- const test2 = {
55032
+ const test = {
54919
55033
  name,
54920
55034
  fn,
54921
55035
  skip: true,
@@ -54924,11 +55038,11 @@ function createTestFunction(defaultTimeout = 5e3) {
54924
55038
  timeout: timeout ?? defaultTimeout,
54925
55039
  suite: currentSuite
54926
55040
  };
54927
- currentSuite.tests.push(test2);
55041
+ currentSuite.tests.push(test);
54928
55042
  };
54929
55043
  testFn.only = (name, fn, timeout) => {
54930
55044
  hasOnly = true;
54931
- const test2 = {
55045
+ const test = {
54932
55046
  name,
54933
55047
  fn,
54934
55048
  skip: false,
@@ -54937,10 +55051,10 @@ function createTestFunction(defaultTimeout = 5e3) {
54937
55051
  timeout: timeout ?? defaultTimeout,
54938
55052
  suite: currentSuite
54939
55053
  };
54940
- currentSuite.tests.push(test2);
55054
+ currentSuite.tests.push(test);
54941
55055
  };
54942
55056
  testFn.todo = (name, fn, timeout) => {
54943
- const test2 = {
55057
+ const test = {
54944
55058
  name,
54945
55059
  fn,
54946
55060
  skip: false,
@@ -54949,7 +55063,7 @@ function createTestFunction(defaultTimeout = 5e3) {
54949
55063
  timeout: timeout ?? defaultTimeout,
54950
55064
  suite: currentSuite
54951
55065
  };
54952
- currentSuite.tests.push(test2);
55066
+ currentSuite.tests.push(test);
54953
55067
  };
54954
55068
  return testFn;
54955
55069
  }
@@ -55059,29 +55173,7 @@ async function runTests(options) {
55059
55173
  try {
55060
55174
  const source = await readFile(file, "utf-8");
55061
55175
  const testFileDir = dirname(file);
55062
- const importRegex = /import\s+{\s*([^}]+)\s*}\s+from\s+['"]([^'"]+)['"]/g;
55063
- const imports = {};
55064
- let importIndex = 0;
55065
- let codeWithoutImports = source.replace(importRegex, (_, named, path) => {
55066
- const varName = `__import_${importIndex++}`;
55067
- const trimmedNamed = named.trim();
55068
- imports[varName] = { path, named: trimmedNamed };
55069
- return `// ${trimmedNamed} import injected later
55070
- `;
55071
- });
55072
- const result2 = (0, import_esbuild3.transformSync)(codeWithoutImports, {
55073
- loader: file.endsWith(".ts") || file.endsWith(".tsx") ? "ts" : "js",
55074
- format: "iife",
55075
- sourcemap: "inline",
55076
- target: "es2020",
55077
- tsconfigRaw: {
55078
- compilerOptions: {
55079
- jsx: "react",
55080
- jsxFactory: "h",
55081
- jsxFragmentFactory: "Fragment"
55082
- }
55083
- }
55084
- });
55176
+ const result2 = (0, import_esbuild3.transformSync)(source, createTestTransformOptions(file, "cjs", "inline"));
55085
55177
  let code = result2.code;
55086
55178
  const sourceMapMatch = code.match(/\/\/# sourceMappingURL=data:application\/json;base64,(.+)/);
55087
55179
  if (sourceMapMatch) {
@@ -55092,99 +55184,15 @@ async function runTests(options) {
55092
55184
  } else {
55093
55185
  currentSourceMapConsumer = void 0;
55094
55186
  }
55095
- const importedValues = {};
55096
- const importParamNames = [];
55097
- const importAssignments = [];
55098
- if (Object.keys(imports).length > 0) {
55099
- for (const [, { path, named }] of Object.entries(imports)) {
55100
- let resolvedPath = path;
55101
- if (path.startsWith(".")) {
55102
- const nodePath = require("path");
55103
- resolvedPath = nodePath.resolve(testFileDir, path);
55104
- }
55105
- if (!resolvedPath.endsWith(".ts") && !resolvedPath.endsWith(".js") && !resolvedPath.endsWith(".mjs") && !resolvedPath.endsWith(".cjs")) {
55106
- resolvedPath += ".ts";
55107
- }
55108
- if (resolvedPath.endsWith(".ts")) {
55109
- try {
55110
- const importSource = await readFile(resolvedPath, "utf-8");
55111
- const transpiled = (0, import_esbuild3.transformSync)(importSource, {
55112
- loader: "ts",
55113
- format: "cjs",
55114
- target: "es2020",
55115
- tsconfigRaw: {
55116
- compilerOptions: {
55117
- jsx: "react",
55118
- jsxFactory: "h",
55119
- jsxFragmentFactory: "Fragment"
55120
- }
55121
- }
55122
- });
55123
- const moduleExports = {};
55124
- const moduleObj = { exports: moduleExports };
55125
- const fn2 = new Function("module", "exports", "require", "__filename", "__dirname", transpiled.code);
55126
- const requireFn = (id) => {
55127
- if (id.startsWith("elit/") || id === "elit") {
55128
- return require(id);
55129
- }
55130
- if (id.startsWith(".")) {
55131
- const nodePath = require("path");
55132
- const absPath = nodePath.resolve(dirname(resolvedPath), id);
55133
- return require(absPath);
55134
- }
55135
- return require(id);
55136
- };
55137
- fn2(moduleObj, moduleExports, requireFn, resolvedPath, dirname(resolvedPath));
55138
- if (!resolvedPath.includes(".test.") && !resolvedPath.includes(".spec.")) {
55139
- coveredFiles.add(resolvedPath);
55140
- }
55141
- let exportedValue = moduleObj.exports[named];
55142
- if (exportedValue === void 0 && moduleObj.exports.default) {
55143
- exportedValue = moduleObj.exports.default[named];
55144
- }
55145
- if (exportedValue === void 0 && typeof moduleObj.exports === "object") {
55146
- exportedValue = moduleObj.exports[named];
55147
- }
55148
- const paramKey = `__import_${Math.random().toString(36).substring(2, 11)}`;
55149
- importedValues[paramKey] = exportedValue;
55150
- importParamNames.push(paramKey);
55151
- importAssignments.push(`const ${named} = ${paramKey};`);
55152
- } catch (err) {
55153
- const paramKey = `__import_${Math.random().toString(36).substring(2, 11)}`;
55154
- importedValues[paramKey] = null;
55155
- importParamNames.push(paramKey);
55156
- importAssignments.push(`const ${named} = ${paramKey}; /* Error importing ${resolvedPath}: ${err} */`);
55157
- }
55158
- } else {
55159
- const requiredModule = require(resolvedPath);
55160
- const exportedValue = requiredModule[named];
55161
- const paramKey = `__import_${Math.random().toString(36).substring(2, 11)}`;
55162
- importedValues[paramKey] = exportedValue;
55163
- importParamNames.push(paramKey);
55164
- importAssignments.push(`const ${named} = ${paramKey};`);
55165
- }
55166
- }
55167
- }
55168
- let preamble = "";
55169
- if (Object.keys(imports).length > 0) {
55170
- const iifeStartMatch = code.match(/^(\s*(?:var\s+\w+\s*=\s*)?\(\(\)\s*=>\s*\{\n)/);
55171
- if (iifeStartMatch) {
55172
- const iifePrefix = iifeStartMatch[1];
55173
- const assignments = `${importAssignments.join("\n")}
55174
- `;
55175
- preamble = iifePrefix;
55176
- code = iifePrefix + assignments + code.slice(iifeStartMatch[1].length);
55177
- } else {
55178
- preamble = importAssignments.join("\n") + "\n";
55179
- code = preamble + code;
55180
- }
55181
- }
55182
- wrapperLineOffset = preamble.split("\n").length;
55187
+ wrapperLineOffset = 0;
55183
55188
  setupGlobals();
55184
- const allParams = ["describe", "it", "test", "expect", "beforeAll", "afterAll", "beforeEach", "afterEach", "vi", "require", "module", "__filename", "__dirname", ...importParamNames];
55185
- const allArgs = [describe, it, test, expect, beforeAll, afterAll, beforeEach, afterEach, vi, require, module, file, testFileDir, ...importParamNames.map((p) => importedValues[p])];
55186
- const fn = new Function(...allParams, code);
55187
- await fn(...allArgs);
55189
+ const moduleCache = /* @__PURE__ */ new Map();
55190
+ const moduleRecord = { exports: {} };
55191
+ const moduleObj = { exports: moduleRecord.exports };
55192
+ moduleCache.set(file, moduleRecord);
55193
+ const fn = new Function("module", "exports", "require", "__filename", "__dirname", code);
55194
+ const requireFn = createTestModuleRequire(file, moduleCache);
55195
+ await fn(moduleObj, moduleObj.exports, requireFn, file, testFileDir);
55188
55196
  await executeSuite(currentSuite, timeout, bail);
55189
55197
  if (currentSourceMapConsumer) {
55190
55198
  currentSourceMapConsumer.destroy();
@@ -55219,13 +55227,13 @@ async function runTests(options) {
55219
55227
  async function executeSuite(suite, timeout, bail, parentMatched = false) {
55220
55228
  let directMatch = false;
55221
55229
  if (describePattern) {
55222
- const escapedPattern = escapeRegex(describePattern);
55230
+ const escapedPattern = escapeRegex2(describePattern);
55223
55231
  const regex = new RegExp(escapedPattern, "i");
55224
55232
  directMatch = regex.test(suite.name);
55225
55233
  }
55226
55234
  function suiteOrDescendantMatches(s) {
55227
55235
  if (!describePattern) return true;
55228
- const escapedPattern = escapeRegex(describePattern);
55236
+ const escapedPattern = escapeRegex2(describePattern);
55229
55237
  const regex = new RegExp(escapedPattern, "i");
55230
55238
  if (regex.test(s.name)) return true;
55231
55239
  for (const child of s.suites) {
@@ -55249,22 +55257,22 @@ async function executeSuite(suite, timeout, bail, parentMatched = false) {
55249
55257
  for (const hook of beforeAllHooks) {
55250
55258
  await hook();
55251
55259
  }
55252
- for (const test2 of suite.tests) {
55253
- if (hasOnly && !test2.only && !suite.only) {
55260
+ for (const test of suite.tests) {
55261
+ if (hasOnly && !test.only && !suite.only) {
55254
55262
  continue;
55255
55263
  }
55256
55264
  let testMatches = true;
55257
55265
  if (testPattern) {
55258
- const escapedPattern = escapeRegex(testPattern);
55266
+ const escapedPattern = escapeRegex2(testPattern);
55259
55267
  const regex = new RegExp(escapedPattern, "i");
55260
- testMatches = regex.test(test2.name);
55268
+ testMatches = regex.test(test.name);
55261
55269
  }
55262
55270
  if (!testMatches) {
55263
55271
  continue;
55264
55272
  }
55265
- if (test2.skip || suite.skip) {
55273
+ if (test.skip || suite.skip) {
55266
55274
  testResults.push({
55267
- name: test2.name,
55275
+ name: test.name,
55268
55276
  status: "skip",
55269
55277
  duration: 0,
55270
55278
  suite: suite.name,
@@ -55272,9 +55280,9 @@ async function executeSuite(suite, timeout, bail, parentMatched = false) {
55272
55280
  });
55273
55281
  continue;
55274
55282
  }
55275
- if (test2.todo) {
55283
+ if (test.todo) {
55276
55284
  testResults.push({
55277
- name: test2.name,
55285
+ name: test.name,
55278
55286
  status: "todo",
55279
55287
  duration: 0,
55280
55288
  suite: suite.name,
@@ -55288,13 +55296,13 @@ async function executeSuite(suite, timeout, bail, parentMatched = false) {
55288
55296
  const startTime = Date.now();
55289
55297
  try {
55290
55298
  await Promise.race([
55291
- test2.fn(),
55299
+ test.fn(),
55292
55300
  new Promise(
55293
- (_, reject) => setTimeout(() => reject(new Error(`Test timed out after ${test2.timeout}ms`)), test2.timeout)
55301
+ (_, reject) => setTimeout(() => reject(new Error(`Test timed out after ${test.timeout}ms`)), test.timeout)
55294
55302
  )
55295
55303
  ]);
55296
55304
  testResults.push({
55297
- name: test2.name,
55305
+ name: test.name,
55298
55306
  status: "pass",
55299
55307
  duration: Date.now() - startTime,
55300
55308
  suite: suite.name,
@@ -55308,7 +55316,7 @@ async function executeSuite(suite, timeout, bail, parentMatched = false) {
55308
55316
  codeSnippet = error.codeSnippet;
55309
55317
  }
55310
55318
  testResults.push({
55311
- name: test2.name,
55319
+ name: test.name,
55312
55320
  status: "fail",
55313
55321
  duration: Date.now() - startTime,
55314
55322
  error,
@@ -55357,7 +55365,7 @@ function getCoveredFiles() {
55357
55365
  function resetCoveredFiles() {
55358
55366
  coveredFiles.clear();
55359
55367
  }
55360
- var import_esbuild3, import_source_map, AssertionError, currentSuite, testResults, hasOnly, coveredFiles, describePattern, testPattern, currentTestFile, currentSourceMapConsumer, wrapperLineOffset, Expect, vi, beforeAllHooks, afterAllHooks, beforeEachHooks, afterEachHooks, beforeAll, afterAll, beforeEach, afterEach, globals;
55368
+ var import_esbuild3, import_source_map, AssertionError, currentSuite, testResults, hasOnly, coveredFiles, describePattern, testPattern, currentTestFile, currentSourceMapConsumer, wrapperLineOffset, TEST_MODULE_EXTENSIONS, Expect, vi, beforeAllHooks, afterAllHooks, beforeEachHooks, afterEachHooks, beforeAll, afterAll, beforeEach, afterEach, globals;
55361
55369
  var init_test_runtime = __esm({
55362
55370
  "src/test-runtime.ts"() {
55363
55371
  "use strict";
@@ -55390,6 +55398,7 @@ var init_test_runtime = __esm({
55390
55398
  currentTestFile = void 0;
55391
55399
  currentSourceMapConsumer = void 0;
55392
55400
  wrapperLineOffset = 0;
55401
+ TEST_MODULE_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
55393
55402
  Expect = class _Expect {
55394
55403
  constructor(actual, isNot = false, isAsync = false) {
55395
55404
  this.actual = actual;
@@ -74875,7 +74884,7 @@ function readLineIgnorePatterns(filePath) {
74875
74884
  if (!(0, import_node_fs2.existsSync)(filePath)) {
74876
74885
  return [];
74877
74886
  }
74878
- return (0, import_node_fs2.readFileSync)(filePath, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
74887
+ return (0, import_node_fs2.readFileSync)(filePath, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && (!line.startsWith("#") || line.startsWith("\\#")));
74879
74888
  }
74880
74889
  function normalizePackageEntry(value) {
74881
74890
  const normalized = normalizeNonEmptyString(value)?.replace(/^[.][\\/]/, "").split("\\").join("/");
@@ -75056,23 +75065,103 @@ function resolveLinkedDependencyArchivePrefix(archivePrefix, dependencyName) {
75056
75065
  }
75057
75066
  return `${normalizedPrefix.slice(0, markerIndex + marker.length)}${dependencyName}`;
75058
75067
  }
75059
- function shouldIgnore(relativePath2, ignorePatterns) {
75060
- const pathParts = relativePath2.split("/");
75061
- for (const pattern of ignorePatterns) {
75062
- if (relativePath2 === pattern || pathParts.includes(pattern)) {
75063
- return true;
75064
- }
75065
- if (pattern.endsWith("*")) {
75066
- const prefix = pattern.slice(0, -1);
75067
- if (relativePath2.startsWith(prefix) || pathParts.some((part) => part.startsWith(prefix))) {
75068
- return true;
75068
+ function escapeRegex(text) {
75069
+ return text.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
75070
+ }
75071
+ function globPatternToRegex(pattern, options = {}) {
75072
+ let regex = "";
75073
+ for (let index = 0; index < pattern.length; index++) {
75074
+ const char = pattern[index];
75075
+ if (char === "*") {
75076
+ const nextChar = pattern[index + 1];
75077
+ const nextNextChar = pattern[index + 2];
75078
+ if (nextChar === "*") {
75079
+ if (nextNextChar === "/") {
75080
+ regex += "(?:.*?/)?";
75081
+ index += 2;
75082
+ continue;
75083
+ }
75084
+ regex += ".*";
75085
+ index += 1;
75086
+ continue;
75069
75087
  }
75088
+ regex += "[^/]*";
75089
+ continue;
75070
75090
  }
75071
- if (pattern.startsWith("*.") && relativePath2.endsWith(pattern.slice(1))) {
75072
- return true;
75091
+ if (char === "?") {
75092
+ regex += "[^/]";
75093
+ continue;
75073
75094
  }
75095
+ regex += escapeRegex(char);
75074
75096
  }
75075
- return false;
75097
+ const suffix = options.directoryOnly ? "(?:$|/.*)" : "$";
75098
+ const prefix = options.matchSegmentsOnly ? "^(?:.*?/)?" : "^";
75099
+ return new RegExp(`${prefix}${regex}${suffix}`);
75100
+ }
75101
+ function normalizeIgnorePattern(pattern) {
75102
+ let normalizedPattern = pattern.trim();
75103
+ if (!normalizedPattern) {
75104
+ return void 0;
75105
+ }
75106
+ let negate = false;
75107
+ if (normalizedPattern.startsWith("\\!") || normalizedPattern.startsWith("\\#")) {
75108
+ normalizedPattern = normalizedPattern.slice(1);
75109
+ } else if (normalizedPattern.startsWith("!")) {
75110
+ negate = true;
75111
+ normalizedPattern = normalizedPattern.slice(1).trim();
75112
+ }
75113
+ if (!normalizedPattern) {
75114
+ return void 0;
75115
+ }
75116
+ const directoryOnly = normalizedPattern.endsWith("/");
75117
+ if (directoryOnly) {
75118
+ normalizedPattern = normalizedPattern.replace(/\/+$/, "");
75119
+ }
75120
+ normalizedPattern = normalizedPattern.replace(/^\.\//, "").replace(/^\//, "").replace(/\\/g, "/");
75121
+ if (!normalizedPattern) {
75122
+ return void 0;
75123
+ }
75124
+ return {
75125
+ directoryOnly,
75126
+ matchSegmentsOnly: !normalizedPattern.includes("/"),
75127
+ negate,
75128
+ pattern: normalizedPattern
75129
+ };
75130
+ }
75131
+ function matchesIgnorePattern(relativePath2, pattern, isDirectory) {
75132
+ const normalizedRule = normalizeIgnorePattern(pattern);
75133
+ if (!normalizedRule) {
75134
+ return false;
75135
+ }
75136
+ if (normalizedRule.directoryOnly && !isDirectory) {
75137
+ return false;
75138
+ }
75139
+ const hasGlob = /[*?]/.test(normalizedRule.pattern);
75140
+ if (!hasGlob) {
75141
+ if (normalizedRule.matchSegmentsOnly) {
75142
+ return relativePath2 === normalizedRule.pattern || relativePath2.split("/").includes(normalizedRule.pattern);
75143
+ }
75144
+ return relativePath2 === normalizedRule.pattern;
75145
+ }
75146
+ if (normalizedRule.matchSegmentsOnly) {
75147
+ const segmentRegex = globPatternToRegex(normalizedRule.pattern);
75148
+ return relativePath2.split("/").some((segment) => segmentRegex.test(segment));
75149
+ }
75150
+ return globPatternToRegex(normalizedRule.pattern, { directoryOnly: normalizedRule.directoryOnly }).test(relativePath2);
75151
+ }
75152
+ function shouldIgnore(relativePath2, ignorePatterns, isDirectory) {
75153
+ let ignored = false;
75154
+ for (const pattern of ignorePatterns) {
75155
+ const normalizedRule = normalizeIgnorePattern(pattern);
75156
+ if (!normalizedRule) {
75157
+ continue;
75158
+ }
75159
+ if (!matchesIgnorePattern(relativePath2, pattern, isDirectory)) {
75160
+ continue;
75161
+ }
75162
+ ignored = !normalizedRule.negate;
75163
+ }
75164
+ return ignored;
75076
75165
  }
75077
75166
  function collectFiles(directory, baseDirectory, ignorePatterns) {
75078
75167
  const files = [];
@@ -75080,7 +75169,7 @@ function collectFiles(directory, baseDirectory, ignorePatterns) {
75080
75169
  for (const entry of entries) {
75081
75170
  const fullPath = (0, import_node_path2.join)(directory, entry.name);
75082
75171
  const relativePath2 = (0, import_node_path2.relative)(baseDirectory, fullPath).split("\\").join("/");
75083
- if (shouldIgnore(relativePath2, ignorePatterns)) {
75172
+ if (shouldIgnore(relativePath2, ignorePatterns, entry.isDirectory())) {
75084
75173
  continue;
75085
75174
  }
75086
75175
  if (entry.isSymbolicLink()) {
@@ -76483,7 +76572,7 @@ function printWapkHelp() {
76483
76572
  "",
76484
76573
  "Notes:",
76485
76574
  " - Pack reads wapk from elit.config.* and falls back to package.json.",
76486
- " - Pack includes node_modules by default; use .wapkignore if you need to exclude them.",
76575
+ " - Pack includes node_modules by default; use .wapkignore if you need to exclude them, and !pattern to re-include later matches.",
76487
76576
  " - Run never installs dependencies automatically; archives must include the runtime dependencies they need.",
76488
76577
  " - Run mode can read config.wapk.run for default file/runtime/live-sync options.",
76489
76578
  " - Browser-style archives with scripts.start or wapk.script.start run that start script automatically.",