@cldmv/wisp 1.0.0 → 1.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cldmv/wisp",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Version-agnostic JSON importing for Node.js with fallback handling and caller path resolution.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -135,11 +135,26 @@ export function getStack(skipFn) {
135
135
  const THIS_FILE = fileURLToPath(import.meta.url);
136
136
  const THIS_DIR = path.dirname(THIS_FILE);
137
137
 
138
+ // Find the package root by looking for package.json
139
+ function findPackageRoot(startPath) {
140
+ let currentPath = startPath;
141
+ while (currentPath !== path.dirname(currentPath)) {
142
+ const packageJsonPath = path.join(currentPath, "package.json");
143
+ if (fs.existsSync(packageJsonPath)) {
144
+ return currentPath;
145
+ }
146
+ currentPath = path.dirname(currentPath);
147
+ }
148
+ return null;
149
+ }
150
+
151
+ const PACKAGE_ROOT = findPackageRoot(THIS_FILE);
152
+
138
153
  /* ---------- base selection (shared) ---------- */
139
- // Rule you specified:
140
- // 1) Find the LAST frame whose basename is "slothlet.mjs".
141
- // 2) Take the NEXT frame; if its basename is "index.[mjs|cjs|js]", take the following one.
142
- // 3) Fallback: first non-helper frame that isn’t slothlet.mjs.
154
+ // Two-flag state machine for detecting when we've exited package infrastructure:
155
+ // 1) Flag 1: Set when we exit src/ or dist/ directories
156
+ // 2) Flag 2: Set when we exit index.* entry point files
157
+ // 3) Once both flags are set, we've found the actual caller outside the package
143
158
 
144
159
  /**
145
160
  * @function pickPrimaryBaseFile
@@ -148,51 +163,71 @@ const THIS_DIR = path.dirname(THIS_FILE);
148
163
  * @returns {string|null} Primary base file path for resolution, null if detection fails
149
164
  *
150
165
  * @description
151
- * Find the primary base file using stack trace analysis.
152
- * Implements sophisticated caller detection algorithm designed for slothlet's module loading patterns.
153
- * Uses a two-phase approach: locate the last slothlet.mjs frame, then find the actual user code.
166
+ * Find the primary base file using stack trace analysis with a two-flag state machine.
167
+ * Tracks when we **exit** from package infrastructure directories/files.
154
168
  *
155
169
  * Algorithm:
156
- * 1. Scan stack trace to find the LAST frame whose basename is "slothlet.mjs"
157
- * 2. Take the NEXT frame after slothlet.mjs
158
- * 3. If that frame is "index.[mjs|cjs|js]", take the following frame instead
159
- * 4. Return null if no suitable frame found (fallback will be used)
160
- *
161
- * This pattern handles slothlet's loading chain: slothlet.mjs → index.mjs → user-code.mjs
170
+ * 1. Walk stack trace backwards (from deepest to shallowest calls)
171
+ * 2. Flag 1: Set when we exit src/ or dist/ folder (transition from src/dist to non-src/dist)
172
+ * 3. Flag 2: Set when we exit index.* files (transition from index.* to non-index.*)
173
+ * 4. Once both flags are set, we've fully exited the package infrastructure
174
+ * 5. Return the current file as the actual caller
162
175
  *
163
176
  * @example
164
- * // Stack trace scenario:
165
- * // 0: pickPrimaryBaseFile() [this function]
166
- * // 1: resolveWith() [internal helper]
167
- * // 2: resolvePathFromCaller() [public API]
168
- * // 3: slothlet.mjs [slothlet loader] ← LAST slothlet.mjs
169
- * // 4: index.mjs [entry point] ← Skip this
170
- * // 5: user-code.mjs [actual caller] ← Return this
177
+ * // Stack trace flow (wisp example):
178
+ * // 0: src/lib/resolve-from-caller.mjs [in src/]
179
+ * // 1: src/wisp.mjs [still in src/]
180
+ * // 2: index.mjs [exited src/ - Flag 1 set]
181
+ * // 3: user-code.mjs [exited index.* - Flag 2 set, return this!]
171
182
  */
172
183
  function pickPrimaryBaseFile() {
173
- const files = [];
184
+ let exitedSrcOrDist = false; // Flag 1: Have we exited src/ or dist/?
185
+ let exitedIndex = false; // Flag 2: Have we exited index.*?
186
+ let previousWasInSrcOrDist = false;
187
+ let previousWasIndex = false;
188
+
174
189
  for (const cs of getStack(pickPrimaryBaseFile)) {
175
190
  const f = toFsPath(cs?.getFileName?.());
176
191
  if (!f) continue;
177
192
  if (f.startsWith?.("node:internal")) continue;
178
- files.push(f);
179
- }
193
+ if (f === THIS_FILE) continue;
180
194
 
181
- let iSloth = -1;
182
- for (let i = 0; i < files.length; i++) {
183
- if (path.basename(files[i]).toLowerCase() === "slothlet.mjs") iSloth = i;
184
- }
185
- if (iSloth !== -1) {
186
- const j = iSloth + 1;
187
- if (j < files.length) {
188
- const b = path.basename(files[j]).toLowerCase();
189
- if (/^index\.(mjs|cjs|js)$/.test(b) && j + 1 < files.length) return files[j + 1];
190
- return files[j];
195
+ let currentIsInSrcOrDist = false;
196
+ let currentIsIndex = false;
197
+
198
+ // Check if this file is in our package
199
+ if (PACKAGE_ROOT && f.startsWith(PACKAGE_ROOT + path.sep)) {
200
+ const relativePath = path.relative(PACKAGE_ROOT, f);
201
+ const segments = relativePath.split(path.sep);
202
+
203
+ // Check if current file is in src/ or dist/
204
+ currentIsInSrcOrDist = segments[0] === "src" || segments[0] === "dist";
205
+
206
+ // Check if current file is index.*
207
+ currentIsIndex = segments.length === 1 && /^index\.(mjs|cjs|js|ts)$/.test(segments[0]);
191
208
  }
209
+
210
+ // Flag 1: Check if we've exited src/dist (was in, now not in)
211
+ if (previousWasInSrcOrDist && !currentIsInSrcOrDist) {
212
+ exitedSrcOrDist = true;
213
+ }
214
+
215
+ // Flag 2: Check if we've exited index.* (was index, now not index)
216
+ if (previousWasIndex && !currentIsIndex) {
217
+ exitedIndex = true;
218
+ }
219
+
220
+ // If we've exited src/dist, we've found the caller (index.mjs might be optimized away)
221
+ if (exitedSrcOrDist) {
222
+ return f;
223
+ }
224
+
225
+ // Update previous state for next iteration
226
+ previousWasInSrcOrDist = currentIsInSrcOrDist;
227
+ previousWasIndex = currentIsIndex;
192
228
  }
193
229
  return null;
194
230
  }
195
-
196
231
  /**
197
232
  * @function pickFallbackBaseFile
198
233
  * @internal
@@ -222,13 +257,12 @@ function pickPrimaryBaseFile() {
222
257
  * // - Direct API usage without slothlet loader
223
258
  */
224
259
  function pickFallbackBaseFile() {
260
+ // Use simpler fallback logic - just find first non-Node.js-internal file
225
261
  for (const cs of getStack(pickFallbackBaseFile)) {
226
262
  const f = toFsPath(cs?.getFileName?.());
227
263
  if (!f) continue;
228
264
  if (f.startsWith?.("node:internal")) continue;
229
265
  if (f === THIS_FILE) continue;
230
- if (f.startsWith(THIS_DIR + path.sep)) continue; // helper’s own dir
231
- if (path.basename(f).toLowerCase() === "slothlet.mjs") continue;
232
266
  return f;
233
267
  }
234
268
  return THIS_FILE;
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-from-caller.d.mts","sourceRoot":"","sources":["../../src/lib/resolve-from-caller.mjs"],"names":[],"mappings":"AAqFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,6CAhCa,KAAK,CAAC,QAAQ,CAAC,CA0C3B;AAqKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,2CAzCW,MAAM,GACJ,MAAM,CAsDlB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,0CA1CW,MAAM,GACJ,MAAM,CAuDlB;AA/UM,4BAvBI,GAAG,GACD,MAAM,GAAC,IAAI,CAsB+F;;iBAmVzG,MAAY,MAAM,GAAC,SAAS;mBAC5B,MAAY,MAAM,GAAC,SAAS;qBAC5B,MAAY,MAAM,GAAC,SAAS;iBAC5B,MAAY,MAAM,GAAC,SAAS;mBAC5B,MAAY,MAAM,GAAC,SAAS;8BAC5B,MAAY,MAAM,GAAC,SAAS;qBAC5B,MAAY,MAAM,GAAC,SAAS;cAC5B,MAAY,OAAO,GAAC,SAAS;YAC7B,MAAY,OAAO,GAAC,SAAS;mBAC7B,MAAY,OAAO,GAAC,SAAS;gBAC7B,MAAY,OAAO,GAAC,SAAS;aAC7B,MAAY,OAAO,GAAC,SAAS;kBAC7B,MAAY,OAAO,GAAC,SAAS;qBAC7B,MAAY,MAAM,GAAC,SAAS"}
1
+ {"version":3,"file":"resolve-from-caller.d.mts","sourceRoot":"","sources":["../../src/lib/resolve-from-caller.mjs"],"names":[],"mappings":"AAqFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,6CAhCa,KAAK,CAAC,QAAQ,CAAC,CA0C3B;AAuMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,2CAzCW,MAAM,GACJ,MAAM,CAsDlB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,0CA1CW,MAAM,GACJ,MAAM,CAuDlB;AAjXM,4BAvBI,GAAG,GACD,MAAM,GAAC,IAAI,CAsB+F;;iBAqXzG,MAAY,MAAM,GAAC,SAAS;mBAC5B,MAAY,MAAM,GAAC,SAAS;qBAC5B,MAAY,MAAM,GAAC,SAAS;iBAC5B,MAAY,MAAM,GAAC,SAAS;mBAC5B,MAAY,MAAM,GAAC,SAAS;8BAC5B,MAAY,MAAM,GAAC,SAAS;qBAC5B,MAAY,MAAM,GAAC,SAAS;cAC5B,MAAY,OAAO,GAAC,SAAS;YAC7B,MAAY,OAAO,GAAC,SAAS;mBAC7B,MAAY,OAAO,GAAC,SAAS;gBAC7B,MAAY,OAAO,GAAC,SAAS;aAC7B,MAAY,OAAO,GAAC,SAAS;kBAC7B,MAAY,OAAO,GAAC,SAAS;qBAC7B,MAAY,MAAM,GAAC,SAAS"}