@bgord/tools 0.15.1 → 0.16.0
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/basename.vo.d.ts +11 -2
- package/dist/basename.vo.js +22 -13
- package/dist/date-calculator.service.d.ts +2 -2
- package/dist/date-calculator.service.js +10 -11
- package/dist/date-range.vo.d.ts +1 -0
- package/dist/date-range.vo.js +2 -1
- package/dist/day-iso-id.vo.d.ts +3 -0
- package/dist/day-iso-id.vo.js +4 -4
- package/dist/day.vo.js +12 -10
- package/dist/directory-path-absolute.vo.d.ts +5 -0
- package/dist/directory-path-absolute.vo.js +11 -5
- package/dist/directory-path-relative.vo.d.ts +6 -0
- package/dist/directory-path-relative.vo.js +12 -6
- package/dist/dll.service.js +37 -31
- package/dist/extension.vo.d.ts +6 -2
- package/dist/extension.vo.js +11 -9
- package/dist/file-path-absolute-schema.vo.d.ts +5 -0
- package/dist/file-path-absolute-schema.vo.js +12 -6
- package/dist/file-path-relative-schema.vo.d.ts +6 -1
- package/dist/file-path-relative-schema.vo.js +10 -6
- package/dist/file-path.vo.js +4 -4
- package/dist/filename-from-string.vo.d.ts +6 -4
- package/dist/filename-from-string.vo.js +15 -14
- package/dist/filename-suffix.vo.d.ts +4 -2
- package/dist/filename-suffix.vo.js +5 -3
- package/dist/filename.vo.d.ts +2 -2
- package/dist/filename.vo.js +9 -9
- package/dist/height.vo.d.ts +6 -4
- package/dist/height.vo.js +56 -51
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/language.vo.d.ts +1 -1
- package/dist/language.vo.js +1 -2
- package/dist/mime.vo.d.ts +3 -1
- package/dist/mime.vo.js +8 -6
- package/dist/month-iso-id.vo.d.ts +3 -0
- package/dist/month-iso-id.vo.js +7 -12
- package/dist/month.vo.js +15 -13
- package/dist/object-key.vo.d.ts +5 -0
- package/dist/object-key.vo.js +16 -6
- package/dist/package-version.vo.d.ts +3 -0
- package/dist/package-version.vo.js +12 -34
- package/dist/pagination.service.d.ts +1 -1
- package/dist/pagination.service.js +11 -11
- package/dist/quarter-iso-id.vo.d.ts +3 -0
- package/dist/quarter-iso-id.vo.js +8 -7
- package/dist/rate-limiter.service.d.ts +3 -2
- package/dist/rate-limiter.service.js +4 -2
- package/dist/reordering.service.d.ts +20 -2
- package/dist/reordering.service.js +49 -29
- package/dist/revision.vo.d.ts +8 -3
- package/dist/revision.vo.js +13 -6
- package/dist/rounding.adapter.js +1 -2
- package/dist/size.vo.d.ts +1 -0
- package/dist/size.vo.js +4 -7
- package/dist/streak-calculator.service.d.ts +3 -4
- package/dist/streak-calculator.service.js +11 -17
- package/dist/time-zone-offset-value.vo.d.ts +1 -1
- package/dist/time-zone-offset-value.vo.js +1 -7
- package/dist/time.service.d.ts +11 -6
- package/dist/time.service.js +31 -18
- package/dist/timezone.vo.js +1 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/week-iso-id.vo.d.ts +3 -0
- package/dist/week-iso-id.vo.js +4 -4
- package/dist/week.vo.js +1 -1
- package/dist/weekday.vo.d.ts +7 -6
- package/dist/weekday.vo.js +20 -13
- package/dist/weight.vo.d.ts +12 -0
- package/dist/weight.vo.js +37 -27
- package/dist/year-iso-id.vo.d.ts +3 -0
- package/dist/year-iso-id.vo.js +4 -6
- package/dist/year.vo.d.ts +2 -0
- package/dist/year.vo.js +4 -2
- package/package.json +1 -1
- package/readme.md +0 -1
- package/src/basename.vo.ts +25 -14
- package/src/clock.vo.ts +1 -0
- package/src/date-calculator.service.ts +10 -15
- package/src/date-range.vo.ts +3 -1
- package/src/day-iso-id.vo.ts +9 -10
- package/src/day.vo.ts +17 -10
- package/src/directory-path-absolute.vo.ts +12 -5
- package/src/directory-path-relative.vo.ts +13 -6
- package/src/dll.service.ts +45 -43
- package/src/extension.vo.ts +14 -12
- package/src/file-path-absolute-schema.vo.ts +15 -6
- package/src/file-path-relative-schema.vo.ts +13 -6
- package/src/file-path.vo.ts +15 -11
- package/src/filename-from-string.vo.ts +20 -15
- package/src/filename-suffix.vo.ts +8 -4
- package/src/filename.vo.ts +14 -15
- package/src/height.vo.ts +71 -53
- package/src/index.ts +0 -1
- package/src/language.vo.ts +1 -2
- package/src/mime.vo.ts +10 -7
- package/src/month-iso-id.vo.ts +10 -20
- package/src/month.vo.ts +19 -13
- package/src/object-key.vo.ts +21 -7
- package/src/outlier-detector.service.ts +1 -0
- package/src/package-version.vo.ts +18 -47
- package/src/pagination.service.ts +15 -13
- package/src/quarter-iso-id.vo.ts +11 -13
- package/src/quarter.vo.ts +3 -0
- package/src/rate-limiter.service.ts +7 -7
- package/src/reordering.service.ts +52 -38
- package/src/revision.vo.ts +17 -8
- package/src/rounding.adapter.ts +1 -3
- package/src/size.vo.ts +6 -16
- package/src/streak-calculator.service.ts +12 -17
- package/src/time-zone-offset-value.vo.ts +2 -7
- package/src/time.service.ts +43 -45
- package/src/timezone.vo.ts +1 -3
- package/src/week-iso-id.vo.ts +13 -14
- package/src/week.vo.ts +4 -2
- package/src/weekday.vo.ts +27 -13
- package/src/weight.vo.ts +49 -30
- package/src/year-iso-id.vo.ts +6 -9
- package/src/year.vo.ts +12 -2
- package/dist/stepper.service.d.ts +0 -23
- package/dist/stepper.service.js +0 -33
- package/src/stepper.service.ts +0 -43
package/dist/basename.vo.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
export declare const
|
|
3
|
-
export
|
|
2
|
+
export declare const BasenameTypeError: "basename.not.string";
|
|
3
|
+
export declare const BasenameEmptyError: "basename.empty";
|
|
4
|
+
export declare const BasenameTooLongError: "basename.too.long";
|
|
5
|
+
export declare const BasenameSlashesForbiddenError: "basename.slashes.forbidden";
|
|
6
|
+
export declare const BasenameControlCharsForbiddenError: "basename.control.chars.forbidden";
|
|
7
|
+
export declare const BasenameDotSegmentsForbiddenError: "basename.dot.segments.forbidden";
|
|
8
|
+
export declare const BasenameDotfilesForbiddenError: "basename.dotfiles.forbidden";
|
|
9
|
+
export declare const BasenameTrailingDotForbiddenError: "basename.trailing.dot.forbidden";
|
|
10
|
+
export declare const BasenameBadCharsError: "basename.bad.chars";
|
|
11
|
+
export declare const Basename: z.core.$ZodBranded<z.ZodString, "Basename">;
|
|
12
|
+
export type BasenameType = z.infer<typeof Basename>;
|
package/dist/basename.vo.js
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
export const
|
|
3
|
-
|
|
2
|
+
export const BasenameTypeError = "basename.not.string";
|
|
3
|
+
export const BasenameEmptyError = "basename.empty";
|
|
4
|
+
export const BasenameTooLongError = "basename.too.long";
|
|
5
|
+
export const BasenameSlashesForbiddenError = "basename.slashes.forbidden";
|
|
6
|
+
export const BasenameControlCharsForbiddenError = "basename.control.chars.forbidden";
|
|
7
|
+
export const BasenameDotSegmentsForbiddenError = "basename.dot.segments.forbidden";
|
|
8
|
+
export const BasenameDotfilesForbiddenError = "basename.dotfiles.forbidden";
|
|
9
|
+
export const BasenameTrailingDotForbiddenError = "basename.trailing.dot.forbidden";
|
|
10
|
+
export const BasenameBadCharsError = "basename.bad.chars";
|
|
11
|
+
export const Basename = z
|
|
12
|
+
.string(BasenameTypeError)
|
|
4
13
|
.trim()
|
|
5
|
-
.min(1,
|
|
6
|
-
.max(128,
|
|
7
|
-
.refine((s) => !/[/\\]/.test(s),
|
|
14
|
+
.min(1, BasenameEmptyError)
|
|
15
|
+
.max(128, BasenameTooLongError)
|
|
16
|
+
.refine((s) => !/[/\\]/.test(s), BasenameSlashesForbiddenError)
|
|
17
|
+
// dot-related checks: dot-segments first for specific errors…
|
|
8
18
|
// biome-ignore lint: lint/suspicious/noControlCharactersInRegex
|
|
9
|
-
.refine((
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.refine((
|
|
14
|
-
.
|
|
15
|
-
.
|
|
16
|
-
.brand("basename");
|
|
19
|
+
.refine((value) => !/[\u0000-\u001F\u007F]/.test(value), BasenameControlCharsForbiddenError)
|
|
20
|
+
.refine((value) => value !== "." && value !== "..", BasenameDotSegmentsForbiddenError)
|
|
21
|
+
// …then any other dotfile
|
|
22
|
+
.refine((value) => !value.startsWith("."), BasenameDotfilesForbiddenError)
|
|
23
|
+
.refine((value) => !value.endsWith("."), BasenameTrailingDotForbiddenError)
|
|
24
|
+
.regex(/^[A-Za-z0-9._-]+$/, BasenameBadCharsError)
|
|
25
|
+
.brand("Basename");
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type TimestampType } from "./timestamp.vo";
|
|
2
2
|
type GetStartOfDayTsInTzConfigType = {
|
|
3
3
|
now: TimestampType;
|
|
4
4
|
timeZoneOffsetMs: number;
|
|
5
5
|
};
|
|
6
6
|
export declare class DateCalculator {
|
|
7
|
-
static getStartOfDayTsInTz(config: GetStartOfDayTsInTzConfigType):
|
|
7
|
+
static getStartOfDayTsInTz(config: GetStartOfDayTsInTzConfigType): TimestampType;
|
|
8
8
|
}
|
|
9
9
|
export {};
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { Time } from "./time.service";
|
|
2
|
+
import { Timestamp } from "./timestamp.vo";
|
|
2
3
|
export class DateCalculator {
|
|
3
4
|
static getStartOfDayTsInTz(config) {
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
return config.now - timeSinceNewDayInTimeZoneRelativeToUtcStartOfDay - Time.Days(1).ms;
|
|
5
|
+
const dayMs = Time.Days(1).ms;
|
|
6
|
+
// UTC midnight for the UTC date of `now`
|
|
7
|
+
const utcMidnight = Math.floor(config.now / dayMs) * dayMs;
|
|
8
|
+
// Candidate start of the local day (in UTC), anchored to the same UTC date
|
|
9
|
+
let start = utcMidnight + config.timeZoneOffsetMs;
|
|
10
|
+
// If the candidate is in the future relative to `now`, it means local midnight was "yesterday" in UTC.
|
|
11
|
+
if (start > config.now)
|
|
12
|
+
start -= dayMs;
|
|
13
|
+
return Timestamp.parse(start);
|
|
15
14
|
}
|
|
16
15
|
}
|
package/dist/date-range.vo.d.ts
CHANGED
package/dist/date-range.vo.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export const DateRangeInvalidError = "invalid.date.range";
|
|
1
2
|
export class DateRange {
|
|
2
3
|
start;
|
|
3
4
|
end;
|
|
@@ -5,7 +6,7 @@ export class DateRange {
|
|
|
5
6
|
this.start = start;
|
|
6
7
|
this.end = end;
|
|
7
8
|
if (start > end)
|
|
8
|
-
throw new Error(
|
|
9
|
+
throw new Error(DateRangeInvalidError);
|
|
9
10
|
}
|
|
10
11
|
getStart() {
|
|
11
12
|
return this.start;
|
package/dist/day-iso-id.vo.d.ts
CHANGED
package/dist/day-iso-id.vo.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { isValid, parseISO } from "date-fns";
|
|
2
2
|
import { z } from "zod/v4";
|
|
3
|
+
export const DayIsoIdError = { error: "invalid.day.iso.id" };
|
|
3
4
|
export const DayIsoId = z
|
|
4
|
-
.string()
|
|
5
|
-
|
|
6
|
-
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
5
|
+
.string(DayIsoIdError)
|
|
6
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/, DayIsoIdError)
|
|
7
7
|
.refine((value) => {
|
|
8
8
|
const date = parseISO(value);
|
|
9
9
|
return isValid(date) && value === date.toISOString().slice(0, 10);
|
|
10
|
-
},
|
|
10
|
+
}, DayIsoIdError);
|
package/dist/day.vo.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { addDays, endOfDay, startOfDay } from "date-fns";
|
|
2
1
|
import { DateRange } from "./date-range.vo";
|
|
3
2
|
import { DayIsoId } from "./day-iso-id.vo";
|
|
4
3
|
import { Time } from "./time.service";
|
|
@@ -8,31 +7,34 @@ export class Day extends DateRange {
|
|
|
8
7
|
super(start, end);
|
|
9
8
|
}
|
|
10
9
|
toIsoId() {
|
|
11
|
-
|
|
10
|
+
const midday = this.getStart() + Time.Hours(12).ms;
|
|
11
|
+
return new Date(midday).toISOString().slice(0, 10);
|
|
12
12
|
}
|
|
13
13
|
previous() {
|
|
14
|
-
const shifted =
|
|
14
|
+
const shifted = this.getStart() - Time.Days(1).ms;
|
|
15
15
|
return Day.fromTimestamp(Timestamp.parse(shifted));
|
|
16
16
|
}
|
|
17
17
|
next() {
|
|
18
|
-
const shifted =
|
|
18
|
+
const shifted = this.getStart() + Time.Days(1).ms;
|
|
19
19
|
return Day.fromTimestamp(Timestamp.parse(shifted));
|
|
20
20
|
}
|
|
21
21
|
shift(count) {
|
|
22
|
-
const shifted =
|
|
22
|
+
const shifted = this.getStart() + count * Time.Days(1).ms;
|
|
23
23
|
return Day.fromTimestamp(Timestamp.parse(shifted));
|
|
24
24
|
}
|
|
25
25
|
static fromTimestamp(timestamp) {
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
26
|
+
const date = new Date(timestamp);
|
|
27
|
+
const startUtc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
|
|
28
|
+
const endUtc = startUtc + Time.Days(1).ms - 1;
|
|
29
|
+
return new Day(Timestamp.parse(startUtc), Timestamp.parse(endUtc));
|
|
29
30
|
}
|
|
30
31
|
static fromNow(now) {
|
|
31
32
|
return Day.fromTimestamp(now);
|
|
32
33
|
}
|
|
33
34
|
static fromIsoId(isoId) {
|
|
34
35
|
const [year, month, day] = DayIsoId.parse(isoId).split("-").map(Number);
|
|
35
|
-
const
|
|
36
|
-
|
|
36
|
+
const startUtc = Date.UTC(year, month - 1, day);
|
|
37
|
+
const endUtc = startUtc + Time.Days(1).ms - 1;
|
|
38
|
+
return new Day(Timestamp.parse(startUtc), Timestamp.parse(endUtc));
|
|
37
39
|
}
|
|
38
40
|
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
+
export declare const AbsDirTypeError: "abs_dir.not.string";
|
|
3
|
+
export declare const AbsDirMustStartWithSlashError: "abs_dir_must_start_with_slash";
|
|
4
|
+
export declare const AbsDirBackslashForbiddenError: "abs_dir_backslash_forbidden";
|
|
5
|
+
export declare const AbsDirControlCharsForbiddenError: "abs_dir_control_chars_forbidden";
|
|
6
|
+
export declare const AbsDirBadSegmentsError: "abs_dir_bad_segments";
|
|
2
7
|
export declare const DirectoryPathAbsoluteSchema: z.core.$ZodBranded<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodTransform<string, string>>, "directory_path_absolute">;
|
|
3
8
|
export type DirectoryPathAbsoluteType = z.infer<typeof DirectoryPathAbsoluteSchema>;
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
+
export const AbsDirTypeError = "abs_dir.not.string";
|
|
3
|
+
export const AbsDirMustStartWithSlashError = "abs_dir_must_start_with_slash";
|
|
4
|
+
export const AbsDirBackslashForbiddenError = "abs_dir_backslash_forbidden";
|
|
5
|
+
export const AbsDirControlCharsForbiddenError = "abs_dir_control_chars_forbidden";
|
|
6
|
+
export const AbsDirBadSegmentsError = "abs_dir_bad_segments";
|
|
2
7
|
export const DirectoryPathAbsoluteSchema = z
|
|
3
|
-
.string()
|
|
8
|
+
.string(AbsDirTypeError)
|
|
4
9
|
.trim()
|
|
5
|
-
.refine((value) => value.startsWith("/"),
|
|
6
|
-
.refine((value) => !value.includes("\\"),
|
|
10
|
+
.refine((value) => value.startsWith("/"), AbsDirMustStartWithSlashError)
|
|
11
|
+
.refine((value) => !value.includes("\\"), AbsDirBackslashForbiddenError)
|
|
7
12
|
// biome-ignore lint: lint/suspicious/noControlCharactersInRegex
|
|
8
|
-
.refine((value) => !/[\u0000-\u001F\u007F]/.test(value),
|
|
13
|
+
.refine((value) => !/[\u0000-\u001F\u007F]/.test(value), AbsDirControlCharsForbiddenError)
|
|
14
|
+
// collapse duplicate slashes, then drop trailing slash unless it's the root "/"
|
|
9
15
|
.transform((value) => value.replace(/\/{2,}/g, "/"))
|
|
10
16
|
.transform((value) => (value !== "/" && value.endsWith("/") ? value.slice(0, -1) : value))
|
|
11
17
|
.refine((value) => {
|
|
@@ -13,5 +19,5 @@ export const DirectoryPathAbsoluteSchema = z
|
|
|
13
19
|
return true;
|
|
14
20
|
const segments = value.slice(1).split("/");
|
|
15
21
|
return segments.every((segment) => segment.length > 0 && /^[A-Za-z0-9._-]+$/.test(segment) && segment !== "." && segment !== "..");
|
|
16
|
-
},
|
|
22
|
+
}, AbsDirBadSegmentsError)
|
|
17
23
|
.brand("directory_path_absolute");
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
+
export declare const RelDirTypeError: "rel_dir.not.string";
|
|
3
|
+
export declare const RelDirMustNotStartWithSlashError: "rel_dir_must_not_start_with_slash";
|
|
4
|
+
export declare const RelDirBackslashForbiddenError: "rel_dir_backslash_forbidden";
|
|
5
|
+
export declare const RelDirControlCharsForbiddenError: "rel_dir_control_chars_forbidden";
|
|
6
|
+
export declare const RelDirEmptyError: "rel_dir_empty";
|
|
7
|
+
export declare const RelDirBadSegmentsError: "rel_dir_bad_segments";
|
|
2
8
|
export declare const DirectoryPathRelativeSchema: z.core.$ZodBranded<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodTransform<string, string>>, "directory_path_relative">;
|
|
3
9
|
export type DirectoryPathRelativeType = z.infer<typeof DirectoryPathRelativeSchema>;
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
+
export const RelDirTypeError = "rel_dir.not.string";
|
|
3
|
+
export const RelDirMustNotStartWithSlashError = "rel_dir_must_not_start_with_slash";
|
|
4
|
+
export const RelDirBackslashForbiddenError = "rel_dir_backslash_forbidden";
|
|
5
|
+
export const RelDirControlCharsForbiddenError = "rel_dir_control_chars_forbidden";
|
|
6
|
+
export const RelDirEmptyError = "rel_dir_empty";
|
|
7
|
+
export const RelDirBadSegmentsError = "rel_dir_bad_segments";
|
|
2
8
|
export const DirectoryPathRelativeSchema = z
|
|
3
|
-
.string()
|
|
9
|
+
.string(RelDirTypeError)
|
|
4
10
|
.trim()
|
|
5
|
-
.refine((value) => !value.startsWith("/"),
|
|
6
|
-
.refine((value) => !value.includes("\\"),
|
|
11
|
+
.refine((value) => !value.startsWith("/"), RelDirMustNotStartWithSlashError)
|
|
12
|
+
.refine((value) => !value.includes("\\"), RelDirBackslashForbiddenError)
|
|
7
13
|
// biome-ignore lint: lint/suspicious/noControlCharactersInRegex
|
|
8
|
-
.refine((value) => !/[\u0000-\u001F\u007F]/.test(value),
|
|
14
|
+
.refine((value) => !/[\u0000-\u001F\u007F]/.test(value), RelDirControlCharsForbiddenError)
|
|
9
15
|
.transform((value) => value.replace(/\/{2,}/g, "/"))
|
|
10
16
|
.transform((value) => value.replace(/^\/+|\/+$/g, ""))
|
|
11
|
-
.refine((value) => value.length > 0,
|
|
17
|
+
.refine((value) => value.length > 0, RelDirEmptyError)
|
|
12
18
|
.refine((value) => value
|
|
13
19
|
.split("/")
|
|
14
|
-
.every((segment) => /^[A-Za-z0-9._-]+$/.test(segment) && segment !== "." && segment !== ".."),
|
|
20
|
+
.every((segment) => /^[A-Za-z0-9._-]+$/.test(segment) && segment !== "." && segment !== ".."), RelDirBadSegmentsError)
|
|
15
21
|
.brand("directory_path_relative");
|
package/dist/dll.service.js
CHANGED
|
@@ -7,21 +7,19 @@ export class Node {
|
|
|
7
7
|
}
|
|
8
8
|
forward(n) {
|
|
9
9
|
let currentNode = this;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return currentNode;
|
|
13
|
-
}
|
|
10
|
+
let steps = n;
|
|
11
|
+
while (steps > 0 && currentNode) {
|
|
14
12
|
currentNode = currentNode.next;
|
|
13
|
+
steps -= 1;
|
|
15
14
|
}
|
|
16
15
|
return currentNode;
|
|
17
16
|
}
|
|
18
17
|
backward(n) {
|
|
19
18
|
let currentNode = this;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return currentNode;
|
|
23
|
-
}
|
|
19
|
+
let steps = n;
|
|
20
|
+
while (steps > 0 && currentNode) {
|
|
24
21
|
currentNode = currentNode.prev;
|
|
22
|
+
steps -= 1;
|
|
25
23
|
}
|
|
26
24
|
return currentNode;
|
|
27
25
|
}
|
|
@@ -44,30 +42,28 @@ export class DoublyLinkedList {
|
|
|
44
42
|
return this.tail;
|
|
45
43
|
}
|
|
46
44
|
append(node) {
|
|
47
|
-
if (this.
|
|
48
|
-
this.size++;
|
|
45
|
+
if (this.tail === null) {
|
|
49
46
|
this.head = node;
|
|
50
47
|
this.tail = node;
|
|
51
48
|
}
|
|
52
49
|
else {
|
|
53
|
-
this.size++;
|
|
54
50
|
this.tail.next = node;
|
|
55
51
|
node.prev = this.tail;
|
|
56
52
|
this.tail = node;
|
|
57
53
|
}
|
|
54
|
+
this.size += 1;
|
|
58
55
|
}
|
|
59
56
|
prepend(node) {
|
|
60
|
-
if (this.head === null
|
|
61
|
-
this.size++;
|
|
57
|
+
if (this.head === null) {
|
|
62
58
|
this.head = node;
|
|
63
59
|
this.tail = node;
|
|
64
60
|
}
|
|
65
61
|
else {
|
|
66
|
-
this.size++;
|
|
67
62
|
node.next = this.head;
|
|
68
63
|
this.head.prev = node;
|
|
69
64
|
this.head = node;
|
|
70
65
|
}
|
|
66
|
+
this.size += 1;
|
|
71
67
|
}
|
|
72
68
|
clear() {
|
|
73
69
|
this.size = 0;
|
|
@@ -87,43 +83,53 @@ export class DoublyLinkedList {
|
|
|
87
83
|
else {
|
|
88
84
|
this.tail = node.prev;
|
|
89
85
|
}
|
|
90
|
-
this.size
|
|
86
|
+
this.size -= 1;
|
|
91
87
|
node.prev = null;
|
|
92
88
|
node.next = null;
|
|
93
89
|
}
|
|
94
90
|
insertAfter(node, target) {
|
|
95
91
|
if (target === this.tail) {
|
|
96
92
|
this.append(node);
|
|
93
|
+
return;
|
|
97
94
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
target.next = node;
|
|
95
|
+
const nextNode = target.next;
|
|
96
|
+
this.size += 1;
|
|
97
|
+
node.prev = target;
|
|
98
|
+
node.next = nextNode;
|
|
99
|
+
if (nextNode) {
|
|
100
|
+
nextNode.prev = node;
|
|
105
101
|
}
|
|
102
|
+
target.next = node;
|
|
106
103
|
}
|
|
107
104
|
insertBefore(node, target) {
|
|
108
105
|
if (target === this.head) {
|
|
109
106
|
this.prepend(node);
|
|
107
|
+
return;
|
|
110
108
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
target.prev = node;
|
|
109
|
+
const prevNode = target.prev;
|
|
110
|
+
this.size += 1;
|
|
111
|
+
node.next = target;
|
|
112
|
+
node.prev = prevNode;
|
|
113
|
+
if (prevNode) {
|
|
114
|
+
prevNode.next = node;
|
|
118
115
|
}
|
|
116
|
+
target.prev = node;
|
|
119
117
|
}
|
|
120
118
|
find(callback) {
|
|
121
|
-
|
|
119
|
+
let current = this.head;
|
|
120
|
+
while (current) {
|
|
121
|
+
if (callback(current))
|
|
122
|
+
return current;
|
|
123
|
+
current = current.next;
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
122
126
|
}
|
|
123
127
|
reverse() {
|
|
124
128
|
[this.head, this.tail] = [this.tail, this.head];
|
|
125
129
|
for (const node of this) {
|
|
126
|
-
|
|
130
|
+
const originalNext = node.next;
|
|
131
|
+
node.next = node.prev;
|
|
132
|
+
node.prev = originalNext;
|
|
127
133
|
}
|
|
128
134
|
}
|
|
129
135
|
toArray() {
|
package/dist/extension.vo.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
export declare const
|
|
3
|
-
export
|
|
2
|
+
export declare const ExtensionTypeError: "extension.not.string";
|
|
3
|
+
export declare const ExtensionEmptyError: "extension.empty";
|
|
4
|
+
export declare const ExtensionTooLongError: "extension.too.long";
|
|
5
|
+
export declare const ExtensionBadCharsError: "extension.bad.chars";
|
|
6
|
+
export declare const Extension: z.core.$ZodBranded<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, "Extension">;
|
|
7
|
+
export type ExtensionType = z.infer<typeof Extension>;
|
package/dist/extension.vo.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
export const
|
|
3
|
-
|
|
2
|
+
export const ExtensionTypeError = "extension.not.string";
|
|
3
|
+
export const ExtensionEmptyError = "extension.empty";
|
|
4
|
+
export const ExtensionTooLongError = "extension.too.long";
|
|
5
|
+
export const ExtensionBadCharsError = "extension.bad.chars";
|
|
6
|
+
export const Extension = z
|
|
7
|
+
.string(ExtensionTypeError)
|
|
4
8
|
.trim()
|
|
9
|
+
.toLowerCase()
|
|
5
10
|
.transform((value) => (value.startsWith(".") ? value.slice(1) : value))
|
|
6
|
-
.
|
|
7
|
-
.
|
|
8
|
-
.
|
|
9
|
-
.
|
|
10
|
-
.max(16, "extension_too_long")
|
|
11
|
-
.regex(/^[a-z0-9]+$/, "extension_bad_chars"))
|
|
12
|
-
.brand("extension");
|
|
11
|
+
.refine((value) => value.length >= 1, ExtensionEmptyError)
|
|
12
|
+
.refine((value) => value.length <= 16, ExtensionTooLongError)
|
|
13
|
+
.refine((value) => /^[a-z0-9]+$/.test(value), ExtensionBadCharsError)
|
|
14
|
+
.brand("Extension");
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { Filename } from "./filename.vo";
|
|
3
|
+
export declare const AbsFilePathTypeError: "abs.file.path.not.string";
|
|
4
|
+
export declare const AbsFilePathMustStartWithSlashError: "abs_file_path_must_start_with_slash";
|
|
5
|
+
export declare const AbsFilePathBackslashForbiddenError: "abs_file_path_backslash_forbidden";
|
|
6
|
+
export declare const AbsFilePathMissingFilenameError: "abs_file_path_missing_filename";
|
|
3
7
|
export declare const FilePathAbsoluteSchema: z.ZodPipe<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodTransform<string, string>>, z.ZodTransform<{
|
|
4
8
|
directory: string & z.core.$brand<"directory_path_absolute">;
|
|
5
9
|
filename: Filename;
|
|
6
10
|
}, string>>;
|
|
11
|
+
export type FilePathAbsoluteType = z.infer<typeof FilePathAbsoluteSchema>;
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { DirectoryPathAbsoluteSchema } from "./directory-path-absolute.vo";
|
|
3
3
|
import { Filename } from "./filename.vo";
|
|
4
|
+
export const AbsFilePathTypeError = "abs.file.path.not.string";
|
|
5
|
+
export const AbsFilePathMustStartWithSlashError = "abs_file_path_must_start_with_slash";
|
|
6
|
+
export const AbsFilePathBackslashForbiddenError = "abs_file_path_backslash_forbidden";
|
|
7
|
+
export const AbsFilePathMissingFilenameError = "abs_file_path_missing_filename";
|
|
4
8
|
export const FilePathAbsoluteSchema = z
|
|
5
|
-
.string()
|
|
9
|
+
.string(AbsFilePathTypeError)
|
|
6
10
|
.trim()
|
|
7
|
-
.refine((value) => value.startsWith("/"),
|
|
8
|
-
.refine((value) => !value.includes("\\"),
|
|
9
|
-
|
|
10
|
-
.transform((value) =>
|
|
11
|
-
|
|
11
|
+
.refine((value) => value.startsWith("/"), AbsFilePathMustStartWithSlashError)
|
|
12
|
+
.refine((value) => !value.includes("\\"), AbsFilePathBackslashForbiddenError)
|
|
13
|
+
// collapse duplicate slashes
|
|
14
|
+
.transform((value) => value.replace(/\/{2,}/g, "/"))
|
|
15
|
+
// keep "/" as-is; otherwise remove a trailing slash
|
|
16
|
+
.transform((value) => (value !== "/" && value.endsWith("/") ? value.slice(0, -1) : value))
|
|
17
|
+
.refine((value) => value !== "/", AbsFilePathMissingFilenameError)
|
|
12
18
|
.transform((normalized) => {
|
|
13
19
|
const lastSlashIndex = normalized.lastIndexOf("/");
|
|
14
20
|
const directoryCandidate = lastSlashIndex === 0 ? "/" : normalized.slice(0, lastSlashIndex);
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { Filename } from "./filename.vo";
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const RelFilePathTypeError: "rel.file.path.not.string";
|
|
4
|
+
export declare const RelFilePathMustNotStartWithSlashError: "rel_file_path_must_not_start_with_slash";
|
|
5
|
+
export declare const RelFilePathBackslashForbiddenError: "rel_file_path_backslash_forbidden";
|
|
6
|
+
export declare const RelFilePathRequiresDirectoryError: "rel_file_path_requires_directory";
|
|
7
|
+
export declare const FilePathRelativeSchema: z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodTransform<{
|
|
4
8
|
directory: string & z.core.$brand<"directory_path_relative">;
|
|
5
9
|
filename: Filename;
|
|
6
10
|
}, string>>;
|
|
11
|
+
export type FilePathRelativeType = z.infer<typeof FilePathRelativeSchema>;
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { DirectoryPathRelativeSchema } from "./directory-path-relative.vo";
|
|
3
3
|
import { Filename } from "./filename.vo";
|
|
4
|
+
export const RelFilePathTypeError = "rel.file.path.not.string";
|
|
5
|
+
export const RelFilePathMustNotStartWithSlashError = "rel_file_path_must_not_start_with_slash";
|
|
6
|
+
export const RelFilePathBackslashForbiddenError = "rel_file_path_backslash_forbidden";
|
|
7
|
+
export const RelFilePathRequiresDirectoryError = "rel_file_path_requires_directory";
|
|
4
8
|
export const FilePathRelativeSchema = z
|
|
5
|
-
.string()
|
|
9
|
+
.string(RelFilePathTypeError)
|
|
6
10
|
.trim()
|
|
7
|
-
.refine((value) => !value.startsWith("/"),
|
|
8
|
-
.refine((value) => !value.includes("\\"),
|
|
9
|
-
|
|
10
|
-
.transform((value) => value.replace(/^\/+|\/+$/g, ""))
|
|
11
|
-
.refine((value) => value.includes("/"),
|
|
11
|
+
.refine((value) => !value.startsWith("/"), RelFilePathMustNotStartWithSlashError)
|
|
12
|
+
.refine((value) => !value.includes("\\"), RelFilePathBackslashForbiddenError)
|
|
13
|
+
// collapse duplicate slashes, then trim leading/trailing slashes
|
|
14
|
+
.transform((value) => value.replace(/\/{2,}/g, "/").replace(/^\/+|\/+$/g, ""))
|
|
15
|
+
.refine((value) => value.includes("/"), RelFilePathRequiresDirectoryError)
|
|
12
16
|
.transform((normalized) => {
|
|
13
17
|
const lastSlashIndex = normalized.lastIndexOf("/");
|
|
14
18
|
const directoryCandidate = normalized.slice(0, lastSlashIndex);
|
package/dist/file-path.vo.js
CHANGED
|
@@ -17,8 +17,8 @@ export class FilePathRelative {
|
|
|
17
17
|
return new FilePathRelative(directory, filename);
|
|
18
18
|
}
|
|
19
19
|
static fromString(pathCandidate) {
|
|
20
|
-
const
|
|
21
|
-
return new FilePathRelative(directory, filename);
|
|
20
|
+
const parsed = FilePathRelativeSchema.parse(pathCandidate);
|
|
21
|
+
return new FilePathRelative(parsed.directory, parsed.filename);
|
|
22
22
|
}
|
|
23
23
|
get() {
|
|
24
24
|
return `${this.directory}/${this.filename.get()}`;
|
|
@@ -54,8 +54,8 @@ export class FilePathAbsolute {
|
|
|
54
54
|
return new FilePathAbsolute(directory, filename);
|
|
55
55
|
}
|
|
56
56
|
static fromString(pathCandidate) {
|
|
57
|
-
const
|
|
58
|
-
return new FilePathAbsolute(directory, filename);
|
|
57
|
+
const parsed = FilePathAbsoluteSchema.parse(pathCandidate);
|
|
58
|
+
return new FilePathAbsolute(parsed.directory, parsed.filename);
|
|
59
59
|
}
|
|
60
60
|
get() {
|
|
61
61
|
if (this.directory === "/")
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
export declare const
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
export declare const FilenameTypeError: "filename.not.string";
|
|
3
|
+
export declare const FilenameInvalidError: "filename.invalid";
|
|
4
|
+
export declare const FilenameFromString: z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
5
|
+
basename: string & z.core.$brand<"Basename">;
|
|
6
|
+
extension: string & z.core.$brand<"Extension">;
|
|
5
7
|
}, string>>;
|
|
6
|
-
export type
|
|
8
|
+
export type FilenameFromStringType = z.infer<typeof FilenameFromString>;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
export const
|
|
5
|
-
|
|
2
|
+
import { Basename } from "./basename.vo";
|
|
3
|
+
import { Extension } from "./extension.vo";
|
|
4
|
+
export const FilenameTypeError = "filename.not.string";
|
|
5
|
+
export const FilenameInvalidError = "filename.invalid";
|
|
6
|
+
export const FilenameFromString = z
|
|
7
|
+
.string(FilenameTypeError)
|
|
6
8
|
.trim()
|
|
7
|
-
.refine((
|
|
8
|
-
const index =
|
|
9
|
-
return index > 0 && index <
|
|
10
|
-
},
|
|
11
|
-
|
|
12
|
-
.
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
return { basename: base, extension: extension };
|
|
9
|
+
.refine((value) => {
|
|
10
|
+
const index = value.lastIndexOf(".");
|
|
11
|
+
return index > 0 && index < value.length - 1;
|
|
12
|
+
}, FilenameInvalidError)
|
|
13
|
+
.transform((value) => {
|
|
14
|
+
const index = value.lastIndexOf(".");
|
|
15
|
+
const basename = Basename.parse(value.slice(0, index));
|
|
16
|
+
const extension = Extension.parse(value.slice(index + 1));
|
|
17
|
+
return { basename, extension };
|
|
17
18
|
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
export declare const
|
|
3
|
-
export
|
|
2
|
+
export declare const FilenameSuffixTypeError: "suffix.not.string";
|
|
3
|
+
export declare const FilenameSuffixTooLongError: "suffix_too_long";
|
|
4
|
+
export declare const FilenameSuffix: z.core.$ZodBranded<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, "basename_suffix">;
|
|
5
|
+
export type FilenameSuffixType = z.infer<typeof FilenameSuffix>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
export const
|
|
3
|
-
|
|
2
|
+
export const FilenameSuffixTypeError = "suffix.not.string";
|
|
3
|
+
export const FilenameSuffixTooLongError = "suffix_too_long";
|
|
4
|
+
export const FilenameSuffix = z
|
|
5
|
+
.string(FilenameSuffixTypeError)
|
|
4
6
|
.trim()
|
|
5
7
|
.transform((value) => value.replace(/[^A-Za-z0-9_-]/g, ""))
|
|
6
|
-
.
|
|
8
|
+
.refine((value) => value.length <= 32, FilenameSuffixTooLongError)
|
|
7
9
|
.brand("basename_suffix");
|