Skip to content

Commit 8a3083c

Browse files
authored
Merge branch 'main' into refactor/node-test
2 parents 4dcc0ba + 47802de commit 8a3083c

File tree

6 files changed

+433
-31
lines changed

6 files changed

+433
-31
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
name: Node Unit Tests
12
on:
23
push:
34
branches-ignore:
@@ -8,14 +9,15 @@ jobs:
89
strategy:
910
matrix:
1011
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
11-
node: ["16", "18", "20"]
12+
node: ["16", "18", "20", "22"]
1213
name: Node.js ${{ matrix.node }} on ${{ matrix.os }}
1314
steps:
14-
- uses: actions/checkout@v3
15+
- uses: actions/checkout@v4
1516
- name: Setup node
16-
uses: actions/setup-node@v3
17+
uses: actions/setup-node@v4
1718
with:
1819
node-version: ${{ matrix.node }}
20+
# cache: npm
1921
- run: npm install
2022
- run: npm test
2123
env:

index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
const TemplatePath = require("./src/TemplatePath.js");
22
const isPlainObject = require("./src/IsPlainObject.js");
3+
const Merge = require("./src/Merge.js");
4+
const { DeepCopy } = Merge;
35

46
module.exports = {
57
TemplatePath,
68
isPlainObject,
9+
Merge,
10+
DeepCopy,
711
};

package.json

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
{
22
"name": "@11ty/eleventy-utils",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"description": "Low level internal utilities to be shared amongst Eleventy projects",
55
"main": "index.js",
6+
"files": [
7+
"src",
8+
"src/**",
9+
"index.js",
10+
"!test",
11+
"!test/**"
12+
],
613
"scripts": {
714
"test": "node --test"
815
},
@@ -30,8 +37,5 @@
3037
"url": "git://github.com/11ty/eleventy-utils.git"
3138
},
3239
"bugs": "https://github.com/11ty/eleventy-utils/issues",
33-
"homepage": "https://github.com/11ty/eleventy-utils/",
34-
"dependencies": {
35-
"normalize-path": "^3.0.0"
36-
}
40+
"homepage": "https://github.com/11ty/eleventy-utils/"
3741
}

src/Merge.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
"use strict";
2+
// above is required for Object.freeze to fail correctly.
3+
4+
const isPlainObject = require("./IsPlainObject.js");
5+
6+
const OVERRIDE_PREFIX = "override:";
7+
8+
function cleanKey(key, prefix) {
9+
if (prefix && key.startsWith(prefix)) {
10+
return key.slice(prefix.length);
11+
}
12+
return key;
13+
}
14+
15+
function getMergedItem(target, source, prefixes = {}) {
16+
let { override } = prefixes;
17+
18+
// Shortcut for frozen source (if target does not exist)
19+
if (!target && isPlainObject(source) && Object.isFrozen(source)) {
20+
return source;
21+
}
22+
23+
let sourcePlainObjectShortcut;
24+
if (!target && isPlainObject(source)) {
25+
// deep copy objects to avoid sharing and to effect key renaming
26+
target = {};
27+
sourcePlainObjectShortcut = true;
28+
}
29+
30+
if (Array.isArray(target) && Array.isArray(source)) {
31+
return target.concat(source);
32+
} else if (isPlainObject(target)) {
33+
if (sourcePlainObjectShortcut || isPlainObject(source)) {
34+
for (let key in source) {
35+
let overrideKey = cleanKey(key, override);
36+
37+
// An error happens here if the target is frozen
38+
target[overrideKey] = getMergedItem(target[key], source[key], prefixes);
39+
}
40+
}
41+
return target;
42+
}
43+
// number, string, class instance, etc
44+
return source;
45+
}
46+
47+
// The same as Merge but without override prefixes
48+
function DeepCopy(targetObject, ...sources) {
49+
for (let source of sources) {
50+
if (!source) {
51+
continue;
52+
}
53+
54+
targetObject = getMergedItem(targetObject, source);
55+
}
56+
return targetObject;
57+
}
58+
59+
function Merge(target, ...sources) {
60+
// Remove override prefixes from root target.
61+
if (isPlainObject(target)) {
62+
for (let key in target) {
63+
if (key.indexOf(OVERRIDE_PREFIX) === 0) {
64+
target[key.slice(OVERRIDE_PREFIX.length)] = target[key];
65+
delete target[key];
66+
}
67+
}
68+
}
69+
70+
for (let source of sources) {
71+
if (!source) {
72+
continue;
73+
}
74+
75+
target = getMergedItem(target, source, {
76+
override: OVERRIDE_PREFIX,
77+
});
78+
}
79+
80+
return target;
81+
}
82+
83+
module.exports = Merge;
84+
module.exports.DeepCopy = DeepCopy;

src/TemplatePath.js

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
const path = require("path");
2-
const normalize = require("normalize-path");
32
const fs = require("fs");
43

54
function TemplatePath() {}
@@ -15,7 +14,7 @@ TemplatePath.getWorkingDir = function () {
1514
* Returns the directory portion of a path.
1615
* Works for directory and file paths and paths ending in a glob pattern.
1716
*
18-
* @param {String} path A path
17+
* @param {String} path - A path
1918
* @returns {String} the directory portion of a path.
2019
*/
2120
TemplatePath.getDir = function (path) {
@@ -34,8 +33,8 @@ TemplatePath.getDir = function (path) {
3433
*
3534
* [1]: https://nodejs.org/api/path.html#path_path_parse_path
3635
*
37-
* @param {String} path A path
3836
* @returns {String} the directory portion of a path.
37+
* @param {String} filePath - A path
3938
*/
4039
TemplatePath.getDirFromFilePath = function (filePath) {
4140
return path.parse(filePath).dir || ".";
@@ -48,7 +47,7 @@ TemplatePath.getDirFromFilePath = function (filePath) {
4847
*
4948
* [1]: https://nodejs.org/api/path.html#path_path_parse_path
5049
*
51-
* @param {String} path A path
50+
* @param {String} path - A path
5251
* @returns {String} the last path segment in a path
5352
*/
5453
TemplatePath.getLastPathSegment = function (path) {
@@ -59,11 +58,11 @@ TemplatePath.getLastPathSegment = function (path) {
5958
// Trim a trailing slash if there is one
6059
path = path.replace(/\/$/, "");
6160

62-
return path.substr(path.lastIndexOf("/") + 1);
61+
return path.slice(path.lastIndexOf("/") + 1);
6362
};
6463

6564
/**
66-
* @param {String} path A path
65+
* @param {String} path - A path
6766
* @returns {String[]} an array of paths pointing to each path segment of the
6867
* provided `path`.
6968
*/
@@ -89,34 +88,37 @@ TemplatePath.getAllDirs = function (path) {
8988
*
9089
* [1]: https://nodejs.org/api/path.html#path_path_normalize_path
9190
*
92-
* @param {String} thePath The path that should be normalized.
91+
* @param {String} thePath - The path that should be normalized.
9392
* @returns {String} the normalized path.
9493
*/
9594
TemplatePath.normalize = function (thePath) {
96-
return normalize(path.normalize(thePath));
95+
let filePath = path.normalize(thePath).split(path.sep).join("/");
96+
if(filePath !== "/" && filePath.endsWith("/")) {
97+
return filePath.slice(0, -1);
98+
}
99+
return filePath;
97100
};
98101

99102
/**
100103
* Joins all given path segments together.
101104
*
102-
* It uses Node.js’ [`path.join`][1] method and the [normalize-path][2] package.
105+
* It uses Node.js’ [`path.join`][1] method.
103106
*
104107
* [1]: https://nodejs.org/api/path.html#path_path_join_paths
105-
* [2]: https://www.npmjs.com/package/normalize-path
106108
*
107-
* @param {String[]} paths An arbitrary amount of path segments.
109+
* @param {...String} paths - An arbitrary amount of path segments.
108110
* @returns {String} the normalized and joined path.
109111
*/
110112
TemplatePath.join = function (...paths) {
111-
return normalize(path.join(...paths));
113+
return TemplatePath.normalize(path.join(...paths));
112114
};
113115

114116
/**
115117
* Joins the given URL path segments and normalizes the resulting path.
116118
* Maintains a single trailing slash if the last URL path argument
117119
* had at least one.
118120
*
119-
* @param {String[]} urlPaths
121+
* @param {...String} urlPaths
120122
* @returns {String} a normalized URL path described by the given URL path segments.
121123
*/
122124
TemplatePath.normalizeUrlPath = function (...urlPaths) {
@@ -128,7 +130,7 @@ TemplatePath.normalizeUrlPath = function (...urlPaths) {
128130
* Joins the given path segments. Since the first path is absolute,
129131
* the resulting path will be absolute as well.
130132
*
131-
* @param {String[]} paths
133+
* @param {...String} paths
132134
* @returns {String} the absolute path described by the given path segments.
133135
*/
134136
TemplatePath.absolutePath = function (...paths) {
@@ -180,7 +182,7 @@ TemplatePath.addLeadingDotSlashArray = function (paths) {
180182
/**
181183
* Adds a leading dot-slash segment to `path`.
182184
*
183-
* @param {String} path
185+
* @param {String} pathArg
184186
* @returns {String}
185187
*/
186188
TemplatePath.addLeadingDotSlash = function (pathArg) {
@@ -212,8 +214,8 @@ TemplatePath.stripLeadingDotSlash = function (path) {
212214
/**
213215
* Determines whether a path starts with a given sub path.
214216
*
215-
* @param {String} path A path
216-
* @param {String} subPath A path
217+
* @param {String} path - A path
218+
* @param {String} subPath - A path
217219
* @returns {Boolean} whether `path` starts with `subPath`.
218220
*/
219221
TemplatePath.startsWithSubPath = function (path, subPath) {
@@ -227,31 +229,31 @@ TemplatePath.startsWithSubPath = function (path, subPath) {
227229
* Removes the `subPath` at the start of `path` if present
228230
* and returns the remainding path.
229231
*
230-
* @param {String} path A path
231-
* @param {String} subPath A path
232+
* @param {String} path - A path
233+
* @param {String} subPath - A path
232234
* @returns {String} the `path` without `subPath` at the start of it.
233235
*/
234236
TemplatePath.stripLeadingSubPath = function (path, subPath) {
235237
path = TemplatePath.normalize(path);
236238
subPath = TemplatePath.normalize(subPath);
237239

238240
if (subPath !== "." && path.startsWith(subPath)) {
239-
return path.substr(subPath.length + 1);
241+
return path.slice(subPath.length + 1);
240242
}
241243

242244
return path;
243245
};
244246

245247
/**
246-
* @param {String} path A path
248+
* @param {String} path - A path
247249
* @returns {Boolean} whether `path` points to an existing directory.
248250
*/
249251
TemplatePath.isDirectorySync = function (path) {
250252
return fs.existsSync(path) && fs.statSync(path).isDirectory();
251253
};
252254

253255
/**
254-
* @param {String} path A path
256+
* @param {String} path - A path
255257
* @returns {Boolean} whether `path` points to an existing directory.
256258
*/
257259
TemplatePath.isDirectory = async function (path) {
@@ -325,7 +327,7 @@ TemplatePath.getExtension = function (thePath) {
325327
* Removes the extension from a path.
326328
*
327329
* @param {String} path
328-
* @param {String} extension
330+
* @param {String} [extension]
329331
* @returns {String}
330332
*/
331333
TemplatePath.removeExtension = function (path, extension = undefined) {
@@ -347,6 +349,7 @@ TemplatePath.removeExtension = function (path, extension = undefined) {
347349
* e.g. `./my/dir/` stays `./my/dir/` on *nix and becomes `.\\my\\dir\\` on Windows
348350
*
349351
* @param {String} filePath
352+
* @param {String} [sep="/"]
350353
* @returns {String} a file path with the correct local directory separator.
351354
*/
352355
TemplatePath.normalizeOperatingSystemFilePath = function (filePath, sep = "/") {
@@ -359,6 +362,7 @@ TemplatePath.normalizeOperatingSystemFilePath = function (filePath, sep = "/") {
359362
* e.g. `./my/dir/` stays `./my/dir/` on *nix and becomes `.\\my\\dir\\` on Windows
360363
*
361364
* @param {String} filePath
365+
* @param {String} [sep="/"]
362366
* @returns {String} a file path with the correct local directory separator.
363367
*/
364368
TemplatePath.standardizeFilePath = function (filePath, sep = "/") {

0 commit comments

Comments
 (0)