Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F102301045
StatsFactory.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Wed, Feb 19, 07:02
Size
7 KB
Mime Type
text/x-c++
Expires
Fri, Feb 21, 07:02 (4 h, 42 m)
Engine
blob
Format
Raw Data
Handle
24327003
Attached To
rOACCT Open Access Compliance Check Tool (OACCT)
StatsFactory.js
View Options
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict"
;
const
{
HookMap
,
SyncBailHook
,
SyncWaterfallHook
}
=
require
(
"tapable"
);
const
{
concatComparators
,
keepOriginalOrder
}
=
require
(
"../util/comparators"
);
const
smartGrouping
=
require
(
"../util/smartGrouping"
);
/** @typedef {import("../util/smartGrouping").GroupConfig<any, object>} GroupConfig */
class
StatsFactory
{
constructor
()
{
this
.
hooks
=
Object
.
freeze
({
/** @type {HookMap<SyncBailHook<[Object, any, Object]>>} */
extract
:
new
HookMap
(
()
=>
new
SyncBailHook
([
"object"
,
"data"
,
"context"
])
),
/** @type {HookMap<SyncBailHook<[any, Object, number, number]>>} */
filter
:
new
HookMap
(
()
=>
new
SyncBailHook
([
"item"
,
"context"
,
"index"
,
"unfilteredIndex"
])
),
/** @type {HookMap<SyncBailHook<[(function(any, any): number)[], Object]>>} */
sort
:
new
HookMap
(()
=>
new
SyncBailHook
([
"comparators"
,
"context"
])),
/** @type {HookMap<SyncBailHook<[any, Object, number, number]>>} */
filterSorted
:
new
HookMap
(
()
=>
new
SyncBailHook
([
"item"
,
"context"
,
"index"
,
"unfilteredIndex"
])
),
/** @type {HookMap<SyncBailHook<[GroupConfig[], Object]>>} */
groupResults
:
new
HookMap
(
()
=>
new
SyncBailHook
([
"groupConfigs"
,
"context"
])
),
/** @type {HookMap<SyncBailHook<[(function(any, any): number)[], Object]>>} */
sortResults
:
new
HookMap
(
()
=>
new
SyncBailHook
([
"comparators"
,
"context"
])
),
filterResults
:
new
HookMap
(
()
=>
new
SyncBailHook
([
"item"
,
"context"
,
"index"
,
"unfilteredIndex"
])
),
/** @type {HookMap<SyncBailHook<[any[], Object]>>} */
merge
:
new
HookMap
(()
=>
new
SyncBailHook
([
"items"
,
"context"
])),
/** @type {HookMap<SyncBailHook<[any[], Object]>>} */
result
:
new
HookMap
(()
=>
new
SyncWaterfallHook
([
"result"
,
"context"
])),
/** @type {HookMap<SyncBailHook<[any, Object]>>} */
getItemName
:
new
HookMap
(()
=>
new
SyncBailHook
([
"item"
,
"context"
])),
/** @type {HookMap<SyncBailHook<[any, Object]>>} */
getItemFactory
:
new
HookMap
(()
=>
new
SyncBailHook
([
"item"
,
"context"
]))
});
const
hooks
=
this
.
hooks
;
this
.
_caches
=
/** @type {Record<keyof typeof hooks, Map<string, SyncBailHook<[any[], Object]>[]>>} */
({});
for
(
const
key
of
Object
.
keys
(
hooks
))
{
this
.
_caches
[
key
]
=
new
Map
();
}
this
.
_inCreate
=
false
;
}
_getAllLevelHooks
(
hookMap
,
cache
,
type
)
{
const
cacheEntry
=
cache
.
get
(
type
);
if
(
cacheEntry
!==
undefined
)
{
return
cacheEntry
;
}
const
hooks
=
[];
const
typeParts
=
type
.
split
(
"."
);
for
(
let
i
=
0
;
i
<
typeParts
.
length
;
i
++
)
{
const
hook
=
hookMap
.
get
(
typeParts
.
slice
(
i
).
join
(
"."
));
if
(
hook
)
{
hooks
.
push
(
hook
);
}
}
cache
.
set
(
type
,
hooks
);
return
hooks
;
}
_forEachLevel
(
hookMap
,
cache
,
type
,
fn
)
{
for
(
const
hook
of
this
.
_getAllLevelHooks
(
hookMap
,
cache
,
type
))
{
const
result
=
fn
(
hook
);
if
(
result
!==
undefined
)
return
result
;
}
}
_forEachLevelWaterfall
(
hookMap
,
cache
,
type
,
data
,
fn
)
{
for
(
const
hook
of
this
.
_getAllLevelHooks
(
hookMap
,
cache
,
type
))
{
data
=
fn
(
hook
,
data
);
}
return
data
;
}
_forEachLevelFilter
(
hookMap
,
cache
,
type
,
items
,
fn
,
forceClone
)
{
const
hooks
=
this
.
_getAllLevelHooks
(
hookMap
,
cache
,
type
);
if
(
hooks
.
length
===
0
)
return
forceClone
?
items
.
slice
()
:
items
;
let
i
=
0
;
return
items
.
filter
((
item
,
idx
)
=>
{
for
(
const
hook
of
hooks
)
{
const
r
=
fn
(
hook
,
item
,
idx
,
i
);
if
(
r
!==
undefined
)
{
if
(
r
)
i
++
;
return
r
;
}
}
i
++
;
return
true
;
});
}
create
(
type
,
data
,
baseContext
)
{
if
(
this
.
_inCreate
)
{
return
this
.
_create
(
type
,
data
,
baseContext
);
}
else
{
try
{
this
.
_inCreate
=
true
;
return
this
.
_create
(
type
,
data
,
baseContext
);
}
finally
{
for
(
const
key
of
Object
.
keys
(
this
.
_caches
))
this
.
_caches
[
key
].
clear
();
this
.
_inCreate
=
false
;
}
}
}
_create
(
type
,
data
,
baseContext
)
{
const
context
=
{
...
baseContext
,
type
,
[
type
]
:
data
};
if
(
Array
.
isArray
(
data
))
{
// run filter on unsorted items
const
items
=
this
.
_forEachLevelFilter
(
this
.
hooks
.
filter
,
this
.
_caches
.
filter
,
type
,
data
,
(
h
,
r
,
idx
,
i
)
=>
h
.
call
(
r
,
context
,
idx
,
i
),
true
);
// sort items
const
comparators
=
[];
this
.
_forEachLevel
(
this
.
hooks
.
sort
,
this
.
_caches
.
sort
,
type
,
h
=>
h
.
call
(
comparators
,
context
)
);
if
(
comparators
.
length
>
0
)
{
items
.
sort
(
// @ts-expect-error number of arguments is correct
concatComparators
(...
comparators
,
keepOriginalOrder
(
items
))
);
}
// run filter on sorted items
const
items2
=
this
.
_forEachLevelFilter
(
this
.
hooks
.
filterSorted
,
this
.
_caches
.
filterSorted
,
type
,
items
,
(
h
,
r
,
idx
,
i
)
=>
h
.
call
(
r
,
context
,
idx
,
i
),
false
);
// for each item
let
resultItems
=
items2
.
map
((
item
,
i
)
=>
{
const
itemContext
=
{
...
context
,
_index
:
i
};
// run getItemName
const
itemName
=
this
.
_forEachLevel
(
this
.
hooks
.
getItemName
,
this
.
_caches
.
getItemName
,
`
$
{
type
}[]
`
,
h
=>
h
.
call
(
item
,
itemContext
)
);
if
(
itemName
)
itemContext
[
itemName
]
=
item
;
const
innerType
=
itemName
?
`
$
{
type
}[].
$
{
itemName
}
`
:
`
$
{
type
}[]
`
;
// run getItemFactory
const
itemFactory
=
this
.
_forEachLevel
(
this
.
hooks
.
getItemFactory
,
this
.
_caches
.
getItemFactory
,
innerType
,
h
=>
h
.
call
(
item
,
itemContext
)
)
||
this
;
// run item factory
return
itemFactory
.
create
(
innerType
,
item
,
itemContext
);
});
// sort result items
const
comparators2
=
[];
this
.
_forEachLevel
(
this
.
hooks
.
sortResults
,
this
.
_caches
.
sortResults
,
type
,
h
=>
h
.
call
(
comparators2
,
context
)
);
if
(
comparators2
.
length
>
0
)
{
resultItems
.
sort
(
// @ts-expect-error number of arguments is correct
concatComparators
(...
comparators2
,
keepOriginalOrder
(
resultItems
))
);
}
// group result items
const
groupConfigs
=
[];
this
.
_forEachLevel
(
this
.
hooks
.
groupResults
,
this
.
_caches
.
groupResults
,
type
,
h
=>
h
.
call
(
groupConfigs
,
context
)
);
if
(
groupConfigs
.
length
>
0
)
{
resultItems
=
smartGrouping
(
resultItems
,
groupConfigs
);
}
// run filter on sorted result items
const
finalResultItems
=
this
.
_forEachLevelFilter
(
this
.
hooks
.
filterResults
,
this
.
_caches
.
filterResults
,
type
,
resultItems
,
(
h
,
r
,
idx
,
i
)
=>
h
.
call
(
r
,
context
,
idx
,
i
),
false
);
// run merge on mapped items
let
result
=
this
.
_forEachLevel
(
this
.
hooks
.
merge
,
this
.
_caches
.
merge
,
type
,
h
=>
h
.
call
(
finalResultItems
,
context
)
);
if
(
result
===
undefined
)
result
=
finalResultItems
;
// run result on merged items
return
this
.
_forEachLevelWaterfall
(
this
.
hooks
.
result
,
this
.
_caches
.
result
,
type
,
result
,
(
h
,
r
)
=>
h
.
call
(
r
,
context
)
);
}
else
{
const
object
=
{};
// run extract on value
this
.
_forEachLevel
(
this
.
hooks
.
extract
,
this
.
_caches
.
extract
,
type
,
h
=>
h
.
call
(
object
,
data
,
context
)
);
// run result on extracted object
return
this
.
_forEachLevelWaterfall
(
this
.
hooks
.
result
,
this
.
_caches
.
result
,
type
,
object
,
(
h
,
r
)
=>
h
.
call
(
r
,
context
)
);
}
}
}
module
.
exports
=
StatsFactory
;
Event Timeline
Log In to Comment