Initial commit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+134
@@ -0,0 +1,134 @@
|
||||
# cross-dirname
|
||||
|
||||
[Node.js](https://nodejs.org) + [Gjs](https://gjs.guide/) + [Deno](https://deno.land/) module that returns the current script dirname and filename. Similar to `__dirname` and `__filename` but also works in CommonJs and ES modules.
|
||||
|
||||
## Installation
|
||||
|
||||
On Node.js and GJS you can install the package as with NPM:
|
||||
|
||||
```
|
||||
npm install cross-dirname --save
|
||||
```
|
||||
|
||||
On Deno you just need to import this package:
|
||||
|
||||
```ts
|
||||
import { getDirname, getFilename } from 'https://deno.land/x/cross_dirname/mod.ts';
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Please do not use `getDirname` and `getFilename` in nested other methods, instead always use them in the root of your file, otherwise it may return wrong results.
|
||||
|
||||
### Node.js ESM
|
||||
|
||||
```js
|
||||
// /path/to/the/script.mjs
|
||||
import { getDirname, getFilename } from 'cross-dirname'
|
||||
|
||||
console.log(getDirname()) // outputs "/path/to/the"
|
||||
console.log(getFilename()) // outputs "/path/to/the/script.mjs"
|
||||
```
|
||||
|
||||
### Node.js CJS
|
||||
|
||||
```js
|
||||
// /path/to/the/script.cjs
|
||||
const { getDirname, getFilename } = require('cross-dirname');
|
||||
|
||||
console.log(getDirname() === __dirname) // true
|
||||
console.log(getFilename() === __filename) // true
|
||||
```
|
||||
|
||||
### Deno
|
||||
|
||||
```ts
|
||||
// /path/to/the/script.ts
|
||||
import { getDirname, getFilename } from 'https://deno.land/x/cross_dirname@v0.0.4/mod.ts';
|
||||
|
||||
console.log(getDirname()); // outputs "/path/to/the"
|
||||
console.log(getFilename()); // outputs "/path/to/the/script.ts"
|
||||
```
|
||||
|
||||
### GJS
|
||||
|
||||
You can use NPM packages in GJS with a bundler like [esbuild](https://esbuild.github.io/).
|
||||
|
||||
Take a look at the examples for an [GJS + esbuild example](/examples/gjs), you can start the example like this:
|
||||
|
||||
```bash
|
||||
# Install dev dependencies
|
||||
npm install
|
||||
|
||||
# Go to the example
|
||||
cd examples/gjs
|
||||
|
||||
# Bundle src/index.js
|
||||
node esbuild.mjs
|
||||
|
||||
# Run the bundled index.js
|
||||
gjs -m index.js
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
You can run the examples with
|
||||
|
||||
```bash
|
||||
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
deno run ./examples/deno/index.ts
|
||||
# -> /.../examples/deno
|
||||
|
||||
node ./examples/node/index.cjs
|
||||
# -> /.../examples/node
|
||||
|
||||
node ./examples/node/index.mjs
|
||||
# -> /.../examples/node
|
||||
|
||||
node ./examples/gjs/esbuild.mjs
|
||||
gjs -m ./examples/gjs/index.js
|
||||
# -> /.../examples/gjs
|
||||
```
|
||||
|
||||
### Contributions
|
||||
|
||||
Contributions for more platforms are welcome :)
|
||||
|
||||
### Tests
|
||||
|
||||
This module has been tested on the following platforms:
|
||||
|
||||
| Runtime | Type | Platform | State |
|
||||
|---------|--------|----------|----------|
|
||||
| Node.js | CJS | Linux | ✔ |
|
||||
| Node.js | CJS | MacOS | ✔ |
|
||||
| Node.js | CJS | Windows | ✔ |
|
||||
| Node.js | ESM | Linux | ✔ |
|
||||
| Node.js | ESM | MacOS | ✔ |
|
||||
| Node.js | ESM | Windows | ✔ |
|
||||
| Deno | ESM | Linux | ✔ |
|
||||
| Deno | ESM | MacOS | ✔ |
|
||||
| Deno | ESM | Windows | ✔ |
|
||||
| Gjs | ESM | Linux | ✔ |
|
||||
| Gjs | ESM | MacOS | UNTESTED |
|
||||
| Gjs | ESM | Windows | UNTESTED |
|
||||
| Chrome | ESM | Browser | ✔ |
|
||||
| Chrome | CJS | Browser | ✔ |
|
||||
|
||||
You can run all tests with:
|
||||
|
||||
```
|
||||
npm run test
|
||||
```
|
||||
|
||||
Or the tests for a special runtime:
|
||||
|
||||
```
|
||||
npm run test:node
|
||||
npm run test:deno
|
||||
npm run test:gjs
|
||||
npm run test:browser´
|
||||
```
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getFilename = exports.getDirname = void 0;
|
||||
const DIRNAME_POSIX_REGEX = /^((?:\.(?![^\/]))|(?:(?:\/?|)(?:[\s\S]*?)))(?:\/+?|)(?:(?:\.{1,2}|[^\/]+?|)(?:\.[^.\/]*|))(?:[\/]*)$/;
|
||||
const DIRNAME_WIN32_REGEX = /^((?:\.(?![^\\]))|(?:(?:\\?|)(?:[\s\S]*?)))(?:\\+?|)(?:(?:\.{1,2}|[^\\]+?|)(?:\.[^.\\]*|))(?:[\\]*)$/;
|
||||
const EXTRACT_PATH_REGEX = /@?(?<path>[file:\/\/]?[^\(\s]+):[0-9]+:[0-9]+/;
|
||||
const WIN_POSIX_DRIVE_REGEX = /^\/[A-Z]:\/*/;
|
||||
const pathDirname = (path) => {
|
||||
let dirname = DIRNAME_POSIX_REGEX.exec(path)?.[1];
|
||||
if (!dirname) {
|
||||
dirname = DIRNAME_WIN32_REGEX.exec(path)?.[1];
|
||||
}
|
||||
if (!dirname) {
|
||||
throw new Error(`Can't extract dirname from ${path}`);
|
||||
}
|
||||
return dirname;
|
||||
};
|
||||
const getPathFromErrorStack = () => {
|
||||
let path = '';
|
||||
const stack = new Error().stack;
|
||||
if (!stack) {
|
||||
console.warn("Error has no stack!");
|
||||
return path;
|
||||
}
|
||||
// Node.js
|
||||
let initiator = stack.split('\n').slice(4, 5)[0];
|
||||
// Other
|
||||
if (!initiator) {
|
||||
initiator = stack.split('\n').slice(3, 4)[0];
|
||||
}
|
||||
if (initiator) {
|
||||
path = EXTRACT_PATH_REGEX.exec(initiator)?.groups?.path || '';
|
||||
}
|
||||
if (!initiator || !path) {
|
||||
console.warn("Can't get path from error stack!");
|
||||
}
|
||||
return path;
|
||||
};
|
||||
const getPath = () => {
|
||||
let path = getPathFromErrorStack();
|
||||
// Remove protocol
|
||||
const protocol = "file://";
|
||||
if (path.indexOf(protocol) >= 0) {
|
||||
path = path.slice(protocol.length);
|
||||
}
|
||||
// Transform to win32 path
|
||||
if (WIN_POSIX_DRIVE_REGEX.test(path)) {
|
||||
path = path.slice(1).replace(/\//g, '\\');
|
||||
}
|
||||
return path;
|
||||
};
|
||||
/**
|
||||
* Cross platform implementation for `__dirname`.
|
||||
*
|
||||
* @note Please do not use this method in nested other methods,
|
||||
* instead always use it in the root of your file, otherwise it may return wrong results.
|
||||
* @returns What `__dirname` would return in CJS
|
||||
*/
|
||||
const getDirname = () => {
|
||||
let path = getPath();
|
||||
const dirname = pathDirname(path);
|
||||
return dirname;
|
||||
};
|
||||
exports.getDirname = getDirname;
|
||||
/**
|
||||
* Cross platform implementation for `__filename`.
|
||||
*
|
||||
* @note Please do not use this method in nested other methods,
|
||||
* instead always use it in the root of your file, otherwise it may return wrong results.
|
||||
* @returns What `__filename` would return in CJS
|
||||
*/
|
||||
const getFilename = () => {
|
||||
let filename = getPath();
|
||||
return filename;
|
||||
};
|
||||
exports.getFilename = getFilename;
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
const DIRNAME_POSIX_REGEX = /^((?:\.(?![^\/]))|(?:(?:\/?|)(?:[\s\S]*?)))(?:\/+?|)(?:(?:\.{1,2}|[^\/]+?|)(?:\.[^.\/]*|))(?:[\/]*)$/;
|
||||
const DIRNAME_WIN32_REGEX = /^((?:\.(?![^\\]))|(?:(?:\\?|)(?:[\s\S]*?)))(?:\\+?|)(?:(?:\.{1,2}|[^\\]+?|)(?:\.[^.\\]*|))(?:[\\]*)$/;
|
||||
const EXTRACT_PATH_REGEX = /@?(?<path>[file:\/\/]?[^\(\s]+):[0-9]+:[0-9]+/;
|
||||
const WIN_POSIX_DRIVE_REGEX = /^\/[A-Z]:\/*/;
|
||||
const pathDirname = (path) => {
|
||||
let dirname = DIRNAME_POSIX_REGEX.exec(path)?.[1];
|
||||
if (!dirname) {
|
||||
dirname = DIRNAME_WIN32_REGEX.exec(path)?.[1];
|
||||
}
|
||||
if (!dirname) {
|
||||
throw new Error(`Can't extract dirname from ${path}`);
|
||||
}
|
||||
return dirname;
|
||||
};
|
||||
const getPathFromErrorStack = () => {
|
||||
let path = '';
|
||||
const stack = new Error().stack;
|
||||
if (!stack) {
|
||||
console.warn("Error has no stack!");
|
||||
return path;
|
||||
}
|
||||
// Node.js
|
||||
let initiator = stack.split('\n').slice(4, 5)[0];
|
||||
// Other
|
||||
if (!initiator) {
|
||||
initiator = stack.split('\n').slice(3, 4)[0];
|
||||
}
|
||||
if (initiator) {
|
||||
path = EXTRACT_PATH_REGEX.exec(initiator)?.groups?.path || '';
|
||||
}
|
||||
if (!initiator || !path) {
|
||||
console.warn("Can't get path from error stack!");
|
||||
}
|
||||
return path;
|
||||
};
|
||||
const getPath = () => {
|
||||
let path = getPathFromErrorStack();
|
||||
// Remove protocol
|
||||
const protocol = "file://";
|
||||
if (path.indexOf(protocol) >= 0) {
|
||||
path = path.slice(protocol.length);
|
||||
}
|
||||
// Transform to win32 path
|
||||
if (WIN_POSIX_DRIVE_REGEX.test(path)) {
|
||||
path = path.slice(1).replace(/\//g, '\\');
|
||||
}
|
||||
return path;
|
||||
};
|
||||
/**
|
||||
* Cross platform implementation for `__dirname`.
|
||||
*
|
||||
* @note Please do not use this method in nested other methods,
|
||||
* instead always use it in the root of your file, otherwise it may return wrong results.
|
||||
* @returns What `__dirname` would return in CJS
|
||||
*/
|
||||
export const getDirname = () => {
|
||||
let path = getPath();
|
||||
const dirname = pathDirname(path);
|
||||
return dirname;
|
||||
};
|
||||
/**
|
||||
* Cross platform implementation for `__filename`.
|
||||
*
|
||||
* @note Please do not use this method in nested other methods,
|
||||
* instead always use it in the root of your file, otherwise it may return wrong results.
|
||||
* @returns What `__filename` would return in CJS
|
||||
*/
|
||||
export const getFilename = () => {
|
||||
let filename = getPath();
|
||||
return filename;
|
||||
};
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Cross platform implementation for `__dirname`.
|
||||
*
|
||||
* @note Please do not use this method in nested other methods,
|
||||
* instead always use it in the root of your file, otherwise it may return wrong results.
|
||||
* @returns What `__dirname` would return in CJS
|
||||
*/
|
||||
export declare const getDirname: () => string;
|
||||
/**
|
||||
* Cross platform implementation for `__filename`.
|
||||
*
|
||||
* @note Please do not use this method in nested other methods,
|
||||
* instead always use it in the root of your file, otherwise it may return wrong results.
|
||||
* @returns What `__filename` would return in CJS
|
||||
*/
|
||||
export declare const getFilename: () => string;
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "cross-dirname",
|
||||
"version": "0.1.0",
|
||||
"type": "commonjs",
|
||||
"main": "./dist/cjs/index.cjs",
|
||||
"module": "./dist/esm/index.mjs",
|
||||
"types": "./dist/types/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"require": "./dist/cjs/index.cjs",
|
||||
"default": "./dist/esm/index.mjs"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"/dist"
|
||||
],
|
||||
"scripts": {
|
||||
"clear": "rm -rf dist",
|
||||
"build": "npm run clear && npm run build:cjs && npm run build:esm && npm run build:types",
|
||||
"build:cjs": "tsc && mv ./dist/cjs/index.js ./dist/cjs/index.cjs",
|
||||
"build:esm": "tsc --project tsconfig.esm.json && mv ./dist/esm/index.js ./dist/esm/index.mjs",
|
||||
"build:types": "tsc --project tsconfig.types.json",
|
||||
"test": "npm run test:node && npm run test:deno && npm run test:gjs && npm run test:browser",
|
||||
"test:node": "mocha test/node",
|
||||
"test:gjs": "node test/browser/esbuild.mjs && gjs -m ./test/gjs/base.test.mjs",
|
||||
"test:deno": "deno test ./test/deno/base.test.mjs",
|
||||
"test:browser": "npm run test:browser:esm && npm run test:browser:cjs",
|
||||
"test:browser:esm": "node test/browser/esbuild.mjs && mocha-headless-chrome --timeout 120000 --polling 1000 -f ./test/browser/index.html",
|
||||
"test:browser:cjs": "node test/browser/esbuild.cjs && mocha-headless-chrome --timeout 120000 --polling 1000 -f ./test/browser/index.html"
|
||||
},
|
||||
"keywords": [
|
||||
"dirname",
|
||||
"cross-platform",
|
||||
"esm",
|
||||
"cjs",
|
||||
"node",
|
||||
"deno",
|
||||
"gjs"
|
||||
],
|
||||
"url": "https://github.com/JumpLink/cross-dirname",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/JumpLink/cross-dirname.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.3.6",
|
||||
"cross-dirname": "^0.0.6",
|
||||
"esbuild": "^0.14.49",
|
||||
"esm": "^3.2.25",
|
||||
"mocha": "^10.0.0",
|
||||
"mocha-headless-chrome": "^4.0.0",
|
||||
"typescript": "^4.7.4"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user