mirror of
https://github.com/flynx/actions.js.git
synced 2025-10-28 18:00:11 +00:00
cleanup and some refactoring...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
677260e50b
commit
b97550d36a
379
actions.js
379
actions.js
@ -11,334 +11,10 @@ var object = require('ig-object')
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************/
|
|
||||||
|
|
||||||
// Return value wrapper...
|
|
||||||
//
|
|
||||||
// Wrapping a value in this and returning it from an action will force
|
|
||||||
// the action to return the value as-is...
|
|
||||||
// This is mainly usefull for specially handled values.
|
|
||||||
var ASIS =
|
|
||||||
module.ASIS =
|
|
||||||
object.Constructor('ASIS', {
|
|
||||||
__init__: function(obj){ this.value = obj } })
|
|
||||||
|
|
||||||
// undefined wrapper...
|
|
||||||
var UNDEFINED =
|
|
||||||
module.UNDEFINED = ASIS(undefined)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************/
|
|
||||||
// XXX should we maintain two sets of docs, here and in README.md???
|
|
||||||
//
|
|
||||||
// Actions
|
|
||||||
//
|
|
||||||
// Actions are an extension to the JavaScript object model tailored for
|
|
||||||
// a set of specific tasks.
|
|
||||||
//
|
|
||||||
// Goals:
|
|
||||||
// - provide a unified mechanism to define and manage user API's for
|
|
||||||
// use in UI-hooks, keyboard mappings, scripting, ... etc.
|
|
||||||
// - a means to generate configuration UI's
|
|
||||||
// - a means to generate documentation
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// The main entities:
|
|
||||||
//
|
|
||||||
// Action set
|
|
||||||
// - an object containing a number of actions,
|
|
||||||
// - optionally, directly or indirectly inherited from MetaActions
|
|
||||||
// and/or other action sets,
|
|
||||||
// - the action handlers are bound relative to it (._action_handlers)
|
|
||||||
//
|
|
||||||
// Action
|
|
||||||
//
|
|
||||||
// + pre + pre + + post + post +
|
|
||||||
// Action event handler: o-------x o-------x
|
|
||||||
// v ^
|
|
||||||
// Actions o-------x o-------x
|
|
||||||
// v ^
|
|
||||||
// Root Action o---|---x
|
|
||||||
//
|
|
||||||
// - a method, created by Action(..),
|
|
||||||
// - calls all the shadowed/overloaded actions in the inheritance
|
|
||||||
// chain in sequence implicitly,
|
|
||||||
// NOTE: there is no way to prevent an action in the chain from
|
|
||||||
// running, this is by design, i.e. no way to fully shadow.
|
|
||||||
// - actions that do not shadow anything are called root actions.
|
|
||||||
// - returns the action set by default (for call chaining),
|
|
||||||
// - the base/root action can return any value.
|
|
||||||
// NOTE: if undefined is returned, it will be replaced by the
|
|
||||||
// action context/action set.
|
|
||||||
// NOTE: there is no distinction between root and other actions
|
|
||||||
// other than that root action's return values are not
|
|
||||||
// ignored.
|
|
||||||
// - if the root action returns a Promise, the post phase is run
|
|
||||||
// when that promise is resolved or rejected.
|
|
||||||
// This can be disabled by setting the 'await' action attribute
|
|
||||||
// to false (default: true).
|
|
||||||
// - can consist of two parts: the first is called before the
|
|
||||||
// shadowed action (pre-callback) and the second after (post-callback).
|
|
||||||
// - post-callback has access to the return value and can modify it
|
|
||||||
// but not replace it.
|
|
||||||
// - can be bound to, a-la an event, calling the handlers when it is
|
|
||||||
// called,
|
|
||||||
//
|
|
||||||
// Action (event) handler
|
|
||||||
// - a function,
|
|
||||||
// - can be bound to run before and/or after the action itself,
|
|
||||||
// - is local to an action set it was bound via,
|
|
||||||
// - when an action is triggered from an action set, all the pre
|
|
||||||
// handlers in its inheritance chain will be called before the
|
|
||||||
// respective actions they are bound to and all the post handlers
|
|
||||||
// are called directly after.
|
|
||||||
// - pre handlers are passed the same arguments the original actions
|
|
||||||
// got when it was called.
|
|
||||||
// - post action handlers will get the root action result as first
|
|
||||||
// argument succeeded by the action arguments.
|
|
||||||
//
|
|
||||||
// Alias
|
|
||||||
// - an action created by Alias(..),
|
|
||||||
// - identical to an action with one key difference: instead of a
|
|
||||||
// function Alias(..) expects a string/code,
|
|
||||||
// - code syntax is configurable, defaulting to the defined by
|
|
||||||
// parseActionCall(..)
|
|
||||||
// - aliases are designed to be defined and managed in runtime while
|
|
||||||
// actions are mainly load-time entities.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// The action system main protocols:
|
|
||||||
//
|
|
||||||
// 1) Documentation generation and introspection (MetaActions)
|
|
||||||
//
|
|
||||||
// <action>.toString()
|
|
||||||
// -> code of original action function
|
|
||||||
//
|
|
||||||
// <action-set>.getDoc()
|
|
||||||
// <action-set>.getDoc(<action-name>[, ..])
|
|
||||||
// -> dict of action-name, doc
|
|
||||||
//
|
|
||||||
// <action-set>.a.getHandlerDocStr(<action-name>)
|
|
||||||
// -> formated string of action handlers
|
|
||||||
//
|
|
||||||
// <action-set>.actions
|
|
||||||
// -> list of action names
|
|
||||||
//
|
|
||||||
// <action-set>.length
|
|
||||||
// -> number of actions
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// 2) Event-like callbacks for actions (MetaActions, Action)
|
|
||||||
//
|
|
||||||
// <action-set>.on('action', function(){ ... })
|
|
||||||
// <action-set>.on('action.post', function(){ ... })
|
|
||||||
//
|
|
||||||
// <action-set>.on('action.pre', function(){ ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// 3) A mechanism to define and extend already defined actions
|
|
||||||
// This replaces / complements the standard JavaScript overloading
|
|
||||||
// mechanisms (Action, Actions)
|
|
||||||
//
|
|
||||||
// // Actions...
|
|
||||||
// var X = Actions({
|
|
||||||
// m: [function(){ console.log('m') }]
|
|
||||||
// })
|
|
||||||
// var O = Actions(X, {
|
|
||||||
// m: [function(){
|
|
||||||
// console.log('pre')
|
|
||||||
// return function(res){
|
|
||||||
// console.log('post')
|
|
||||||
// }
|
|
||||||
// }]
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// NOTE: what is done here is similar to calling O.__proto__.m.call(..)
|
|
||||||
// but is implicit, and not dependant on the original containing
|
|
||||||
// object name/reference ('O'), thus enabling an action to be
|
|
||||||
// referenced and called from any object and still chain correctly.
|
|
||||||
// NOTE: if a normal method is encountered in the inheritance chain, it
|
|
||||||
// will shadow all the actions beyond it.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Secondary action protocols:
|
|
||||||
//
|
|
||||||
// 1) A mechanism to manually call the pre/post stages of an action
|
|
||||||
//
|
|
||||||
// Pre phase...
|
|
||||||
// <action>.pre(<context>)
|
|
||||||
// <action>.pre(<context>, [<arg>, ..])
|
|
||||||
// -> <call-data>
|
|
||||||
//
|
|
||||||
// Post phase...
|
|
||||||
// <action>.post(<context>, <call-data>)
|
|
||||||
// -> <result>
|
|
||||||
//
|
|
||||||
// This is internally used to implement the action call as well as the
|
|
||||||
// chaining callbacks (see below).
|
|
||||||
//
|
|
||||||
// All action protocol details apply.
|
|
||||||
//
|
|
||||||
// NOTE: there is not reliable way to call the post phase without first
|
|
||||||
// calling the pre phase due to how the pre phase is defined (i.e.
|
|
||||||
// pre phase functions can return post phase functions).
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// 2) A mechanism to chain/wrap actions or an action and a function.
|
|
||||||
// This enables us to call a callback or another action (inner) between
|
|
||||||
// the root action's (outer) pre and post stages.
|
|
||||||
//
|
|
||||||
// Outer action o-------x o-------x
|
|
||||||
// v ^
|
|
||||||
// Inner action/callback o---|---x
|
|
||||||
//
|
|
||||||
// A trivial example:
|
|
||||||
//
|
|
||||||
// actionSet.someAction.chainApply(actionsSet,
|
|
||||||
// function(){
|
|
||||||
// // this gets run between someAction's pre and post
|
|
||||||
// // stages...
|
|
||||||
// },
|
|
||||||
// args)
|
|
||||||
//
|
|
||||||
// This is intended to implement protocols where a single action is
|
|
||||||
// intended to act as a hook point (outer) and multiple different
|
|
||||||
// implementations (inner) within a single action set can be used as
|
|
||||||
// entry points.
|
|
||||||
//
|
|
||||||
// // Protocol root action (outer) definition...
|
|
||||||
// protocolAction: [function(){}],
|
|
||||||
//
|
|
||||||
// // Implementation actions (inner)...
|
|
||||||
// implementationAction1: [function(){
|
|
||||||
// return this.protocolAction.chainApply(this, function(){
|
|
||||||
// // ...
|
|
||||||
// }, ..)
|
|
||||||
// }]
|
|
||||||
//
|
|
||||||
// implementationAction2: [function(){
|
|
||||||
// return this.protocolAction.chainApply(this, function(){
|
|
||||||
// // ...
|
|
||||||
// }, ..)
|
|
||||||
// }]
|
|
||||||
//
|
|
||||||
// Now calling any of the 'implementation' actions will execute code
|
|
||||||
// in the following order:
|
|
||||||
// 1) pre phase of protocol action (outer)
|
|
||||||
// 2) implementation action (inner)
|
|
||||||
// 3) post phase of protocol action (outer)
|
|
||||||
//
|
|
||||||
// Differences form the base action protocol:
|
|
||||||
// - returning undefined from inner will keep the outer return value.
|
|
||||||
// ...this is different from the base action protocol where returning
|
|
||||||
// undefined will get replaces by the context (this), here to
|
|
||||||
// guarantee returning the context, it should be returned explicitly,
|
|
||||||
// otherwise the responsibility is shifted to the outer action.
|
|
||||||
// - returning anything else will override the outer return
|
|
||||||
//
|
|
||||||
// NOTE: this will not affect to protocol/signature of the outer action
|
|
||||||
// in any way other than the ability to override the return value.
|
|
||||||
// NOTE: both the inner and outer actions will get passed the same
|
|
||||||
// arguments.
|
|
||||||
// NOTE: another use-case is testing/debugging actions.
|
|
||||||
// NOTE: this is effectively the inside-out of normal action overloading.
|
|
||||||
// NOTE: there is intentionally no shorthand for this feature, to avoid
|
|
||||||
// confusion and to discourage the use of this feature unless
|
|
||||||
// really necessary.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// 3) .__actioncall__ action / handler
|
|
||||||
// This action if defined is called for every action called. It behaves
|
|
||||||
// like any other action but with a fixed signature, it always receives
|
|
||||||
// the action name as first argument and a list of action arguments as
|
|
||||||
// the second arguments, and as normal a result on the post phase.
|
|
||||||
//
|
|
||||||
// NOTE: it is not necessary to define the actual action, binding to a
|
|
||||||
// handler will also work.
|
|
||||||
// NOTE: one should not call actions directly from within a __actioncall__
|
|
||||||
// handler as that will result in infinite recursion.
|
|
||||||
// XXX need a way to prevent this...
|
|
||||||
// NOTE: one should use this with extreme care as this will introduce
|
|
||||||
// an overhead on all the actions if not done carefully.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// 4) Action attributes
|
|
||||||
// XXX
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// 5) After action calls...
|
|
||||||
// This enables the action code to schedule a call after the current
|
|
||||||
// action level or the root action is done.
|
|
||||||
//
|
|
||||||
// .afterAction(func)
|
|
||||||
// .afterAction('top', func)
|
|
||||||
// -> this
|
|
||||||
//
|
|
||||||
// .afterAction('local', func)
|
|
||||||
// -> this
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// someAction: [
|
|
||||||
// function(){
|
|
||||||
// ...
|
|
||||||
//
|
|
||||||
// // the function passed will get called after the root action
|
|
||||||
// // and all it's handlers are done.
|
|
||||||
// this.afterAction(function(){ ... })
|
|
||||||
//
|
|
||||||
// ...
|
|
||||||
// }],
|
|
||||||
//
|
|
||||||
// NOTE: the functions are executed in order of registration.
|
|
||||||
// XXX EXPERIMENTAL (handler cache)...
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Alias protocols:
|
|
||||||
//
|
|
||||||
// 1) Defining aliases in runtime (MetaActions)
|
|
||||||
//
|
|
||||||
// <action-set>.alias('alias', 'action: args')
|
|
||||||
// <action-set>.alias('alias', .., 'action: args')
|
|
||||||
// -> <action-set>
|
|
||||||
//
|
|
||||||
// To enable extending in runtime .alias(..) itself is implemented as
|
|
||||||
// an action, thus all action protocols also apply.
|
|
||||||
//
|
|
||||||
// NOTE: .alias(..) is signature compatible to Action(..) / Alias(..),
|
|
||||||
// supporting all the documentation and attribute definition.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// 2) Deleting aliases in runtime (MetaActions)
|
|
||||||
//
|
|
||||||
// <action-set>.alias('alias', null)
|
|
||||||
// <action-set>.alias('alias', false)
|
|
||||||
// -> <action-set>
|
|
||||||
//
|
|
||||||
// NOTE: only own aliases can be deleted via .alias(.., null|false)
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// 3) Documentation generation and introspection (MetaActions, Alias)
|
|
||||||
//
|
|
||||||
// Alias code...
|
|
||||||
// <alias>.alias
|
|
||||||
// <alias>.toString()
|
|
||||||
// -> <code>
|
|
||||||
//
|
|
||||||
// List own aliases...
|
|
||||||
// <action-set>.aliases
|
|
||||||
// -> <action-set>
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
// helpers...
|
// helpers...
|
||||||
|
|
||||||
var normalizeIndent = object.normalizeIndent
|
// XXX doc...
|
||||||
|
|
||||||
|
|
||||||
var doWithRootAction =
|
var doWithRootAction =
|
||||||
module.doWithRootAction =
|
module.doWithRootAction =
|
||||||
function(func){
|
function(func){
|
||||||
@ -347,12 +23,19 @@ function(func){
|
|||||||
var handlers = (this.getHandlerList
|
var handlers = (this.getHandlerList
|
||||||
|| MetaActions.getHandlerList)
|
|| MetaActions.getHandlerList)
|
||||||
.apply(this, args)
|
.apply(this, args)
|
||||||
|
|
||||||
return func.apply(this, [handlers.pop()].concat(args)) } }
|
return func.apply(this, [handlers.pop()].concat(args)) } }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------
|
||||||
// String action parser/runner...
|
// String action parser/runner...
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
// 'actionName'
|
||||||
|
// 'actionName: attr 123 "string" -- comment...'
|
||||||
|
// 'actionName: ...'
|
||||||
//
|
//
|
||||||
|
//
|
||||||
// Syntax:
|
// Syntax:
|
||||||
// ALIAS ::=
|
// ALIAS ::=
|
||||||
// <action-name>
|
// <action-name>
|
||||||
@ -387,6 +70,7 @@ function(func){
|
|||||||
// code: txt,
|
// code: txt,
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
//
|
||||||
// NOTE: identifiers are resolved as attributes of the context...
|
// NOTE: identifiers are resolved as attributes of the context...
|
||||||
// NOTE: this is a stateless object...
|
// NOTE: this is a stateless object...
|
||||||
// XXX this is the same as ImageGrid's keyboard.parseActionCall(..), reuse
|
// XXX this is the same as ImageGrid's keyboard.parseActionCall(..), reuse
|
||||||
@ -533,6 +217,22 @@ module.isStringAction =
|
|||||||
|
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
|
// Action...
|
||||||
|
|
||||||
|
// Return value wrapper...
|
||||||
|
//
|
||||||
|
// Wrapping a value in this and returning it from an action will force
|
||||||
|
// the action to return the value as-is...
|
||||||
|
// This is mainly usefull for specially handled values.
|
||||||
|
var ASIS =
|
||||||
|
module.ASIS =
|
||||||
|
object.Constructor('ASIS', {
|
||||||
|
__init__: function(obj){ this.value = obj } })
|
||||||
|
|
||||||
|
// undefined wrapper...
|
||||||
|
var UNDEFINED =
|
||||||
|
module.UNDEFINED = ASIS(undefined)
|
||||||
|
|
||||||
|
|
||||||
// Construct an action object...
|
// Construct an action object...
|
||||||
//
|
//
|
||||||
@ -997,7 +697,7 @@ object.Constructor('Action', {
|
|||||||
|
|
||||||
// make introspection be a bit better...
|
// make introspection be a bit better...
|
||||||
meth.toString = function(){
|
meth.toString = function(){
|
||||||
return normalizeIndent(func.toString()) }
|
return object.normalizeIndent(func.toString()) }
|
||||||
|
|
||||||
// setup attrs...
|
// setup attrs...
|
||||||
Object.assign(meth, attrs)
|
Object.assign(meth, attrs)
|
||||||
@ -1561,6 +1261,7 @@ module.MetaActions = {
|
|||||||
// NOTE: the object result must be compatible with Action.pre(..)
|
// NOTE: the object result must be compatible with Action.pre(..)
|
||||||
// return value...
|
// return value...
|
||||||
// NOTE: this is mostly a stub, here for documentation reasons...
|
// NOTE: this is mostly a stub, here for documentation reasons...
|
||||||
|
// XXX doc / revise...
|
||||||
//preActionHandler: doWithRootAction(
|
//preActionHandler: doWithRootAction(
|
||||||
// function(action, name, handlers, args){ return null }),
|
// function(action, name, handlers, args){ return null }),
|
||||||
|
|
||||||
@ -2183,19 +1884,19 @@ module.MetaActions = {
|
|||||||
|
|
||||||
var getTags = function(handler, p){
|
var getTags = function(handler, p){
|
||||||
return (handler.event_tag ?
|
return (handler.event_tag ?
|
||||||
normalizeIndent('// Event tag: ' + handler.event_tag) + p
|
object.normalizeIndent('// Event tag: ' + handler.event_tag) + p
|
||||||
: '')
|
: '')
|
||||||
+ (handler.source_tag ?
|
+ (handler.source_tag ?
|
||||||
normalizeIndent('// Source tag: ' + handler.source_tag) + p
|
object.normalizeIndent('// Source tag: ' + handler.source_tag) + p
|
||||||
: '') }
|
: '') }
|
||||||
var getDoc = function(cur, p){
|
var getDoc = function(cur, p){
|
||||||
return (cur.doc ?
|
return (cur.doc ?
|
||||||
'// --- .doc ---'+p
|
'// --- .doc ---'+p
|
||||||
+'// '+ normalizeIndent(cur.doc).replace(/\n/g, p+'// ') +p
|
+'// '+ object.normalizeIndent(cur.doc).replace(/\n/g, p+'// ') +p
|
||||||
: '')
|
: '')
|
||||||
+ (cur.long_doc ?
|
+ (cur.long_doc ?
|
||||||
'// --- .long_doc ---'+p
|
'// --- .long_doc ---'+p
|
||||||
+'// '+ normalizeIndent(cur.long_doc).replace(/\n/g, p+'// ') + p
|
+'// '+ object.normalizeIndent(cur.long_doc).replace(/\n/g, p+'// ') + p
|
||||||
: '') }
|
: '') }
|
||||||
|
|
||||||
var handler = function(p){
|
var handler = function(p){
|
||||||
@ -2214,7 +1915,7 @@ module.MetaActions = {
|
|||||||
+ getTags(cur.pre, p)
|
+ getTags(cur.pre, p)
|
||||||
+ getDoc(cur, p)
|
+ getDoc(cur, p)
|
||||||
// code...
|
// code...
|
||||||
+ normalizeIndent(cur.pre.toString()).replace(/\n/g, p)
|
+ object.normalizeIndent(cur.pre.toString()).replace(/\n/g, p)
|
||||||
+ p
|
+ p
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2227,7 +1928,7 @@ module.MetaActions = {
|
|||||||
+ getTags(cur.post, p)
|
+ getTags(cur.post, p)
|
||||||
+ getDoc(cur, p)
|
+ getDoc(cur, p)
|
||||||
// code...
|
// code...
|
||||||
+ normalizeIndent(cur.post.toString()).replace(/\n/g, p)
|
+ object.normalizeIndent(cur.post.toString()).replace(/\n/g, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2252,11 +1953,11 @@ module.MetaActions = {
|
|||||||
p.append($('<pre>').html(
|
p.append($('<pre>').html(
|
||||||
// meta...
|
// meta...
|
||||||
(cur.pre.event_tag ?
|
(cur.pre.event_tag ?
|
||||||
normalizeIndent('// Event tag: ' + cur.pre.event_tag) + p : '')
|
object.normalizeIndent('// Event tag: ' + cur.pre.event_tag) + p : '')
|
||||||
+ (cur.pre.source_tag ?
|
+ (cur.pre.source_tag ?
|
||||||
normalizeIndent('// Source tag: ' + cur.pre.source_tag) + p : '')
|
object.normalizeIndent('// Source tag: ' + cur.pre.source_tag) + p : '')
|
||||||
// code...
|
// code...
|
||||||
+ normalizeIndent(cur.pre.toString())
|
+ object.normalizeIndent(cur.pre.toString())
|
||||||
.replace(/return/g, '<b>return</b>')))
|
.replace(/return/g, '<b>return</b>')))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2266,11 +1967,11 @@ module.MetaActions = {
|
|||||||
p.append($('<pre>').html(
|
p.append($('<pre>').html(
|
||||||
// meta...
|
// meta...
|
||||||
(cur.post.event_tag ?
|
(cur.post.event_tag ?
|
||||||
normalizeIndent('// Event source tag: ' + cur.post.event_tag) + p : '')
|
object.normalizeIndent('// Event source tag: ' + cur.post.event_tag) + p : '')
|
||||||
+ (cur.post.source_tag ?
|
+ (cur.post.source_tag ?
|
||||||
normalizeIndent('// Source tag: ' + cur.post.source_tag) + p : '')
|
object.normalizeIndent('// Source tag: ' + cur.post.source_tag) + p : '')
|
||||||
// code...
|
// code...
|
||||||
+ normalizeIndent(cur.post.toString())))
|
+ object.normalizeIndent(cur.post.toString())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ig-actions",
|
"name": "ig-actions",
|
||||||
"version": "3.24.7",
|
"version": "3.24.8",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "actions.js",
|
"main": "actions.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user