nesoi 3.4.14 → 3.4.16
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/lib/elements/entities/bucket/view/bucket_view.js +24 -16
- package/lib/elements/entities/bucket/view/bucket_view.schema.d.ts +3 -1
- package/lib/elements/entities/bucket/view/bucket_view.schema.js +3 -1
- package/lib/elements/entities/bucket/view/bucket_view_field.builder.d.ts +2 -0
- package/lib/elements/entities/bucket/view/bucket_view_field.builder.js +6 -1
- package/lib/elements/entities/message/template/message_template.schema.d.ts +1 -0
- package/lib/elements/entities/message/template/message_template_field.builder.d.ts +3 -2
- package/lib/elements/entities/message/template/message_template_field.builder.js +17 -12
- package/lib/engine/data/date.d.ts +36 -0
- package/lib/engine/data/date.js +160 -1
- package/lib/engine/data/datetime.d.ts +35 -9
- package/lib/engine/data/datetime.js +125 -29
- package/lib/engine/data/duration.d.ts +51 -17
- package/lib/engine/data/duration.js +8 -2
- package/lib/engine/data/error.d.ts +6 -0
- package/lib/engine/data/error.js +8 -0
- package/lib/engine/transaction/nodes/external.trx_node.js +2 -1
- package/lib/engine/transaction/trx_engine.js +12 -11
- package/lib/engine/transaction/trx_node.js +1 -1
- package/lib/engine/treeshake.js +4 -4
- package/package.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -38,7 +38,9 @@ class BucketView {
|
|
|
38
38
|
if ('__root' in this.schema.fields || '__parent' in this.schema.fields || '__value' in this.schema.fields) {
|
|
39
39
|
Object.assign(parsed, root);
|
|
40
40
|
}
|
|
41
|
-
let layer = Object.values(this.schema.fields)
|
|
41
|
+
let layer = Object.values(this.schema.fields)
|
|
42
|
+
.sort((a, b) => a.idx - b.idx)
|
|
43
|
+
.map(field => ({
|
|
42
44
|
bucket: meta,
|
|
43
45
|
field,
|
|
44
46
|
data: [{
|
|
@@ -102,12 +104,6 @@ class BucketView {
|
|
|
102
104
|
continue;
|
|
103
105
|
next.push(...this.parseModelProp(node, flags));
|
|
104
106
|
}
|
|
105
|
-
// Computed props
|
|
106
|
-
for (const node of layer) {
|
|
107
|
-
if (node.field.scope !== 'computed')
|
|
108
|
-
continue;
|
|
109
|
-
await this.parseComputedProp(trx, node);
|
|
110
|
-
}
|
|
111
107
|
// Graph props
|
|
112
108
|
for (const node of layer) {
|
|
113
109
|
if (node.field.scope !== 'graph')
|
|
@@ -131,12 +127,20 @@ class BucketView {
|
|
|
131
127
|
d.target[d.key] = d.value;
|
|
132
128
|
}
|
|
133
129
|
}
|
|
134
|
-
next.push(...Object.values(node.field.children)
|
|
130
|
+
next.push(...Object.values(node.field.children)
|
|
131
|
+
.sort((a, b) => a.idx - b.idx)
|
|
132
|
+
.map(field => ({
|
|
135
133
|
bucket: node.bucket,
|
|
136
134
|
field,
|
|
137
135
|
data: node.data
|
|
138
136
|
})));
|
|
139
137
|
}
|
|
138
|
+
// Computed props
|
|
139
|
+
for (const node of layer) {
|
|
140
|
+
if (node.field.scope !== 'computed')
|
|
141
|
+
continue;
|
|
142
|
+
await this.parseComputedProp(trx, node);
|
|
143
|
+
}
|
|
140
144
|
// Exclude eventual nodes without data
|
|
141
145
|
next = next.filter(node => node.data.length);
|
|
142
146
|
return next;
|
|
@@ -197,7 +201,9 @@ class BucketView {
|
|
|
197
201
|
const next = [];
|
|
198
202
|
// Add children (subview) to queue
|
|
199
203
|
if (node.field.children) {
|
|
200
|
-
|
|
204
|
+
const children = Object.entries(node.field.children)
|
|
205
|
+
.sort((a, b) => a[1].idx - b[1].idx);
|
|
206
|
+
for (const [key, field] of children) {
|
|
201
207
|
if (key === '__root')
|
|
202
208
|
continue;
|
|
203
209
|
if (key === '__parent')
|
|
@@ -206,10 +212,10 @@ class BucketView {
|
|
|
206
212
|
continue;
|
|
207
213
|
next.push({
|
|
208
214
|
bucket: node.bucket,
|
|
209
|
-
field:
|
|
215
|
+
field: field,
|
|
210
216
|
data: nextData.map(d => ({
|
|
211
217
|
...d,
|
|
212
|
-
key: d.key ??
|
|
218
|
+
key: d.key ?? field.name
|
|
213
219
|
}))
|
|
214
220
|
});
|
|
215
221
|
}
|
|
@@ -370,7 +376,7 @@ class BucketView {
|
|
|
370
376
|
async parseComputedProp(trx, node) {
|
|
371
377
|
const meta = node.field.meta.computed;
|
|
372
378
|
for (const entry of node.data) {
|
|
373
|
-
entry.target[entry.key] = await promise_1.default.solve(meta.fn({ trx, root: entry.root, parent: entry.parent, value: entry.value, bucket: node.bucket.schema }));
|
|
379
|
+
entry.target[entry.key] = await promise_1.default.solve(meta.fn({ trx, root: entry.root, parent: entry.parent, value: entry.value, bucket: node.bucket.schema, target: entry.target }));
|
|
374
380
|
}
|
|
375
381
|
}
|
|
376
382
|
/**
|
|
@@ -502,7 +508,7 @@ class BucketView {
|
|
|
502
508
|
// const bucket = await Daemon.getBucketMetadata(module.daemon!, otherBucketDep);
|
|
503
509
|
// Next data is empty if meta.prop is defined, since there's no need to go deeper
|
|
504
510
|
if (nextData.length) {
|
|
505
|
-
for (const field of Object.values(v)) {
|
|
511
|
+
for (const field of Object.values(v).sort((a, b) => a.idx - b.idx)) {
|
|
506
512
|
next.push({
|
|
507
513
|
bucket: otherBucket,
|
|
508
514
|
field,
|
|
@@ -564,7 +570,9 @@ class BucketView {
|
|
|
564
570
|
const module = trx_node_1.TrxNode.getModule(trx);
|
|
565
571
|
const subview_bucket = daemon_1.Daemon.getBucketMetadata(module.daemon, link.bucket);
|
|
566
572
|
// Add subview data to queue
|
|
567
|
-
|
|
573
|
+
const children = Object.entries(node.field.children)
|
|
574
|
+
.sort((a, b) => a[1].idx - b[1].idx);
|
|
575
|
+
for (const [key, field] of children) {
|
|
568
576
|
if (key === '__root')
|
|
569
577
|
continue;
|
|
570
578
|
if (key === '__parent')
|
|
@@ -573,14 +581,14 @@ class BucketView {
|
|
|
573
581
|
continue;
|
|
574
582
|
next.push({
|
|
575
583
|
bucket: subview_bucket,
|
|
576
|
-
field:
|
|
584
|
+
field: field,
|
|
577
585
|
data: subview_data.map(data => ({
|
|
578
586
|
root: data.root,
|
|
579
587
|
parent: data.value,
|
|
580
588
|
index: [],
|
|
581
589
|
value: data.value,
|
|
582
590
|
target: data.target,
|
|
583
|
-
key:
|
|
591
|
+
key: field.name
|
|
584
592
|
}))
|
|
585
593
|
});
|
|
586
594
|
}
|
|
@@ -6,6 +6,7 @@ export type $BucketViewFieldFn<TrxNode extends AnyTrxNode, B extends $Bucket, Pa
|
|
|
6
6
|
parent: Parent;
|
|
7
7
|
value: Value;
|
|
8
8
|
bucket: $Bucket;
|
|
9
|
+
target: Record<string, any>;
|
|
9
10
|
}) => any | Promise<any>;
|
|
10
11
|
export type $BucketViewFieldMeta = {
|
|
11
12
|
model?: {
|
|
@@ -39,9 +40,10 @@ export declare class $BucketViewField {
|
|
|
39
40
|
children?: $BucketViewFields | undefined;
|
|
40
41
|
chain?: $BucketViewField | undefined;
|
|
41
42
|
as_dict?: number[] | undefined;
|
|
43
|
+
idx: number;
|
|
42
44
|
$t: string;
|
|
43
45
|
'#data': unknown;
|
|
44
|
-
constructor(name: string, scope: 'model' | 'graph' | 'computed' | 'group' | 'view' | 'drive', alias: string, meta: $BucketViewFieldMeta, prop?: string | undefined, children?: $BucketViewFields | undefined, chain?: $BucketViewField | undefined, as_dict?: number[] | undefined);
|
|
46
|
+
constructor(name: string, scope: 'model' | 'graph' | 'computed' | 'group' | 'view' | 'drive', alias: string, meta: $BucketViewFieldMeta, prop?: string | undefined, children?: $BucketViewFields | undefined, chain?: $BucketViewField | undefined, as_dict?: number[] | undefined, idx?: number);
|
|
45
47
|
}
|
|
46
48
|
export type $BucketViewFields = {
|
|
47
49
|
[x: string]: $BucketViewField;
|
|
@@ -14,9 +14,10 @@ class $BucketViewField {
|
|
|
14
14
|
children;
|
|
15
15
|
chain;
|
|
16
16
|
as_dict;
|
|
17
|
+
idx;
|
|
17
18
|
$t = 'bucket.view.field';
|
|
18
19
|
'#data';
|
|
19
|
-
constructor(name, scope, alias, meta, prop, children, chain, as_dict) {
|
|
20
|
+
constructor(name, scope, alias, meta, prop, children, chain, as_dict, idx = 0) {
|
|
20
21
|
this.name = name;
|
|
21
22
|
this.scope = scope;
|
|
22
23
|
this.alias = alias;
|
|
@@ -25,6 +26,7 @@ class $BucketViewField {
|
|
|
25
26
|
this.children = children;
|
|
26
27
|
this.chain = chain;
|
|
27
28
|
this.as_dict = as_dict;
|
|
29
|
+
this.idx = idx;
|
|
28
30
|
}
|
|
29
31
|
}
|
|
30
32
|
exports.$BucketViewField = $BucketViewField;
|
|
@@ -48,6 +48,7 @@ export declare class BucketViewFieldBuilder<Module extends $Module, Bucket exten
|
|
|
48
48
|
protected _prop?: string;
|
|
49
49
|
protected _chain?: ($: BucketViewFieldFactory<any, Module, Bucket>) => BucketViewFieldBuilder<Module, Bucket, any, any, any>;
|
|
50
50
|
protected _as_dict?: number[];
|
|
51
|
+
protected _idx: number;
|
|
51
52
|
constructor(scope: $BucketViewField['scope'], meta: $BucketViewFieldMeta, subview?: (BucketViewFieldBuilders<any> | BucketViewDef<any, any, any>) | undefined);
|
|
52
53
|
prop<Obj extends Data extends any[] ? Data[number] : Data, K extends keyof Obj>(prop: K): BucketViewFieldBuilder<Module, Bucket, ChainBucket, Obj[K], Scope, GraphLink>;
|
|
53
54
|
map<Def extends BucketViewDef<any, Module, ChainBucket>>(def: Def): BucketViewFieldBuilder<Module, Bucket, ChainBucket, { [K in keyof Def]: Def extends BucketViewFieldBuilder<any, any, infer X, any, any> ? X : never; }, Scope, GraphLink>;
|
|
@@ -58,6 +59,7 @@ export declare class BucketViewFieldBuilder<Module extends $Module, Bucket exten
|
|
|
58
59
|
} : {
|
|
59
60
|
[x: string]: Data;
|
|
60
61
|
}, Scope, GraphLink>;
|
|
62
|
+
order(idx: number): this;
|
|
61
63
|
static build(builder: BucketViewFieldBuilder<any, any, any, any, any>, model: $BucketModel, graph: $BucketGraph, views: $BucketViews, name: string, n_indexes: number, tree?: ModuleTree): $BucketViewField;
|
|
62
64
|
static buildFields(fields: BucketViewFieldBuilders<any>, model: $BucketModel, graph: $BucketGraph, views: $BucketViews, n_indexes?: number, tree?: ModuleTree): $BucketViewFields;
|
|
63
65
|
}
|
|
@@ -117,6 +117,7 @@ class BucketViewFieldBuilder {
|
|
|
117
117
|
_prop;
|
|
118
118
|
_chain;
|
|
119
119
|
_as_dict;
|
|
120
|
+
_idx = 0;
|
|
120
121
|
constructor(scope, meta, subview) {
|
|
121
122
|
this.scope = scope;
|
|
122
123
|
this.meta = meta;
|
|
@@ -169,6 +170,10 @@ class BucketViewFieldBuilder {
|
|
|
169
170
|
this._as_dict = indexes ?? [-1];
|
|
170
171
|
return this;
|
|
171
172
|
}
|
|
173
|
+
order(idx) {
|
|
174
|
+
this._idx = idx;
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
172
177
|
// Build
|
|
173
178
|
static build(builder, model, graph, views, name, n_indexes, tree) {
|
|
174
179
|
let children = undefined;
|
|
@@ -240,7 +245,7 @@ class BucketViewFieldBuilder {
|
|
|
240
245
|
const subview = builder._chain(factory);
|
|
241
246
|
chain = BucketViewFieldBuilder.build(subview, model, graph, views, name, n_indexes + spread_n, tree);
|
|
242
247
|
}
|
|
243
|
-
return new bucket_view_schema_1.$BucketViewField(name, builder.scope, name, builder.meta, builder._prop, children, chain, builder._as_dict);
|
|
248
|
+
return new bucket_view_schema_1.$BucketViewField(name, builder.scope, name, builder.meta, builder._prop, children, chain, builder._as_dict, builder._idx);
|
|
244
249
|
}
|
|
245
250
|
static buildFields(fields, model, graph, views, n_indexes = 0, tree) {
|
|
246
251
|
const schema = {};
|
|
@@ -61,7 +61,7 @@ export declare class MessageTemplateFieldFactory<Space extends $Space, Module ex
|
|
|
61
61
|
* */
|
|
62
62
|
export declare class MessageTemplateFieldBuilder<Module extends $Module, Message extends $Message, Input, Output, Children extends MessageTemplateFieldBuilders, Optional = [false, false], InputSuffix extends string = ''> {
|
|
63
63
|
private type;
|
|
64
|
-
private
|
|
64
|
+
private _meta;
|
|
65
65
|
private alias?;
|
|
66
66
|
private children?;
|
|
67
67
|
'#input': Input;
|
|
@@ -73,7 +73,7 @@ export declare class MessageTemplateFieldBuilder<Module extends $Module, Message
|
|
|
73
73
|
private _nullable;
|
|
74
74
|
private _rawName?;
|
|
75
75
|
private _rules;
|
|
76
|
-
constructor(type: $MessageTemplateFieldType,
|
|
76
|
+
constructor(type: $MessageTemplateFieldType, _meta: Omit<$MessageTemplateFieldMeta, 'enum' | 'msg' | 'id'> & {
|
|
77
77
|
enum?: {
|
|
78
78
|
options: Record<string, any>;
|
|
79
79
|
} | {
|
|
@@ -100,6 +100,7 @@ export declare class MessageTemplateFieldBuilder<Module extends $Module, Message
|
|
|
100
100
|
get nullable(): MessageTemplateFieldBuilder<Module, Message, Input | null, Output | null, Children, Optional, InputSuffix>;
|
|
101
101
|
rule(rule: MessageTemplateRuleDef<Output, Message['#raw']>): this;
|
|
102
102
|
rawName(name: string): this;
|
|
103
|
+
meta(data: Record<string, any>): this;
|
|
103
104
|
static build(builder: AnyMessageTemplateFieldBuilder, name: string, tree: ModuleTree, module: $Module, basePathRaw: string, basePathParsed: string): $MessageTemplateField;
|
|
104
105
|
static buildMany(fields: MessageTemplateFieldBuilders, tree: ModuleTree, module: $Module, basePathRaw?: string, basePathParsed?: string, name?: string, key?: string): $MessageTemplateFields;
|
|
105
106
|
}
|
|
@@ -128,7 +128,7 @@ exports.MessageTemplateFieldFactory = MessageTemplateFieldFactory;
|
|
|
128
128
|
* */
|
|
129
129
|
class MessageTemplateFieldBuilder {
|
|
130
130
|
type;
|
|
131
|
-
|
|
131
|
+
_meta;
|
|
132
132
|
alias;
|
|
133
133
|
children;
|
|
134
134
|
'#input';
|
|
@@ -140,9 +140,9 @@ class MessageTemplateFieldBuilder {
|
|
|
140
140
|
_nullable = false;
|
|
141
141
|
_rawName;
|
|
142
142
|
_rules = [];
|
|
143
|
-
constructor(type,
|
|
143
|
+
constructor(type, _meta, alias, children) {
|
|
144
144
|
this.type = type;
|
|
145
|
-
this.
|
|
145
|
+
this._meta = _meta;
|
|
146
146
|
this.alias = alias;
|
|
147
147
|
this.children = children;
|
|
148
148
|
}
|
|
@@ -171,6 +171,11 @@ class MessageTemplateFieldBuilder {
|
|
|
171
171
|
this._rawName = name;
|
|
172
172
|
return this;
|
|
173
173
|
}
|
|
174
|
+
meta(data) {
|
|
175
|
+
this._meta.custom ??= {};
|
|
176
|
+
Object.assign(this._meta.custom, data);
|
|
177
|
+
return this;
|
|
178
|
+
}
|
|
174
179
|
// Build
|
|
175
180
|
static build(builder, name, tree, module, basePathRaw, basePathParsed) {
|
|
176
181
|
const pathRaw = basePathRaw +
|
|
@@ -181,14 +186,14 @@ class MessageTemplateFieldBuilder {
|
|
|
181
186
|
let type = builder.type;
|
|
182
187
|
let children;
|
|
183
188
|
if (builder.type === 'id') {
|
|
184
|
-
const bucket = dependency_1.Tag.resolve(builder.
|
|
185
|
-
builder.
|
|
186
|
-
builder.
|
|
189
|
+
const bucket = dependency_1.Tag.resolve(builder._meta.id.bucket.tag, tree);
|
|
190
|
+
builder._meta.id.type = bucket.model.fields.id.type;
|
|
191
|
+
builder._meta.id.bucket = builder._meta.id.bucket.tag;
|
|
187
192
|
}
|
|
188
193
|
else if (builder.type === 'enum') {
|
|
189
|
-
if ('dep' in builder.
|
|
190
|
-
const _enum = dependency_1.Tag.resolve(builder.
|
|
191
|
-
builder.
|
|
194
|
+
if ('dep' in builder._meta.enum) {
|
|
195
|
+
const _enum = dependency_1.Tag.resolve(builder._meta.enum.dep.tag, tree);
|
|
196
|
+
builder._meta.enum = {
|
|
192
197
|
options: _enum.options
|
|
193
198
|
};
|
|
194
199
|
}
|
|
@@ -196,7 +201,7 @@ class MessageTemplateFieldBuilder {
|
|
|
196
201
|
// A .msg() parameter is an obj which takes fields from
|
|
197
202
|
// another message
|
|
198
203
|
else if (builder.type === 'msg') {
|
|
199
|
-
const dep = builder.
|
|
204
|
+
const dep = builder._meta.msg;
|
|
200
205
|
if (dep.tag.type !== 'message') {
|
|
201
206
|
throw error_1.NesoiError.Builder.Message.UnknownModuleMessage(dep.tag.name);
|
|
202
207
|
}
|
|
@@ -218,7 +223,7 @@ class MessageTemplateFieldBuilder {
|
|
|
218
223
|
type = 'obj';
|
|
219
224
|
children = {};
|
|
220
225
|
injectFields(children, $msg.template.fields);
|
|
221
|
-
builder.
|
|
226
|
+
builder._meta.msg = { tag: dep.tag };
|
|
222
227
|
}
|
|
223
228
|
else if (builder.type === 'list') {
|
|
224
229
|
children = MessageTemplateFieldBuilder.buildMany(builder.children, tree, module, childrenBasePathRaw, childrenBasePathParsed, '#', '#');
|
|
@@ -233,7 +238,7 @@ class MessageTemplateFieldBuilder {
|
|
|
233
238
|
else if (builder.children) {
|
|
234
239
|
children = MessageTemplateFieldBuilder.buildMany(builder.children, tree, module, childrenBasePathRaw, childrenBasePathParsed);
|
|
235
240
|
}
|
|
236
|
-
return new message_template_schema_1.$MessageTemplateField(type, name, builder.alias || name, pathRaw, pathParsed, builder._required, builder._defaultValue, builder._nullable, builder._rules, builder.
|
|
241
|
+
return new message_template_schema_1.$MessageTemplateField(type, name, builder.alias || name, pathRaw, pathParsed, builder._required, builder._defaultValue, builder._nullable, builder._rules, builder._meta, children);
|
|
237
242
|
}
|
|
238
243
|
static buildMany(fields, tree, module, basePathRaw = '', basePathParsed = '', name, key) {
|
|
239
244
|
const schema = {};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { NesoiDatetime } from './datetime';
|
|
2
|
+
import type { DateDuration } from './duration';
|
|
3
|
+
import { NesoiDuration } from './duration';
|
|
1
4
|
/**
|
|
2
5
|
* @category Engine
|
|
3
6
|
* @subcategory Data
|
|
@@ -7,8 +10,41 @@ export declare class NesoiDate {
|
|
|
7
10
|
month: number;
|
|
8
11
|
year: number;
|
|
9
12
|
constructor(day: number, month: number, year: number);
|
|
13
|
+
static from(iso_or_date: any): NesoiDate;
|
|
10
14
|
static fromISO(iso: string): NesoiDate;
|
|
11
15
|
static now(): NesoiDate;
|
|
12
16
|
static isoNow(): string;
|
|
13
17
|
toISO(): string;
|
|
18
|
+
toString(): string;
|
|
19
|
+
toISODatetime(at: 'start' | 'end', tz?: keyof typeof NesoiDatetime.tz): string;
|
|
20
|
+
plus(period: DateDuration | NesoiDuration): NesoiDate;
|
|
21
|
+
minus(period: DateDuration | NesoiDuration): NesoiDate;
|
|
22
|
+
private shift;
|
|
23
|
+
/**
|
|
24
|
+
* Returns a new `NesoiDate` which refers to the
|
|
25
|
+
* start of a given period.
|
|
26
|
+
* @param period
|
|
27
|
+
* @returns
|
|
28
|
+
*/
|
|
29
|
+
startOf(period: 'week' | 'month' | 'year'): NesoiDate;
|
|
30
|
+
/**
|
|
31
|
+
* Returns a new `NesoiDatetime` which refers to the
|
|
32
|
+
* end of a given period.
|
|
33
|
+
* @param period
|
|
34
|
+
* @returns
|
|
35
|
+
*/
|
|
36
|
+
endOf(period: 'week' | 'month' | 'year'): NesoiDate;
|
|
37
|
+
/**
|
|
38
|
+
* Returns a float with the distance in days between the dates.
|
|
39
|
+
* - `> 0`: left is greater
|
|
40
|
+
* - `== 0`: dates match
|
|
41
|
+
* - `< 0`: right is greater
|
|
42
|
+
*/
|
|
43
|
+
compare(other: NesoiDate): number;
|
|
44
|
+
eq(other: NesoiDate): boolean;
|
|
45
|
+
gt(other: NesoiDate): boolean;
|
|
46
|
+
gteq(other: NesoiDate): boolean;
|
|
47
|
+
lt(other: NesoiDate): boolean;
|
|
48
|
+
lteq(other: NesoiDate): boolean;
|
|
49
|
+
toDatetime(at: 'start' | 'end', tz?: keyof typeof NesoiDatetime.tz): NesoiDatetime;
|
|
14
50
|
}
|
package/lib/engine/data/date.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NesoiDate = void 0;
|
|
4
|
+
const datetime_1 = require("./datetime");
|
|
5
|
+
const duration_1 = require("./duration");
|
|
4
6
|
const error_1 = require("./error");
|
|
5
7
|
/**
|
|
6
8
|
* @category Engine
|
|
@@ -15,13 +17,21 @@ class NesoiDate {
|
|
|
15
17
|
this.month = month;
|
|
16
18
|
this.year = year;
|
|
17
19
|
}
|
|
20
|
+
static from(iso_or_date) {
|
|
21
|
+
if (typeof iso_or_date === 'string') {
|
|
22
|
+
return this.fromISO(iso_or_date);
|
|
23
|
+
}
|
|
24
|
+
if (iso_or_date instanceof NesoiDate) {
|
|
25
|
+
return iso_or_date;
|
|
26
|
+
}
|
|
27
|
+
throw error_1.NesoiError.Data.InvalidDate({ value: iso_or_date });
|
|
28
|
+
}
|
|
18
29
|
static fromISO(iso) {
|
|
19
30
|
const match = iso.match(/(\d{4})-(\d{2})-(\d{2})/);
|
|
20
31
|
// TODO: Check invalid date
|
|
21
32
|
if (!match) {
|
|
22
33
|
throw error_1.NesoiError.Data.InvalidISOString({ value: iso });
|
|
23
34
|
}
|
|
24
|
-
const jsDate = new Date(iso);
|
|
25
35
|
return new NesoiDate(parseInt(match[3]), parseInt(match[2]), parseInt(match[1]));
|
|
26
36
|
}
|
|
27
37
|
static now() {
|
|
@@ -35,5 +45,154 @@ class NesoiDate {
|
|
|
35
45
|
toISO() {
|
|
36
46
|
return `${('0000' + this.year).slice(-4)}-${('00' + this.month).slice(-2)}-${('00' + this.day).slice(-2)}`;
|
|
37
47
|
}
|
|
48
|
+
toString() {
|
|
49
|
+
return this.toISO();
|
|
50
|
+
}
|
|
51
|
+
toISODatetime(at, tz = 'Z') {
|
|
52
|
+
return `${('0000' + this.year).slice(-4)}-${('00' + this.month).slice(-2)}-${('00' + this.day).slice(-2)}`
|
|
53
|
+
+ (at === 'start'
|
|
54
|
+
? 'T00:00:00.000'
|
|
55
|
+
: 'T23:59:59.999')
|
|
56
|
+
+ tz;
|
|
57
|
+
}
|
|
58
|
+
// Shift
|
|
59
|
+
plus(period) {
|
|
60
|
+
return this.shift(true, period);
|
|
61
|
+
}
|
|
62
|
+
minus(period) {
|
|
63
|
+
return this.shift(false, period);
|
|
64
|
+
}
|
|
65
|
+
shift(plus, period) {
|
|
66
|
+
let duration;
|
|
67
|
+
if (typeof period === 'string') {
|
|
68
|
+
try {
|
|
69
|
+
const [_, val, type] = period.match(/(\d+) +(\w+)/);
|
|
70
|
+
duration = new duration_1.NesoiDuration({
|
|
71
|
+
[type]: val
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
throw new Error(`Attempt to shift NesoiDate failed due to invalid period '${period}'`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
if (period instanceof duration_1.NesoiDuration) {
|
|
80
|
+
duration = period;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
duration = new duration_1.NesoiDuration(period);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!['days', 'weeks', 'months', 'years'].includes(duration.unit)) {
|
|
87
|
+
throw new Error(`Attempt to shift NesoiDate failed due to invalid duration unit '${duration.unit}'`);
|
|
88
|
+
}
|
|
89
|
+
const mult = plus ? 1 : -1;
|
|
90
|
+
const d = new Date(this.year, this.month - 1, this.day);
|
|
91
|
+
switch (duration.unit) {
|
|
92
|
+
case 'days':
|
|
93
|
+
d.setDate(d.getDate() + mult * duration.value);
|
|
94
|
+
break;
|
|
95
|
+
case 'weeks':
|
|
96
|
+
d.setDate(d.getDate() + mult * duration.value * 7);
|
|
97
|
+
break;
|
|
98
|
+
case 'months':
|
|
99
|
+
d.setMonth(d.getMonth() + mult * duration.value);
|
|
100
|
+
break;
|
|
101
|
+
case 'years':
|
|
102
|
+
d.setFullYear(d.getFullYear() + mult * duration.value);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
return new NesoiDate(d.getDate(), d.getMonth() + 1, d.getFullYear());
|
|
106
|
+
}
|
|
107
|
+
// Start Of
|
|
108
|
+
/**
|
|
109
|
+
* Returns a new `NesoiDate` which refers to the
|
|
110
|
+
* start of a given period.
|
|
111
|
+
* @param period
|
|
112
|
+
* @returns
|
|
113
|
+
*/
|
|
114
|
+
startOf(period) {
|
|
115
|
+
switch (period) {
|
|
116
|
+
case 'week':
|
|
117
|
+
{
|
|
118
|
+
const d = new Date(this.year, this.month - 1, this.day);
|
|
119
|
+
d.setDate(d.getDate() - d.getDay());
|
|
120
|
+
return new NesoiDate(d.getDate(), d.getMonth() + 1, d.getFullYear());
|
|
121
|
+
}
|
|
122
|
+
case 'month':
|
|
123
|
+
return new NesoiDate(1, this.month, this.year);
|
|
124
|
+
case 'year':
|
|
125
|
+
return new NesoiDate(1, 1, this.year);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// End Of
|
|
129
|
+
/**
|
|
130
|
+
* Returns a new `NesoiDatetime` which refers to the
|
|
131
|
+
* end of a given period.
|
|
132
|
+
* @param period
|
|
133
|
+
* @returns
|
|
134
|
+
*/
|
|
135
|
+
endOf(period) {
|
|
136
|
+
switch (period) {
|
|
137
|
+
case 'week':
|
|
138
|
+
{
|
|
139
|
+
const d = new Date(this.year, this.month - 1, this.day);
|
|
140
|
+
d.setDate(d.getDate() + 6 - d.getDay());
|
|
141
|
+
return new NesoiDate(d.getDate(), d.getMonth() + 1, d.getFullYear());
|
|
142
|
+
}
|
|
143
|
+
case 'month':
|
|
144
|
+
return new NesoiDate(new Date(this.year, this.month, 0).getDate(), this.month, this.year);
|
|
145
|
+
case 'year':
|
|
146
|
+
return new NesoiDate(new Date(this.year, 12, 0).getDate(), 12, this.year);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Comparisons
|
|
150
|
+
/**
|
|
151
|
+
* Returns a float with the distance in days between the dates.
|
|
152
|
+
* - `> 0`: left is greater
|
|
153
|
+
* - `== 0`: dates match
|
|
154
|
+
* - `< 0`: right is greater
|
|
155
|
+
*/
|
|
156
|
+
compare(other) {
|
|
157
|
+
return (this.year - other.year) * 365.25
|
|
158
|
+
+ (this.month - other.month) * 12
|
|
159
|
+
+ (this.day - other.day);
|
|
160
|
+
}
|
|
161
|
+
eq(other) {
|
|
162
|
+
return this.compare(other) === 0;
|
|
163
|
+
}
|
|
164
|
+
gt(other) {
|
|
165
|
+
return this.compare(other) > 0;
|
|
166
|
+
}
|
|
167
|
+
gteq(other) {
|
|
168
|
+
return this.compare(other) >= 0;
|
|
169
|
+
}
|
|
170
|
+
lt(other) {
|
|
171
|
+
return this.compare(other) < 0;
|
|
172
|
+
}
|
|
173
|
+
lteq(other) {
|
|
174
|
+
return this.compare(other) <= 0;
|
|
175
|
+
}
|
|
176
|
+
// to NesoiDateTime
|
|
177
|
+
toDatetime(at, tz = 'Z') {
|
|
178
|
+
if (at === 'start')
|
|
179
|
+
return datetime_1.NesoiDatetime.fromValues({
|
|
180
|
+
...this,
|
|
181
|
+
hour: 0,
|
|
182
|
+
minute: 0,
|
|
183
|
+
second: 0,
|
|
184
|
+
ms: 0,
|
|
185
|
+
tz
|
|
186
|
+
});
|
|
187
|
+
else
|
|
188
|
+
return datetime_1.NesoiDatetime.fromValues({
|
|
189
|
+
...this,
|
|
190
|
+
hour: 23,
|
|
191
|
+
minute: 59,
|
|
192
|
+
second: 59,
|
|
193
|
+
ms: 999,
|
|
194
|
+
tz
|
|
195
|
+
});
|
|
196
|
+
}
|
|
38
197
|
}
|
|
39
198
|
exports.NesoiDate = NesoiDate;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { NesoiDate } from './date';
|
|
2
|
+
import type { DateDuration, TimeDuration } from './duration';
|
|
1
3
|
import { NesoiDuration } from './duration';
|
|
2
4
|
export type NesoiDateTimeValues = {
|
|
3
5
|
year: number;
|
|
@@ -50,12 +52,6 @@ export declare class NesoiDatetime {
|
|
|
50
52
|
tz: keyof typeof NesoiDatetime.tz;
|
|
51
53
|
constructor(epoch?: number, tz?: keyof typeof NesoiDatetime.tz);
|
|
52
54
|
atTimezone(tz: NesoiDatetime['tz']): NesoiDatetime;
|
|
53
|
-
/**
|
|
54
|
-
* Parse a timestamp from ISO 8601 format.
|
|
55
|
-
*
|
|
56
|
-
* Example: `2025-04-16T23:04:42.000-03:00`
|
|
57
|
-
*/
|
|
58
|
-
static fromISO(iso: string): NesoiDatetime;
|
|
59
55
|
/**
|
|
60
56
|
* Make a new `NesoiDateTime`
|
|
61
57
|
* @param year Numeric year
|
|
@@ -69,16 +65,26 @@ export declare class NesoiDatetime {
|
|
|
69
65
|
* @returns
|
|
70
66
|
*/
|
|
71
67
|
static make(year?: number, month?: number, day?: number, hour?: number, minute?: number, second?: number, ms?: number, tz?: NesoiDatetime['tz']): NesoiDatetime;
|
|
68
|
+
static parse(value: string | NesoiDatetime): NesoiDatetime;
|
|
69
|
+
/**
|
|
70
|
+
* Create a NesoiDatetime from a string on the ISO 8601 format.
|
|
71
|
+
*
|
|
72
|
+
* Example: `2025-04-16T23:04:42.000-03:00`
|
|
73
|
+
*/
|
|
74
|
+
static fromISO(iso: string): NesoiDatetime;
|
|
75
|
+
static fromJSDate(date: Date, tz?: keyof typeof NesoiDatetime.tz): NesoiDatetime;
|
|
72
76
|
static fromValues(values: Partial<NesoiDateTimeValues>): NesoiDatetime;
|
|
73
77
|
toISO(): string;
|
|
78
|
+
toString(): string;
|
|
79
|
+
toISODate(): string;
|
|
74
80
|
toValues(): NesoiDateTimeValues;
|
|
75
81
|
toJSDate(): Date;
|
|
76
82
|
static now(): NesoiDatetime;
|
|
77
83
|
static isoNow(): string;
|
|
78
84
|
static shortIsoNow(): string;
|
|
79
|
-
plus(period:
|
|
80
|
-
minus(period:
|
|
81
|
-
shift
|
|
85
|
+
plus(period: DateDuration | TimeDuration | NesoiDuration): NesoiDatetime;
|
|
86
|
+
minus(period: DateDuration | TimeDuration | NesoiDuration): NesoiDatetime;
|
|
87
|
+
private shift;
|
|
82
88
|
/**
|
|
83
89
|
* Returns a new `NesoiDatetime` which refers to the
|
|
84
90
|
* start of a given period **on the object timezone**.
|
|
@@ -86,4 +92,24 @@ export declare class NesoiDatetime {
|
|
|
86
92
|
* @returns
|
|
87
93
|
*/
|
|
88
94
|
startOf(period: 'day' | 'month' | 'year'): NesoiDatetime;
|
|
95
|
+
/**
|
|
96
|
+
* Returns a new `NesoiDatetime` which refers to the
|
|
97
|
+
* end of a given period **on the object timezone**.
|
|
98
|
+
* @param period
|
|
99
|
+
* @returns
|
|
100
|
+
*/
|
|
101
|
+
endOf(period: 'day' | 'month' | 'year'): NesoiDatetime;
|
|
102
|
+
/**
|
|
103
|
+
* Returns a float with the distance in milliseconds between the datetimes.
|
|
104
|
+
* - `> 0`: left is greater
|
|
105
|
+
* - `== 0`: dates match
|
|
106
|
+
* - `< 0`: right is greater
|
|
107
|
+
*/
|
|
108
|
+
compare(other: NesoiDatetime): number;
|
|
109
|
+
eq(other: NesoiDatetime): boolean;
|
|
110
|
+
gt(other: NesoiDatetime): boolean;
|
|
111
|
+
gteq(other: NesoiDatetime): boolean;
|
|
112
|
+
lt(other: NesoiDatetime): boolean;
|
|
113
|
+
lteq(other: NesoiDatetime): boolean;
|
|
114
|
+
toDate(): NesoiDate;
|
|
89
115
|
}
|