keycomfort 0.3.0 → 0.5.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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';var require$$0$1=require('node:process'),require$$1=require('node:child_process'),require$$3=require('node:fs'),require$$2=require('node:path'),require$$4$1=require('node:readline'),require$$0=require('node:events'),require$$2$1=require('node:os'),require$$4=require('node:fs/promises'),require$$6$1=require('node:stream'),require$$7=require('node:assert');function getDefaultExportFromCjs (x) {
2
+ 'use strict';var require$$0$1=require('node:process'),require$$1=require('node:child_process'),require$$3=require('node:fs'),require$$3$1=require('node:path'),require$$4$1=require('node:readline'),require$$0=require('node:events'),require$$0$2=require('node:os'),require$$2=require('node:fs/promises'),require$$4=require('node:stream'),require$$7=require('node:assert');function getDefaultExportFromCjs (x) {
3
3
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
4
4
  }
5
5
 
@@ -1485,7 +1485,7 @@ function requireCommand () {
1485
1485
  hasRequiredCommand = 1;
1486
1486
  const EventEmitter = require$$0.EventEmitter;
1487
1487
  const childProcess = require$$1;
1488
- const path = require$$2;
1488
+ const path = require$$3$1;
1489
1489
  const fs = require$$3;
1490
1490
  const process = require$$0$1;
1491
1491
 
@@ -4955,7 +4955,7 @@ function toJS(value, arg, ctx) {
4955
4955
  data = anchors.get(source);
4956
4956
  }
4957
4957
  /* istanbul ignore if */
4958
- if (!data || data.res === undefined) {
4958
+ if (data?.res === undefined) {
4959
4959
  const msg = 'This should not happen: Alias anchor was not resolved?';
4960
4960
  throw new ReferenceError(msg);
4961
4961
  }
@@ -5951,7 +5951,7 @@ function stringify$2(item, ctx, onComment, onChompKeep) {
5951
5951
  ws += `\n${indentComment(cs, ctx.indent)}`;
5952
5952
  }
5953
5953
  if (valueStr === '' && !ctx.inFlow) {
5954
- if (ws === '\n')
5954
+ if (ws === '\n' && valueComment)
5955
5955
  ws = '\n\n';
5956
5956
  }
5957
5957
  else {
@@ -6573,7 +6573,7 @@ function asItemIndex(key) {
6573
6573
  const num = typeof value === 'number' ? value : Number(value);
6574
6574
  if (!isFinite(num))
6575
6575
  return isNaN(num) ? '.nan' : num < 0 ? '-.inf' : '.inf';
6576
- let n = JSON.stringify(value);
6576
+ let n = Object.is(value, -0) ? '-0' : JSON.stringify(value);
6577
6577
  if (!format &&
6578
6578
  minFractionDigits &&
6579
6579
  (!tag || tag === 'tag:yaml.org,2002:float') &&
@@ -7793,7 +7793,7 @@ const prettifyError = (src, lc) => (error) => {
7793
7793
  if (/[^ ]/.test(lineStr)) {
7794
7794
  let count = 1;
7795
7795
  const end = error.linePos[1];
7796
- if (end && end.line === line && end.col > col) {
7796
+ if (end?.line === line && end.col > col) {
7797
7797
  count = Math.max(1, Math.min(end.col - col, 80 - ci));
7798
7798
  }
7799
7799
  const pointer = ' '.repeat(ci) + '^'.repeat(count);
@@ -8116,7 +8116,7 @@ function resolveBlockMap({ composeNode, composeEmptyNode }, ctx, bm, onError, ta
8116
8116
  });
8117
8117
  if (!props.found) {
8118
8118
  if (props.anchor || props.tag || value) {
8119
- if (value && value.type === 'block-seq')
8119
+ if (value?.type === 'block-seq')
8120
8120
  onError(props.end, 'BAD_INDENT', 'All sequence items must start at the same column');
8121
8121
  else
8122
8122
  onError(offset, 'MISSING_CHAR', 'Sequence item without - indicator');
@@ -8298,7 +8298,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
8298
8298
  }
8299
8299
  }
8300
8300
  else if (value) {
8301
- if ('source' in value && value.source && value.source[0] === ':')
8301
+ if ('source' in value && value.source?.[0] === ':')
8302
8302
  onError(value, 'MISSING_CHAR', `Missing space after : in ${fcName}`);
8303
8303
  else
8304
8304
  onError(valueProps.start, 'MISSING_CHAR', `Missing , or : between ${fcName} items`);
@@ -8342,7 +8342,7 @@ function resolveFlowCollection({ composeNode, composeEmptyNode }, ctx, fc, onErr
8342
8342
  const expectedEnd = isMap ? '}' : ']';
8343
8343
  const [ce, ...ee] = fc.end;
8344
8344
  let cePos = offset;
8345
- if (ce && ce.source === expectedEnd)
8345
+ if (ce?.source === expectedEnd)
8346
8346
  cePos = ce.offset + ce.source.length;
8347
8347
  else {
8348
8348
  const name = fcName[0].toUpperCase() + fcName.substring(1);
@@ -8420,7 +8420,7 @@ function composeCollection(CN, ctx, token, props, onError) {
8420
8420
  let tag = ctx.schema.tags.find(t => t.tag === tagName && t.collection === expType);
8421
8421
  if (!tag) {
8422
8422
  const kt = ctx.schema.knownTags[tagName];
8423
- if (kt && kt.collection === expType) {
8423
+ if (kt?.collection === expType) {
8424
8424
  ctx.schema.tags.push(Object.assign({}, kt, { default: false }));
8425
8425
  tag = kt;
8426
8426
  }
@@ -10711,7 +10711,7 @@ class Parser {
10711
10711
  }
10712
10712
  *step() {
10713
10713
  const top = this.peek(1);
10714
- if (this.type === 'doc-end' && (!top || top.type !== 'doc-end')) {
10714
+ if (this.type === 'doc-end' && top?.type !== 'doc-end') {
10715
10715
  while (this.stack.length > 0)
10716
10716
  yield* this.pop();
10717
10717
  this.stack.push({
@@ -11243,7 +11243,7 @@ class Parser {
11243
11243
  do {
11244
11244
  yield* this.pop();
11245
11245
  top = this.peek(1);
11246
- } while (top && top.type === 'flow-collection');
11246
+ } while (top?.type === 'flow-collection');
11247
11247
  }
11248
11248
  else if (fc.end.length === 0) {
11249
11249
  switch (this.type) {
@@ -11540,15 +11540,210 @@ function stringify(value, replacer, options) {
11540
11540
  return new Document(value, _replacer, options).toString(options);
11541
11541
  }var YAML=/*#__PURE__*/Object.freeze({__proto__:null,Alias:Alias,CST:cst,Composer:Composer,Document:Document,Lexer:Lexer,LineCounter:LineCounter,Pair:Pair,Parser:Parser,Scalar:Scalar,Schema:Schema,YAMLError:YAMLError,YAMLMap:YAMLMap,YAMLParseError:YAMLParseError,YAMLSeq:YAMLSeq,YAMLWarning:YAMLWarning,isAlias:isAlias,isCollection:isCollection$1,isDocument:isDocument,isMap:isMap,isNode:isNode,isPair:isPair,isScalar:isScalar$1,isSeq:isSeq,parse:parse,parseAllDocuments:parseAllDocuments,parseDocument:parseDocument,stringify:stringify,visit:visit$1,visitAsync:visitAsync});// `export * as default from ...` fails on Webpack v4
11542
11542
  // https://github.com/eemeli/yaml/issues/228
11543
- var browser=/*#__PURE__*/Object.freeze({__proto__:null,Alias:Alias,CST:cst,Composer:Composer,Document:Document,Lexer:Lexer,LineCounter:LineCounter,Pair:Pair,Parser:Parser,Scalar:Scalar,Schema:Schema,YAMLError:YAMLError,YAMLMap:YAMLMap,YAMLParseError:YAMLParseError,YAMLSeq:YAMLSeq,YAMLWarning:YAMLWarning,default:YAML,isAlias:isAlias,isCollection:isCollection$1,isDocument:isDocument,isMap:isMap,isNode:isNode,isPair:isPair,isScalar:isScalar$1,isSeq:isSeq,parse:parse,parseAllDocuments:parseAllDocuments,parseDocument:parseDocument,stringify:stringify,visit:visit$1,visitAsync:visitAsync});var require$$6 = /*@__PURE__*/getAugmentedNamespace(browser);var bundle$2 = {};var hasRequiredBundle$2;
11543
+ var browser=/*#__PURE__*/Object.freeze({__proto__:null,Alias:Alias,CST:cst,Composer:Composer,Document:Document,Lexer:Lexer,LineCounter:LineCounter,Pair:Pair,Parser:Parser,Scalar:Scalar,Schema:Schema,YAMLError:YAMLError,YAMLMap:YAMLMap,YAMLParseError:YAMLParseError,YAMLSeq:YAMLSeq,YAMLWarning:YAMLWarning,default:YAML,isAlias:isAlias,isCollection:isCollection$1,isDocument:isDocument,isMap:isMap,isNode:isNode,isPair:isPair,isScalar:isScalar$1,isSeq:isSeq,parse:parse,parseAllDocuments:parseAllDocuments,parseDocument:parseDocument,stringify:stringify,visit:visit$1,visitAsync:visitAsync});var require$$6 = /*@__PURE__*/getAugmentedNamespace(browser);var amekusa_util = {};var hasRequiredAmekusa_util;
11544
11544
 
11545
- function requireBundle$2 () {
11546
- if (hasRequiredBundle$2) return bundle$2;
11547
- hasRequiredBundle$2 = 1;
11545
+ function requireAmekusa_util () {
11546
+ if (hasRequiredAmekusa_util) return amekusa_util;
11547
+ hasRequiredAmekusa_util = 1;
11548
+ var os=require$$0$2,fs=require$$3,fsp=require$$2,path=require$$3$1,node_stream=require$$4,node_process=require$$0$1,node_child_process=require$$1,assert=require$$7;function _interopNamespaceDefault(e){var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}});}n.default=e;return Object.freeze(n)}var fsp__namespace=/*#__PURE__*/_interopNamespaceDefault(fsp);/*!
11549
+ * === @amekusa/util.js/gen === *
11550
+ * MIT License
11551
+ *
11552
+ * Copyright (c) 2024 Satoshi Soma
11553
+ *
11554
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
11555
+ * of this software and associated documentation files (the "Software"), to deal
11556
+ * in the Software without restriction, including without limitation the rights
11557
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11558
+ * copies of the Software, and to permit persons to whom the Software is
11559
+ * furnished to do so, subject to the following conditions:
11560
+ *
11561
+ * The above copyright notice and this permission notice shall be included in all
11562
+ * copies or substantial portions of the Software.
11563
+ *
11564
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11565
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11566
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
11567
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11568
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
11569
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
11570
+ * SOFTWARE.
11571
+ */
11548
11572
 
11549
- Object.defineProperty(bundle$2, '__esModule', { value: true });
11573
+ /**
11574
+ * Coerces the given value into an array.
11575
+ * @param {any} x
11576
+ * @return {any[]}
11577
+ */
11578
+ function arr(x) {
11579
+ return Array.isArray(x) ? x : [x];
11580
+ }
11550
11581
 
11551
- /*!
11582
+ /**
11583
+ * Checks the type of the given value matches with one of the given types.
11584
+ * If a constructor is given to `types`, it checks if `x` is `instanceof` the constructor.
11585
+ * @param {any} x
11586
+ * @param {...string|function} types - Type or Constructor
11587
+ * @return {boolean}
11588
+ */
11589
+ function is(x, ...types) {
11590
+ let t = typeof x;
11591
+ for (let i = 0; i < types.length; i++) {
11592
+ let v = types[i];
11593
+ if (typeof v == 'string') {
11594
+ if (v == 'array') {
11595
+ if (Array.isArray(x)) return true;
11596
+ } else if (t == v) return true;
11597
+ } else if (x instanceof v) return true;
11598
+ }
11599
+ return false;
11600
+ }
11601
+
11602
+ /**
11603
+ * Returns whether the given value can be considered as "empty".
11604
+ * @param {any} x
11605
+ * @return {boolean}
11606
+ */
11607
+ function isEmpty(x) {
11608
+ if (Array.isArray(x)) return x.length == 0;
11609
+ switch (typeof x) {
11610
+ case 'string':
11611
+ return !x;
11612
+ case 'object':
11613
+ for (let _ in x) return false;
11614
+ return true;
11615
+ case 'undefined':
11616
+ return true;
11617
+ }
11618
+ return false;
11619
+ }
11620
+
11621
+ /**
11622
+ * Returns whether the given value can be considered as "empty" or "falsy".
11623
+ * Faster than {@link isEmpty}.
11624
+ * @param {any} x
11625
+ * @return {boolean}
11626
+ */
11627
+ function isEmptyOrFalsy(x) {
11628
+ if (!x) return true;
11629
+ if (Array.isArray(x)) return x.length == 0;
11630
+ if (typeof x == 'object') {
11631
+ for (let _ in x) return false;
11632
+ }
11633
+ return false;
11634
+ }
11635
+
11636
+ /**
11637
+ * @function isEmptyOrFalsey
11638
+ * Alias of {@link isEmptyOrFalsy}.
11639
+ */
11640
+ const isEmptyOrFalsey = isEmptyOrFalsy;
11641
+
11642
+ /**
11643
+ * Removes "empty" values from the given object or array.
11644
+ * @param {object|any[]} x
11645
+ * @param {number} recurse - Recursion limit
11646
+ * @return {object|any[]} modified `x`
11647
+ */
11648
+ function clean$1(x, recurse = 8) {
11649
+ if (recurse) {
11650
+ if (Array.isArray(x)) {
11651
+ let r = [];
11652
+ for (let i = 0; i < x.length; i++) {
11653
+ let v = clean$1(x[i], recurse - 1);
11654
+ if (!isEmpty(v)) r.push(v);
11655
+ }
11656
+ return r;
11657
+ }
11658
+ if (typeof x == 'object') {
11659
+ let r = {};
11660
+ for (let k in x) {
11661
+ let v = clean$1(x[k], recurse - 1);
11662
+ if (!isEmpty(v)) r[k] = v;
11663
+ }
11664
+ return r;
11665
+ }
11666
+ }
11667
+ return x;
11668
+ }
11669
+
11670
+ /**
11671
+ * Merges the 2nd object into the 1st object recursively (deep-merge). The 1st object will be modified.
11672
+ * @param {object} x - The 1st object
11673
+ * @param {object} y - The 2nd object
11674
+ * @param {object} [opts] - Options
11675
+ * @param {number} opts.recurse=8 - Recurstion limit. Negative number means unlimited
11676
+ * @param {boolean|string} opts.mergeArrays - How to merge arrays
11677
+ * - `true`: merge x with y
11678
+ * - 'push': push y elements to x
11679
+ * - 'concat': concat x and y
11680
+ * - other: replace x with y
11681
+ * @return {object} The 1st object
11682
+ */
11683
+ function merge$1(x, y, opts = {}) {
11684
+ if (!('recurse' in opts)) opts.recurse = 8;
11685
+ switch (Array.isArray(x) + Array.isArray(y)) {
11686
+ case 0: // no array
11687
+ if (opts.recurse && x && y && typeof x == 'object' && typeof y == 'object') {
11688
+ opts.recurse--;
11689
+ for (let k in y) x[k] = merge$1(x[k], y[k], opts);
11690
+ opts.recurse++;
11691
+ return x;
11692
+ }
11693
+ case 1: // 1 array
11694
+ return y;
11695
+ }
11696
+ // 2 arrays
11697
+ switch (opts.mergeArrays) {
11698
+ case true:
11699
+ for (let i = 0; i < y.length; i++) {
11700
+ if (!x.includes(y[i])) x.push(y[i]);
11701
+ }
11702
+ return x;
11703
+ case 'push':
11704
+ x.push(...y);
11705
+ return x;
11706
+ case 'concat':
11707
+ return x.concat(y);
11708
+ }
11709
+ return y;
11710
+ }
11711
+
11712
+ /**
11713
+ * Gets a property from the given object by the given string path.
11714
+ * @param {object} obj - Object to traverse
11715
+ * @param {string} path - Property names separated with '.'
11716
+ * @return {any} value of the found property, or undefined if it's not found
11717
+ */
11718
+ function dig(obj, path) {
11719
+ path = path.split('.');
11720
+ for (let i = 0; i < path.length; i++) {
11721
+ let p = path[i];
11722
+ if (typeof obj == 'object' && p in obj) obj = obj[p];
11723
+ else return undefined;
11724
+ }
11725
+ return obj;
11726
+ }
11727
+
11728
+ /**
11729
+ * Substitutes the properties of the given data for the references in the given string.
11730
+ * @param {string} str - String that contains references to the properties
11731
+ * @param {object} data - Object that contains properties to replace the references
11732
+ * @param {object} [opts] - Options
11733
+ * @return {string} a modified `str`
11734
+ */
11735
+ function subst(str, data, opts = {}) {
11736
+ let {
11737
+ modifier = null,
11738
+ start = '{{',
11739
+ end = '}}',
11740
+ } = opts;
11741
+ let ref = new RegExp(start + '\\s*([-.\\w]+)\\s*' + end, 'g');
11742
+ return str.replaceAll(ref, modifier
11743
+ ? (_, m1) => (modifier(dig(data, m1), m1, data) || '')
11744
+ : (_, m1) => (dig(data, m1) || '')
11745
+ );
11746
+ }var gen=/*#__PURE__*/Object.freeze({__proto__:null,arr:arr,clean:clean$1,dig:dig,is:is,isEmpty:isEmpty,isEmptyOrFalsey:isEmptyOrFalsey,isEmptyOrFalsy:isEmptyOrFalsy,merge:merge$1,subst:subst});/*!
11552
11747
  * === @amekusa/util.js/web === *
11553
11748
  * MIT License
11554
11749
  *
@@ -11597,15 +11792,7 @@ function requireBundle$2 () {
11597
11792
  // - This avoids double-escaping '&' symbols
11598
11793
  // - Regex negative match: (?!word)
11599
11794
 
11600
- const escHTML_replace = found => `&${escHTML_map[found]};`;
11601
-
11602
- var web = /*#__PURE__*/Object.freeze({
11603
- __proto__: null,
11604
- escHTML: escHTML,
11605
- escHtml: escHtml
11606
- });
11607
-
11608
- /*!
11795
+ const escHTML_replace = found => `&${escHTML_map[found]};`;var web=/*#__PURE__*/Object.freeze({__proto__:null,escHTML:escHTML,escHtml:escHtml});/*!
11609
11796
  * === @amekusa/util.js/time === *
11610
11797
  * MIT License
11611
11798
  *
@@ -11775,25 +11962,8 @@ function requireBundle$2 () {
11775
11962
  */
11776
11963
  function iso9075(d) {
11777
11964
  return ymd(d, '-') + ' ' + hms(d, ':');
11778
- }
11779
-
11780
- var time = /*#__PURE__*/Object.freeze({
11781
- __proto__: null,
11782
- addTime: addTime,
11783
- ceil: ceil,
11784
- date: date,
11785
- floor: floor,
11786
- hms: hms,
11787
- iso9075: iso9075,
11788
- localize: localize,
11789
- ms: ms,
11790
- quantize: quantize,
11791
- round: round,
11792
- ymd: ymd
11793
- });
11794
-
11795
- /*!
11796
- * === @amekusa/util.js === *
11965
+ }var time=/*#__PURE__*/Object.freeze({__proto__:null,addTime:addTime,ceil:ceil,date:date,floor:floor,hms:hms,iso9075:iso9075,localize:localize,ms:ms,quantize:quantize,round:round,ymd:ymd});/*!
11966
+ * === @amekusa/util.js/sh === *
11797
11967
  * MIT License
11798
11968
  *
11799
11969
  * Copyright (c) 2024 Satoshi Soma
@@ -11818,278 +11988,318 @@ function requireBundle$2 () {
11818
11988
  */
11819
11989
 
11820
11990
  /**
11821
- * Coerces the given value into an array.
11822
- * @param {any} x
11823
- * @return {any[]}
11991
+ * Executes the given shell command, and returns a Promise that resolves the stdout
11992
+ * @param {string} cmd
11993
+ * @param {object} [opts]
11994
+ * @return {Promise}
11824
11995
  */
11825
- function arr(x) {
11826
- return Array.isArray(x) ? x : [x];
11996
+ function exec(cmd, opts = {}) {
11997
+ opts = Object.assign({
11998
+ dryRun: false,
11999
+ }, opts);
12000
+ return new Promise((resolve, reject) => {
12001
+ if (opts.dryRun) {
12002
+ console.log(`[DRYRUN] ${cmd}`);
12003
+ return resolve();
12004
+ }
12005
+ node_child_process.exec(cmd, (err, stdout) => {
12006
+ return err ? reject(err) : resolve(stdout);
12007
+ });
12008
+ });
11827
12009
  }
11828
12010
 
11829
12011
  /**
11830
- * Alias of `Array.isArray`.
11831
- * @return {boolean}
11832
- */
11833
- const isArray = Array.isArray;
11834
-
11835
- /**
11836
- * Returns whether the given value is a number or a string.
11837
- * @param {any} x
11838
- * @return {boolean}
12012
+ * Converts the given objects to shell arguments in a string form
12013
+ * @param {object} args
12014
+ * @param {object} [opts]
12015
+ * @return {string}
11839
12016
  */
11840
- function isNumOrStr(x) {
11841
- switch (typeof x) {
11842
- case 'number':
11843
- case 'string':
11844
- return true;
12017
+ function args(args, opts = {}) {
12018
+ opts = Object.assign({
12019
+ sep: ' ', // key-value separator
12020
+ }, opts);
12021
+ let r = [];
12022
+ for (let key in args) {
12023
+ let value = args[key];
12024
+ if (isNaN(key)) { // non-numeric key
12025
+ switch (typeof value) {
12026
+ case 'boolean':
12027
+ if (value) r.push(key);
12028
+ break;
12029
+ case 'number':
12030
+ r.push(key + opts.sep + value);
12031
+ break;
12032
+ case 'string':
12033
+ r.push(key + opts.sep + `"${value}"`);
12034
+ break;
12035
+ }
12036
+ } else { // numeric key
12037
+ r.push(value);
12038
+ }
11845
12039
  }
11846
- return false;
12040
+ return r.join(' ');
11847
12041
  }
11848
12042
 
11849
12043
  /**
11850
- * Returns whether the given value can be considered as "empty".
11851
- * @param {any} x
11852
- * @return {boolean}
12044
+ * Returns if NODE_ENV is 'production'
12045
+ * @param {any} [set]
12046
+ * @return {bool}
11853
12047
  */
11854
- function isEmpty(x) {
11855
- if (Array.isArray(x)) return x.length == 0;
11856
- switch (typeof x) {
11857
- case 'string':
11858
- return !x;
11859
- case 'object':
11860
- if (x === null) return true;
11861
- for (let i in x) return false;
11862
- case 'undefined':
11863
- return true;
11864
- }
11865
- return false;
12048
+ function prod(set = undefined) {
12049
+ let value = 'production';
12050
+ if (set != undefined) node_process.env.NODE_ENV = set ? value : '';
12051
+ return node_process.env.NODE_ENV == value;
11866
12052
  }
11867
12053
 
11868
12054
  /**
11869
- * Removes "empty" values from the given object or array.
11870
- * @param {object|any[]} x
11871
- * @param {number} recurse - Recursion limit
11872
- * @return {object|any[]} modified `x`
12055
+ * Returns if NODE_ENV is 'development'
12056
+ * @param {any} [set]
12057
+ * @return {bool}
11873
12058
  */
11874
- function clean(x, recurse = 8) {
11875
- if (recurse) {
11876
- if (Array.isArray(x)) {
11877
- let r = [];
11878
- for (let i = 0; i < x.length; i++) {
11879
- let I = clean(x[i], recurse - 1);
11880
- if (!isEmpty(I)) r.push(I);
11881
- }
11882
- return r;
11883
- }
11884
- if (typeof x == 'object') {
11885
- let r = {};
11886
- for (let k in x) {
11887
- let v = clean(x[k], recurse - 1);
11888
- if (!isEmpty(v)) r[k] = v;
11889
- }
11890
- return r;
11891
- }
11892
- }
11893
- return x;
11894
- }
11895
-
12059
+ function dev(set = undefined) {
12060
+ let value = 'development';
12061
+ if (set != undefined) node_process.env.NODE_ENV = set ? value : '';
12062
+ return node_process.env.NODE_ENV == value;
12063
+ }var sh=/*#__PURE__*/Object.freeze({__proto__:null,args:args,dev:dev,exec:exec,prod:prod});/*!
12064
+ * === @amekusa/util.js/io/AssetImporter === *
12065
+ * MIT License
12066
+ *
12067
+ * Copyright (c) 2024 Satoshi Soma
12068
+ *
12069
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
12070
+ * of this software and associated documentation files (the "Software"), to deal
12071
+ * in the Software without restriction, including without limitation the rights
12072
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12073
+ * copies of the Software, and to permit persons to whom the Software is
12074
+ * furnished to do so, subject to the following conditions:
12075
+ *
12076
+ * The above copyright notice and this permission notice shall be included in all
12077
+ * copies or substantial portions of the Software.
12078
+ *
12079
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12080
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12081
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12082
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12083
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12084
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
12085
+ * SOFTWARE.
12086
+ */
12087
+
11896
12088
  /**
11897
- * Merges the 2nd object into the 1st object recursively (deep-merge). The 1st object will be modified.
11898
- * @param {object} x - The 1st object
11899
- * @param {object} y - The 2nd object
11900
- * @param {object} [opts] - Options
11901
- * @param {number} opts.recurse=8 - Recurstion limit. Negative number means unlimited
11902
- * @param {boolean|string} opts.mergeArrays - How to merge arrays
11903
- * - `true`: merge x with y
11904
- * - 'push': push y elements to x
11905
- * - 'concat': concat x and y
11906
- * - other: replace x with y
11907
- * @return {object} The 1st object
12089
+ * This is for copying styles or scripts to a certain HTML directory.
12090
+ * @author Satoshi Soma (github.com/amekusa)
11908
12091
  */
11909
- function merge(x, y, opts = {}) {
11910
- if (!('recurse' in opts)) opts.recurse = 8;
11911
- switch (Array.isArray(x) + Array.isArray(y)) {
11912
- case 0: // no array
11913
- if (opts.recurse && x && y && typeof x == 'object' && typeof y == 'object') {
11914
- opts.recurse--;
11915
- for (let k in y) x[k] = merge(x[k], y[k], opts);
11916
- opts.recurse++;
11917
- return x;
11918
- }
11919
- case 1: // 1 array
11920
- return y;
12092
+ class AssetImporter {
12093
+ /**
12094
+ * @param {object} config
12095
+ * @param {boolean} [config.minify=false] - Prefer `*.min.*` version
12096
+ * @param {string} config.src - Source dir to search
12097
+ * @param {string} config.dst - Destination dir
12098
+ */
12099
+ constructor(config) {
12100
+ this.config = Object.assign({
12101
+ minify: false,
12102
+ src: '', // source dir to search
12103
+ dst: '', // destination dir
12104
+ }, config);
12105
+ this.queue = [];
12106
+ this.results = {
12107
+ script: [],
12108
+ style: [],
12109
+ asset: [],
12110
+ };
11921
12111
  }
11922
- // 2 arrays
11923
- switch (opts.mergeArrays) {
11924
- case true:
11925
- for (let i = 0; i < y.length; i++) {
11926
- if (!x.includes(y[i])) x.push(y[i]);
12112
+ /**
12113
+ * Adds a new item to import.
12114
+ * @param {string|string[]|object|object[]} newImport
12115
+ */
12116
+ add(newImport) {
12117
+ if (!Array.isArray(newImport)) newImport = [newImport];
12118
+ for (let i = 0; i < newImport.length; i++) {
12119
+ let item = newImport[i];
12120
+ switch (typeof item) {
12121
+ case 'string':
12122
+ item = {src: item};
12123
+ break;
12124
+ case 'object':
12125
+ if (Array.isArray(item)) throw `invalid type: array`;
12126
+ break;
12127
+ default:
12128
+ throw `invalid type: ${typeof item}`;
12129
+ }
12130
+ if (!('src' in item)) throw `'src' property is missing`;
12131
+ this.queue.push(Object.assign({
12132
+ order: 0,
12133
+ resolve: 'local',
12134
+ private: false,
12135
+ }, item));
11927
12136
  }
11928
- return x;
11929
- case 'push':
11930
- x.push(...y);
11931
- return x;
11932
- case 'concat':
11933
- return x.concat(y);
11934
12137
  }
11935
- return y;
11936
- }
11937
-
11938
- var main = {
11939
- arr,
11940
- isEmpty,
11941
- clean,
11942
- merge,
11943
- };
11944
-
11945
- bundle$2.arr = arr;
11946
- bundle$2.clean = clean;
11947
- bundle$2.default = main;
11948
- bundle$2.isArray = isArray;
11949
- bundle$2.isEmpty = isEmpty;
11950
- bundle$2.isNumOrStr = isNumOrStr;
11951
- bundle$2.merge = merge;
11952
- bundle$2.time = time;
11953
- bundle$2.web = web;
11954
- return bundle$2;
11955
- }var bundle$1 = {};var hasRequiredBundle$1;
11956
-
11957
- function requireBundle$1 () {
11958
- if (hasRequiredBundle$1) return bundle$1;
11959
- hasRequiredBundle$1 = 1;
11960
-
11961
- var node_process = require$$0$1;
11962
- var node_child_process = require$$1;
11963
- var os = require$$2$1;
11964
- var fs = require$$3;
11965
- var fsp = require$$4;
11966
- var path = require$$2;
11967
- var node_stream = require$$6$1;
11968
- var assert = require$$7;
11969
-
11970
- function _interopNamespaceDefault(e) {
11971
- var n = Object.create(null);
11972
- if (e) {
11973
- Object.keys(e).forEach(function (k) {
11974
- if (k !== 'default') {
11975
- var d = Object.getOwnPropertyDescriptor(e, k);
11976
- Object.defineProperty(n, k, d.get ? d : {
11977
- enumerable: true,
11978
- get: function () { return e[k]; }
11979
- });
11980
- }
11981
- });
11982
- }
11983
- n.default = e;
11984
- return Object.freeze(n);
11985
- }
11986
-
11987
- var fsp__namespace = /*#__PURE__*/_interopNamespaceDefault(fsp);
11988
-
11989
- /*!
11990
- * Shell Utils
11991
- * @author amekusa
11992
- */
11993
-
11994
- /**
11995
- * Executes the given shell command, and returns a Promise that resolves the stdout
11996
- * @param {string} cmd
11997
- * @param {object} [opts]
11998
- * @return {Promise}
11999
- */
12000
- function exec(cmd, opts = {}) {
12001
- opts = Object.assign({
12002
- dryRun: false,
12003
- }, opts);
12004
- return new Promise((resolve, reject) => {
12005
- if (opts.dryRun) {
12006
- console.log(`[DRYRUN] ${cmd}`);
12007
- return resolve();
12138
+ /**
12139
+ * Resolves the location of the given file path
12140
+ * @param {string} file - File path
12141
+ * @param {string} method - Resolution method
12142
+ * @return {string} Resolved file path
12143
+ */
12144
+ resolve(file, method) {
12145
+ let find = [];
12146
+ if (this.config.minify) {
12147
+ let _ext = ext(file);
12148
+ find.push(ext(file, '.min' + _ext));
12008
12149
  }
12009
- node_child_process.exec(cmd, (err, stdout) => {
12010
- return err ? reject(err) : resolve(stdout);
12011
- });
12012
- });
12013
- }
12014
-
12015
- /**
12016
- * Converts the given objects to shell arguments in a string form
12017
- * @param {object} args
12018
- * @param {object} [opts]
12019
- * @return {string}
12020
- */
12021
- function args(args, opts = {}) {
12022
- opts = Object.assign({
12023
- sep: ' ', // key-value separator
12024
- }, opts);
12025
- let r = [];
12026
- for (let key in args) {
12027
- let value = args[key];
12028
- if (isNaN(key)) { // non-numeric key
12029
- switch (typeof value) {
12030
- case 'boolean':
12031
- if (value) r.push(key);
12032
- break;
12033
- case 'number':
12034
- r.push(key + opts.sep + value);
12150
+ find.push(file);
12151
+ for (let i = 0; i < find.length; i++) {
12152
+ let r;
12153
+ switch (method) {
12154
+ case 'require':
12155
+ try {
12156
+ r = require.resolve(find[i]);
12157
+ } catch (e) {
12158
+ if (e.code == 'MODULE_NOT_FOUND') continue;
12159
+ throw e;
12160
+ }
12161
+ return r;
12162
+ case 'local':
12163
+ r = path.join(this.config.src, find[i]);
12164
+ if (fs.existsSync(r)) return r;
12035
12165
  break;
12036
- case 'string':
12037
- r.push(key + opts.sep + `"${value}"`);
12166
+ case 'local:absolute':
12167
+ case 'local:abs':
12168
+ r = find[i];
12169
+ if (fs.existsSync(r)) return r;
12038
12170
  break;
12171
+ default:
12172
+ throw `invalid resolution method: ${method}`;
12039
12173
  }
12040
- } else { // numeric key
12041
- r.push(value);
12042
12174
  }
12175
+ throw `cannot resolve '${file}'`;
12043
12176
  }
12044
- return r.join(' ');
12045
- }
12177
+ /**
12178
+ * Imports all items in the queue at once.
12179
+ * @return {Promise}
12180
+ */
12181
+ import() {
12182
+ let tasks = [];
12183
+ let typeMap = {
12184
+ '.css': 'style',
12185
+ '.js': 'script',
12186
+ };
12187
+ this.queue.sort((a, b) => (Number(a.order) - Number(b.order))); // sort by order
12188
+ while (this.queue.length) {
12189
+ let item = this.queue.shift();
12190
+ let {type, src} = item;
12191
+ let url;
12192
+
12193
+ if (!item.resolve) { // no resolution
12194
+ url = src;
12195
+ if (!type) type = typeMap[ext(src)] || 'asset';
12196
+ console.log('---- File Link ----');
12197
+ console.log(' type:', type);
12198
+ console.log(' src:', src);
12199
+
12200
+ } else { // needs resolution
12201
+ let {dst:dstDir, as:dstFile} = item;
12202
+ let create = item.resolve == 'create'; // needs creation?
12203
+ if (create) {
12204
+ if (!dstFile) throw `'as' property is required with {resolve: 'create'}`;
12205
+ } else {
12206
+ src = this.resolve(src, item.resolve);
12207
+ if (!dstFile) dstFile = path.basename(src);
12208
+ }
12209
+ if (!type) type = typeMap[ext(dstFile)] || 'asset';
12210
+ if (!dstDir) dstDir = type + 's';
12211
+
12212
+ // absolute destination
12213
+ url = path.join(dstDir, dstFile);
12214
+ let dst = path.join(this.config.dst, url);
12215
+ dstDir = path.dirname(dst);
12216
+ if (!fs.existsSync(dstDir)) fs.mkdirSync(dstDir, {recursive:true});
12217
+
12218
+ // create/copy file
12219
+ if (create) {
12220
+ console.log('---- File Creation ----');
12221
+ console.log(' type:', type);
12222
+ console.log(' dst:', dst);
12223
+ tasks.push(fsp.writeFile(dst, src));
12224
+ } else {
12225
+ console.log('---- File Import ----');
12226
+ console.log(' type:', type);
12227
+ console.log(' src:', src);
12228
+ console.log(' dst:', dst);
12229
+ tasks.push(fsp.copyFile(src, dst));
12230
+ }
12231
+ }
12046
12232
 
12047
- /**
12048
- * Returns if NODE_ENV is 'production'
12049
- * @param {any} [set]
12050
- * @return {bool}
12051
- */
12052
- function prod(set = undefined) {
12053
- let value = 'production';
12054
- if (set != undefined) node_process.env.NODE_ENV = set ? value : '';
12055
- return node_process.env.NODE_ENV == value;
12056
- }
12233
+ if (!item.private) {
12234
+ if (!(type in this.results)) this.results[type] = [];
12235
+ this.results[type].push({type, url});
12236
+ }
12237
+ }
12057
12238
 
12058
- /**
12059
- * Returns if NODE_ENV is 'development'
12060
- * @param {any} [set]
12061
- * @return {bool}
12062
- */
12063
- function dev(set = undefined) {
12064
- let value = 'development';
12065
- if (set != undefined) node_process.env.NODE_ENV = set ? value : '';
12066
- return node_process.env.NODE_ENV == value;
12239
+ return tasks.length ? Promise.all(tasks) : Promise.resolve();
12240
+ }
12241
+ /**
12242
+ * Outputs HTML tags for imported items.
12243
+ * @param {string} [type] - Type
12244
+ * @return {string} HTML
12245
+ */
12246
+ toHTML(type = null) {
12247
+ let r;
12248
+ if (type) {
12249
+ let tmpl = templates[type];
12250
+ if (!tmpl) return '';
12251
+ if (Array.isArray(tmpl)) tmpl = tmpl.join('\n');
12252
+ let items = this.results[type];
12253
+ r = new Array(items.length);
12254
+ for (let i = 0; i < items.length; i++) {
12255
+ r[i] = tmpl.replaceAll('%s', items[i].url || '');
12256
+ }
12257
+ } else {
12258
+ let keys = Object.keys(this.results);
12259
+ r = new Array(keys.length);
12260
+ for (let i = 0; i < keys.length; i++) {
12261
+ r[i] = this.toHTML(keys[i]);
12262
+ }
12263
+ }
12264
+ return r.join('\n');
12265
+ }
12067
12266
  }
12068
12267
 
12069
- var sh = /*#__PURE__*/Object.freeze({
12070
- __proto__: null,
12071
- args: args,
12072
- dev: dev,
12073
- exec: exec,
12074
- prod: prod
12075
- });
12076
-
12077
- /*!
12078
- * I/O Utils
12079
- * @author amekusa
12080
- */
12081
-
12082
- /**
12268
+ const templates = {
12269
+ script: [
12270
+ `<script src="%s"></script>`,
12271
+ ],
12272
+ module: [
12273
+ `<script type="module" src="%s"></script>`,
12274
+ ],
12275
+ style: [
12276
+ `<link rel="stylesheet" href="%s">`,
12277
+ ],
12278
+ };/**
12083
12279
  * Alias of `os.homedir()`.
12084
12280
  * @type {string}
12085
12281
  */
12086
12282
  const home = os.homedir();
12087
12283
 
12088
12284
  /**
12089
- * Searchs the given file path in the given directories.
12285
+ * Returns or overwrites the extension of the given file path.
12286
+ * @param {string} file - File path
12287
+ * @param {string} [set] - New extension
12288
+ * @return {string} the extension, or a modified file path with the new extension
12289
+ */
12290
+ function ext(file, set = null) {
12291
+ let dot = file.lastIndexOf('.');
12292
+ return typeof set == 'string'
12293
+ ? (dot < 0 ? (file + set) : (file.substring(0, dot) + set))
12294
+ : (dot < 0 ? '' : file.substring(dot));
12295
+ }
12296
+
12297
+ /**
12298
+ * Searches the given file path in the given directories.
12090
12299
  * @param {string} file - File to find
12091
12300
  * @param {string[]} dirs - Array of directories to search
12092
12301
  * @param {object} [opts] - Options
12302
+ * @param {boolean} [opts.allowAbsolute=true] - If true, `file` can be an absolute path
12093
12303
  * @return {string|boolean} found file path, or false if not found
12094
12304
  */
12095
12305
  function find(file, dirs = [], opts = {}) {
@@ -12116,28 +12326,43 @@ function requireBundle$1 () {
12116
12326
  }
12117
12327
 
12118
12328
  /**
12119
- * Deletes the contents of the given directory.
12120
- * @return {Promise}
12121
- */
12122
- function clean(dir, pattern, depth = 1) {
12123
- return exec(`find '${dir}' -type f -name '${pattern}' -maxdepth ${depth} -delete`);
12124
- }
12125
-
12126
- /**
12127
- * Deletes the given file or directory.
12128
- * @param {string} file
12129
- * @return {Promise}
12130
- */
12131
- function rm(file) {
12132
- return fsp__namespace.rm(file, {recursive: true, force: true});
12133
- }
12134
-
12135
- /**
12136
- * Deletes the given file or directory synchronously.
12137
- * @param {string} file
12329
+ * Deletes the files in the given directory.
12330
+ * @param {string} dir - Directory to clean
12331
+ * @param {string|RegExp} [pattern] - File pattern
12332
+ * @param {object} [opts] - Options
12333
+ * @param {boolean} [opts.recursive=false] - Searches recursively
12334
+ * @param {object} [opts.types] - File types to delete
12335
+ * @param {boolean} [opts.types.any=false] - Any type
12336
+ * @param {boolean} [opts.types.file=true] - Regular file
12337
+ * @param {boolean} [opts.types.dir=false] - Directory
12338
+ * @param {boolean} [opts.types.symlink=false] - Symbolic link
12339
+ * @return {Promise} a promise resolved with the deleted file paths
12138
12340
  */
12139
- function rmSync(file) {
12140
- return fs.rmSync(file, {recursive: true, force: true});
12341
+ function clean(dir, pattern = null, opts = {}) {
12342
+ if (pattern && typeof pattern == 'string') pattern = new RegExp(pattern);
12343
+ let {
12344
+ recursive = false,
12345
+ types = {file: true},
12346
+ } = opts;
12347
+ return fsp__namespace.readdir(dir, {recursive, withFileTypes: true}).then(files => {
12348
+ let tasks = [];
12349
+ for (let i = 0; i < files.length; i++) {
12350
+ let f = files[i];
12351
+ if (!types.any) {
12352
+ if (f.isFile()) {
12353
+ if (!types.file) continue;
12354
+ } else if (f.isDirectory()) {
12355
+ if (!types.dir) continue;
12356
+ } else if (f.isSymbolicLink()) {
12357
+ if (!types.symlink) continue;
12358
+ }
12359
+ }
12360
+ f = path.join(dir, f.name);
12361
+ if (pattern && !f.match(pattern)) continue;
12362
+ tasks.push(fsp__namespace.rm(f, {force: true, recursive: true}).then(() => f));
12363
+ }
12364
+ return tasks.length ? Promise.all(tasks) : false;
12365
+ });
12141
12366
  }
12142
12367
 
12143
12368
  /**
@@ -12171,7 +12396,7 @@ function requireBundle$1 () {
12171
12396
  *
12172
12397
  * @example
12173
12398
  * return gulp.src(src)
12174
- * .pipe(modify((data, enc) => {
12399
+ * .pipe(modifyStream((data, enc) => {
12175
12400
  * // do stuff
12176
12401
  * return newData;
12177
12402
  * }));
@@ -12197,25 +12422,31 @@ function requireBundle$1 () {
12197
12422
  }
12198
12423
  }
12199
12424
  });
12200
- }
12201
-
12202
- var io = /*#__PURE__*/Object.freeze({
12203
- __proto__: null,
12204
- clean: clean,
12205
- copy: copy,
12206
- find: find,
12207
- home: home,
12208
- modifyStream: modifyStream,
12209
- rm: rm,
12210
- rmSync: rmSync,
12211
- untilde: untilde
12212
- });
12213
-
12214
- const merge = Object.assign;
12425
+ }var io=/*#__PURE__*/Object.freeze({__proto__:null,AssetImporter:AssetImporter,clean:clean,copy:copy,ext:ext,find:find,home:home,modifyStream:modifyStream,untilde:untilde});const merge = Object.assign;
12215
12426
 
12216
12427
  /*!
12217
- * Test Utils
12218
- * @author amekusa
12428
+ * === @amekusa/util.js/test === *
12429
+ * MIT License
12430
+ *
12431
+ * Copyright (c) 2024 Satoshi Soma
12432
+ *
12433
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
12434
+ * of this software and associated documentation files (the "Software"), to deal
12435
+ * in the Software without restriction, including without limitation the rights
12436
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12437
+ * copies of the Software, and to permit persons to whom the Software is
12438
+ * furnished to do so, subject to the following conditions:
12439
+ *
12440
+ * The above copyright notice and this permission notice shall be included in all
12441
+ * copies or substantial portions of the Software.
12442
+ *
12443
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12444
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12445
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12446
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12447
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12448
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
12449
+ * SOFTWARE.
12219
12450
  */
12220
12451
 
12221
12452
  /**
@@ -12282,28 +12513,36 @@ function requireBundle$1 () {
12282
12513
  let testCase = (c, title) => {
12283
12514
  it(title, () => {
12284
12515
  if (typeof c != 'object') invalid(`a test case must be an object`);
12516
+
12285
12517
  // ---- call function ----
12286
- let r;
12287
12518
  let args = [];
12288
- if (c.args) { // args to pass
12519
+ if ('args' in c) { // args to pass
12289
12520
  if (!Array.isArray(c.args)) invalid(`'args' must be an array`);
12290
12521
  args = c.args;
12522
+ delete c.args;
12291
12523
  }
12292
- r = fn(...args);
12293
- // ---- check ----
12294
- if ('returnType' in c) { // check return type
12295
- assertType(r, c.returnType, `return type failed`);
12296
- }
12297
- if ('return' in c) { // check return
12298
- assertEqual(r, c.return, merge({msg: `return value failed`}, opts));
12299
- }
12300
- if (c.test) { // custom test
12301
- if (typeof c.test != 'function') invalid(`'test' must be a function`);
12302
- c.test(r, ...args);
12524
+ let r = fn(...args);
12525
+
12526
+ // ---- check the result ----
12527
+ let check = {
12528
+ returnType() {
12529
+ assertType(r, c.returnType, `return type failed`);
12530
+ },
12531
+ return() {
12532
+ assertEqual(r, c.return, merge({msg: `return value failed`}, opts));
12533
+ },
12534
+ test() {
12535
+ if (typeof c.test != 'function') invalid(`'test' must be a function`);
12536
+ c.test(r, ...args);
12537
+ }
12538
+ };
12539
+ for (let k in c) {
12540
+ if (check[k]) check[k]();
12541
+ else invalid(`invalid property: '${k}' (available properties: ${Object.keys(check).join(', ')})`);
12303
12542
  }
12304
12543
  });
12305
12544
  };
12306
- describe(fn.displayName || fn.name, () => {
12545
+ describe('function: ' + (fn.displayName || fn.name), () => {
12307
12546
  if (Array.isArray(cases)) {
12308
12547
  for (let i = 0; i < cases.length; i++) {
12309
12548
  let c = cases[i];
@@ -12330,52 +12569,68 @@ function requireBundle$1 () {
12330
12569
  let testCase = (c, title) => {
12331
12570
  it(title, () => {
12332
12571
  if (typeof c != 'object') invalid(`a test case must be an object`);
12572
+
12333
12573
  // ---- instantiate ----
12334
12574
  let obj;
12335
12575
  if (opts.static) {
12336
- if (c.initArgs) invalid(`'initArgs' is not for static method`);
12576
+ if ('initArgs' in c) invalid(`'initArgs' is not available for a static method`);
12577
+ if ('prepare' in c) invalid(`'prepare' is not available for a static method`);
12337
12578
  obj = construct;
12338
12579
  } else {
12339
12580
  let initArgs = [];
12340
- if (c.initArgs) {
12581
+ if ('initArgs' in c) {
12341
12582
  if (!Array.isArray(c.initArgs)) invalid(`'initArgs' must be an array`);
12342
12583
  initArgs = c.initArgs;
12584
+ delete c.initArgs;
12343
12585
  }
12344
12586
  try {
12345
12587
  obj = new construct(...initArgs);
12346
12588
  } catch (e) {
12347
12589
  obj = construct(...initArgs);
12348
12590
  }
12591
+ if ('prepare' in c) {
12592
+ if (typeof c.prepare != 'function') invalid(`'prepare' must be a function`);
12593
+ c.prepare(obj);
12594
+ delete c.prepare;
12595
+ }
12349
12596
  }
12597
+
12350
12598
  // ---- call method ----
12351
- if (!(method in obj)) invalid(`no such method as '${method}`);
12352
- let r;
12599
+ if (!(method in obj)) invalid(`no such method as '${method}'`);
12353
12600
  let args = [];
12354
- if (c.args) { // args to pass
12601
+ if ('args' in c) { // args to pass
12355
12602
  if (!Array.isArray(c.args)) invalid(`'args' must be an array`);
12356
12603
  args = c.args;
12604
+ delete c.args;
12357
12605
  }
12358
- r = obj[method](...args);
12359
- // ---- check ----
12360
- if (c.returnsSelf) { // check if returns itself
12361
- assert.strictEqual(r, obj);
12362
- }
12363
- if ('returnType' in c) { // check return type
12364
- assertType(r, c.returnType, `return type failed`);
12365
- }
12366
- if ('return' in c) { // check return value
12367
- assertEqual(r, c.return, merge({msg: `return failed`}, opts));
12368
- }
12369
- if (c.props) { // check properties
12370
- assertProps(obj, c.props, opts);
12371
- }
12372
- if (c.test) { // custom test
12373
- if (typeof c.test != 'function') invalid(`'test' must be a function`);
12374
- c.test(r, obj, ...args);
12606
+ let r = obj[method](...args);
12607
+
12608
+ // ---- check the result ----
12609
+ let check = {
12610
+ returnsSelf() { // check if returns itself
12611
+ assert.strictEqual(r, obj, `must return self`);
12612
+ },
12613
+ returnType() { // check return type
12614
+ assertType(r, c.returnType, `return type failed`);
12615
+ },
12616
+ return() { // check return value
12617
+ assertEqual(r, c.return, merge({msg: `return failed`}, opts));
12618
+ },
12619
+ props() { // check properties
12620
+ assertProps(obj, c.props, opts);
12621
+ },
12622
+ test() { // custom test
12623
+ if (typeof c.test != 'function') invalid(`'test' must be a function`);
12624
+ c.test(r, obj, ...args);
12625
+ }
12626
+ };
12627
+ for (let k in c) {
12628
+ if (check[k]) check[k]();
12629
+ else invalid(`invalid property: '${k}' (available properties: ${Object.keys(check).join(', ')})`);
12375
12630
  }
12376
12631
  });
12377
12632
  };
12378
- describe(construct.name + ' :: ' + method, () => {
12633
+ describe('method: ' + method, () => {
12379
12634
  if (Array.isArray(cases)) {
12380
12635
  for (let i = 0; i < cases.length; i++) {
12381
12636
  let c = cases[i];
@@ -12400,23 +12655,35 @@ function requireBundle$1 () {
12400
12655
  function testInstance(construct, cases, opts = {}) {
12401
12656
  let testCase = (c, title) => {
12402
12657
  it(title, () => {
12403
- let obj;
12658
+ if (typeof c != 'object') invalid(`a test case must be an object`);
12659
+
12660
+ // ---- instantiate ----
12404
12661
  let args = [];
12405
- if (c.args) {
12662
+ if ('args' in c) {
12406
12663
  if (!Array.isArray(c.args)) invalid(`'args' must be an array`);
12407
12664
  args = c.args;
12665
+ delete c.args;
12408
12666
  }
12667
+ let obj;
12409
12668
  try {
12410
12669
  obj = new construct(...args);
12411
12670
  } catch (e) {
12412
12671
  obj = construct(...args);
12413
12672
  }
12414
- if (c.props) { // check properties
12415
- assertProps(obj, c.props, opts);
12416
- }
12417
- if (c.test) { // custom test
12418
- if (typeof c.test != 'function') invalid(`'test' must be a function`);
12419
- c.test(obj, ...args);
12673
+
12674
+ // ---- check the result ----
12675
+ let check = {
12676
+ props() { // check properties
12677
+ assertProps(obj, c.props, opts);
12678
+ },
12679
+ test() { // custom check
12680
+ if (typeof c.test != 'function') invalid(`'test' must be a function`);
12681
+ c.test(obj, ...args);
12682
+ }
12683
+ };
12684
+ for (let k in c) {
12685
+ if (check[k]) check[k]();
12686
+ else invalid(`invalid property: '${k}' (available properties: ${Object.keys(check).join(', ')})`);
12420
12687
  }
12421
12688
  });
12422
12689
  };
@@ -12435,36 +12702,21 @@ function requireBundle$1 () {
12435
12702
  }
12436
12703
  }
12437
12704
  });
12438
- }
12439
-
12440
- var test = /*#__PURE__*/Object.freeze({
12441
- __proto__: null,
12442
- InvalidTest: InvalidTest,
12443
- assertEqual: assertEqual,
12444
- assertProps: assertProps,
12445
- assertType: assertType,
12446
- testFn: testFn,
12447
- testInstance: testInstance,
12448
- testMethod: testMethod
12449
- });
12705
+ }var test=/*#__PURE__*/Object.freeze({__proto__:null,InvalidTest:InvalidTest,assertEqual:assertEqual,assertProps:assertProps,assertType:assertType,testFn:testFn,testInstance:testInstance,testMethod:testMethod});amekusa_util.arr=arr;amekusa_util.clean=clean$1;amekusa_util.dig=dig;amekusa_util.gen=gen;amekusa_util.io=io;amekusa_util.is=is;amekusa_util.isEmpty=isEmpty;amekusa_util.isEmptyOrFalsey=isEmptyOrFalsey;amekusa_util.isEmptyOrFalsy=isEmptyOrFalsy;amekusa_util.merge=merge$1;amekusa_util.sh=sh;amekusa_util.subst=subst;amekusa_util.test=test;amekusa_util.time=time;amekusa_util.web=web;
12706
+ return amekusa_util;
12707
+ }var karabinerge = {};var hasRequiredKarabinerge;
12450
12708
 
12451
- bundle$1.io = io;
12452
- bundle$1.sh = sh;
12453
- bundle$1.test = test;
12454
- return bundle$1;
12455
- }var bundle = {};var hasRequiredBundle;
12456
-
12457
- function requireBundle () {
12458
- if (hasRequiredBundle) return bundle;
12459
- hasRequiredBundle = 1;
12709
+ function requireKarabinerge () {
12710
+ if (hasRequiredKarabinerge) return karabinerge;
12711
+ hasRequiredKarabinerge = 1;
12460
12712
 
12461
12713
  var node_process = require$$0$1;
12462
- var path = require$$2;
12463
- var node_child_process = require$$1;
12464
- var os = require$$2$1;
12714
+ var path = require$$3$1;
12715
+ var os = require$$0$2;
12465
12716
  var fs = require$$3;
12466
- var fsp = require$$4;
12467
- var node_stream = require$$6$1;
12717
+ var fsp = require$$2;
12718
+ var node_stream = require$$4;
12719
+
12468
12720
 
12469
12721
 
12470
12722
  function _interopNamespaceDefault(e) {
@@ -12486,195 +12738,104 @@ function requireBundle () {
12486
12738
 
12487
12739
  var fsp__namespace = /*#__PURE__*/_interopNamespaceDefault(fsp);
12488
12740
 
12489
- /*!
12490
- * Shell Utils
12491
- * @author amekusa
12492
- */
12493
-
12494
12741
  /**
12495
- * Executes the given shell command, and returns a Promise that resolves the stdout
12496
- * @param {string} cmd
12497
- * @param {object} [opts]
12498
- * @return {Promise}
12742
+ * Coerces the given value into an array.
12743
+ * @param {any} x
12744
+ * @return {any[]}
12499
12745
  */
12500
- function exec(cmd, opts = {}) {
12501
- opts = Object.assign({
12502
- dryRun: false,
12503
- }, opts);
12504
- return new Promise((resolve, reject) => {
12505
- if (opts.dryRun) {
12506
- console.log(`[DRYRUN] ${cmd}`);
12507
- return resolve();
12508
- }
12509
- node_child_process.exec(cmd, (err, stdout) => {
12510
- return err ? reject(err) : resolve(stdout);
12511
- });
12512
- });
12746
+ function arr(x) {
12747
+ return Array.isArray(x) ? x : [x];
12513
12748
  }
12514
12749
 
12515
- /*!
12516
- * I/O Utils
12517
- * @author amekusa
12518
- */
12519
-
12520
- /**
12521
- * Alias of `os.homedir()`.
12522
- * @type {string}
12523
- */
12524
- const home = os.homedir();
12525
-
12526
12750
  /**
12527
- * Searchs the given file path in the given directories.
12528
- * @param {string} file - File to find
12529
- * @param {string[]} dirs - Array of directories to search
12530
- * @param {object} [opts] - Options
12531
- * @return {string|boolean} found file path, or false if not found
12751
+ * Returns whether the given value can be considered as "empty".
12752
+ * @param {any} x
12753
+ * @return {boolean}
12532
12754
  */
12533
- function find(file, dirs = [], opts = {}) {
12534
- let {allowAbsolute = true} = opts;
12535
- if (allowAbsolute && path.isAbsolute(file)) return fs.existsSync(file) ? file : false;
12536
- for (let i = 0; i < dirs.length; i++) {
12537
- let find = path.join(dirs[i], file);
12538
- if (fs.existsSync(find)) return find;
12755
+ function isEmpty(x) {
12756
+ if (Array.isArray(x)) return x.length == 0;
12757
+ switch (typeof x) {
12758
+ case 'string':
12759
+ return !x;
12760
+ case 'object':
12761
+ for (let _ in x) return false;
12762
+ return true;
12763
+ case 'undefined':
12764
+ return true;
12539
12765
  }
12540
12766
  return false;
12541
12767
  }
12542
12768
 
12543
12769
  /**
12544
- * Replaces the beginning `~` character with `os.homedir()`.
12545
- * @param {string} file - File path
12546
- * @param {string} [replace=os.homedir()] - Replacement
12547
- * @return {string} modified `file`
12548
- */
12549
- function untilde(file, replace = home) {
12550
- if (!file.startsWith('~')) return file;
12551
- if (file.length == 1) return replace;
12552
- if (file.startsWith(path.sep, 1)) return replace + file.substring(1);
12553
- return file;
12554
- }
12555
-
12556
- /**
12557
- * Deletes the contents of the given directory.
12558
- * @return {Promise}
12559
- */
12560
- function clean$1(dir, pattern, depth = 1) {
12561
- return exec(`find '${dir}' -type f -name '${pattern}' -maxdepth ${depth} -delete`);
12562
- }
12563
-
12564
- /**
12565
- * Deletes the given file or directory.
12566
- * @param {string} file
12567
- * @return {Promise}
12568
- */
12569
- function rm(file) {
12570
- return fsp__namespace.rm(file, {recursive: true, force: true});
12571
- }
12572
-
12573
- /**
12574
- * Deletes the given file or directory synchronously.
12575
- * @param {string} file
12576
- */
12577
- function rmSync(file) {
12578
- return fs.rmSync(file, {recursive: true, force: true});
12579
- }
12580
-
12581
- /**
12582
- * Copies the given file(s) to another directory
12583
- * @param {string|object|string[]|object[]} src
12584
- * @param {string} dst Base destination directory
12585
- * @return {Promise}
12770
+ * Removes "empty" values from the given object or array.
12771
+ * @param {object|any[]} x
12772
+ * @param {number} recurse - Recursion limit
12773
+ * @return {object|any[]} modified `x`
12586
12774
  */
12587
- function copy(src, dst) {
12588
- return Promise.all((Array.isArray(src) ? src : [src]).map(item => {
12589
- let _src, _dst;
12590
- switch (typeof item) {
12591
- case 'object':
12592
- _src = item.src;
12593
- _dst = item.dst;
12594
- break;
12595
- case 'string':
12596
- _src = item;
12597
- break;
12598
- default:
12599
- throw 'invalid type';
12775
+ function clean$1(x, recurse = 8) {
12776
+ if (recurse) {
12777
+ if (Array.isArray(x)) {
12778
+ let r = [];
12779
+ for (let i = 0; i < x.length; i++) {
12780
+ let v = clean$1(x[i], recurse - 1);
12781
+ if (!isEmpty(v)) r.push(v);
12782
+ }
12783
+ return r;
12600
12784
  }
12601
- _dst = path.join(dst, _dst || path.basename(_src));
12602
- return fsp__namespace.mkdir(path.dirname(_dst), {recursive: true}).then(fsp__namespace.copyFile(_src, _dst));
12603
- }));
12785
+ if (typeof x == 'object') {
12786
+ let r = {};
12787
+ for (let k in x) {
12788
+ let v = clean$1(x[k], recurse - 1);
12789
+ if (!isEmpty(v)) r[k] = v;
12790
+ }
12791
+ return r;
12792
+ }
12793
+ }
12794
+ return x;
12604
12795
  }
12605
12796
 
12606
12797
  /**
12607
- * Returns a Transform stream object with the given function as its transform() method.
12608
- * `fn` must return a string which is to be the new content, or a Promise which resolves a string.
12609
- *
12610
- * @example
12611
- * return gulp.src(src)
12612
- * .pipe(modify((data, enc) => {
12613
- * // do stuff
12614
- * return newData;
12615
- * }));
12616
- *
12617
- * @param {function} fn
12618
- * @return {Transform}
12798
+ * Merges the 2nd object into the 1st object recursively (deep-merge). The 1st object will be modified.
12799
+ * @param {object} x - The 1st object
12800
+ * @param {object} y - The 2nd object
12801
+ * @param {object} [opts] - Options
12802
+ * @param {number} opts.recurse=8 - Recurstion limit. Negative number means unlimited
12803
+ * @param {boolean|string} opts.mergeArrays - How to merge arrays
12804
+ * - `true`: merge x with y
12805
+ * - 'push': push y elements to x
12806
+ * - 'concat': concat x and y
12807
+ * - other: replace x with y
12808
+ * @return {object} The 1st object
12619
12809
  */
12620
- function modifyStream(fn) {
12621
- return new node_stream.Transform({
12622
- objectMode: true,
12623
- transform(file, enc, done) {
12624
- let r = fn(file.contents.toString(enc), enc);
12625
- if (r instanceof Promise) {
12626
- r.then(modified => {
12627
- file.contents = Buffer.from(modified, enc);
12628
- this.push(file);
12629
- done();
12630
- });
12631
- } else {
12632
- file.contents = Buffer.from(r, enc);
12633
- this.push(file);
12634
- done();
12635
- }
12810
+ function merge$1(x, y, opts = {}) {
12811
+ if (!('recurse' in opts)) opts.recurse = 8;
12812
+ switch (Array.isArray(x) + Array.isArray(y)) {
12813
+ case 0: // no array
12814
+ if (opts.recurse && x && y && typeof x == 'object' && typeof y == 'object') {
12815
+ opts.recurse--;
12816
+ for (let k in y) x[k] = merge$1(x[k], y[k], opts);
12817
+ opts.recurse++;
12818
+ return x;
12636
12819
  }
12637
- });
12820
+ case 1: // 1 array
12821
+ return y;
12822
+ }
12823
+ // 2 arrays
12824
+ switch (opts.mergeArrays) {
12825
+ case true:
12826
+ for (let i = 0; i < y.length; i++) {
12827
+ if (!x.includes(y[i])) x.push(y[i]);
12828
+ }
12829
+ return x;
12830
+ case 'push':
12831
+ x.push(...y);
12832
+ return x;
12833
+ case 'concat':
12834
+ return x.concat(y);
12835
+ }
12836
+ return y;
12638
12837
  }
12639
12838
 
12640
- var io = /*#__PURE__*/Object.freeze({
12641
- __proto__: null,
12642
- clean: clean$1,
12643
- copy: copy,
12644
- find: find,
12645
- home: home,
12646
- modifyStream: modifyStream,
12647
- rm: rm,
12648
- rmSync: rmSync,
12649
- untilde: untilde
12650
- });
12651
-
12652
- /*!
12653
- * === @amekusa/util.js/web === *
12654
- * MIT License
12655
- *
12656
- * Copyright (c) 2024 Satoshi Soma
12657
- *
12658
- * Permission is hereby granted, free of charge, to any person obtaining a copy
12659
- * of this software and associated documentation files (the "Software"), to deal
12660
- * in the Software without restriction, including without limitation the rights
12661
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12662
- * copies of the Software, and to permit persons to whom the Software is
12663
- * furnished to do so, subject to the following conditions:
12664
- *
12665
- * The above copyright notice and this permission notice shall be included in all
12666
- * copies or substantial portions of the Software.
12667
- *
12668
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12669
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12670
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12671
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12672
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12673
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
12674
- * SOFTWARE.
12675
- */
12676
-
12677
-
12678
12839
  const escHTML_map = {
12679
12840
  '&': 'amp',
12680
12841
  '"': 'quot',
@@ -12685,31 +12846,6 @@ function requireBundle () {
12685
12846
 
12686
12847
  new RegExp(`["'<>]|(&(?!${Object.values(escHTML_map).join('|')};))`, 'g');
12687
12848
 
12688
- /*!
12689
- * === @amekusa/util.js/time === *
12690
- * MIT License
12691
- *
12692
- * Copyright (c) 2024 Satoshi Soma
12693
- *
12694
- * Permission is hereby granted, free of charge, to any person obtaining a copy
12695
- * of this software and associated documentation files (the "Software"), to deal
12696
- * in the Software without restriction, including without limitation the rights
12697
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12698
- * copies of the Software, and to permit persons to whom the Software is
12699
- * furnished to do so, subject to the following conditions:
12700
- *
12701
- * The above copyright notice and this permission notice shall be included in all
12702
- * copies or substantial portions of the Software.
12703
- *
12704
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12705
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12706
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12707
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12708
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12709
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
12710
- * SOFTWARE.
12711
- */
12712
-
12713
12849
  /**
12714
12850
  * Coerces the given value into a `Date` object.
12715
12851
  * @param {...any} args - A `Date` object or args to pass to `Date()`
@@ -12846,155 +12982,379 @@ function requireBundle () {
12846
12982
  if (!format) return r;
12847
12983
  throw `invalid type`;
12848
12984
  }
12849
- }
12985
+ }
12986
+
12987
+ /**
12988
+ * Returns a string representation of the given `Date` in ISO 9075 format, which is standard for MySQL.
12989
+ * @param {Date} d - Date object
12990
+ * @return {string} a string like `YYYY-MM-DD hh:mm:ss`
12991
+ */
12992
+ function iso9075(d) {
12993
+ return ymd(d, '-') + ' ' + hms(d, ':');
12994
+ }var time=/*#__PURE__*/Object.freeze({__proto__:null,addTime:addTime,ceil:ceil,date:date,floor:floor,hms:hms,iso9075:iso9075,localize:localize,ms:ms,quantize:quantize,round:round,ymd:ymd});/*!
12995
+ * === @amekusa/util.js/sh === *
12996
+ * MIT License
12997
+ *
12998
+ * Copyright (c) 2024 Satoshi Soma
12999
+ *
13000
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
13001
+ * of this software and associated documentation files (the "Software"), to deal
13002
+ * in the Software without restriction, including without limitation the rights
13003
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13004
+ * copies of the Software, and to permit persons to whom the Software is
13005
+ * furnished to do so, subject to the following conditions:
13006
+ *
13007
+ * The above copyright notice and this permission notice shall be included in all
13008
+ * copies or substantial portions of the Software.
13009
+ *
13010
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13011
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13012
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13013
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
13014
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
13015
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
13016
+ * SOFTWARE.
13017
+ */
13018
+
13019
+ /**
13020
+ * This is for copying styles or scripts to a certain HTML directory.
13021
+ * @author Satoshi Soma (github.com/amekusa)
13022
+ */
13023
+ class AssetImporter {
13024
+ /**
13025
+ * @param {object} config
13026
+ * @param {boolean} [config.minify=false] - Prefer `*.min.*` version
13027
+ * @param {string} config.src - Source dir to search
13028
+ * @param {string} config.dst - Destination dir
13029
+ */
13030
+ constructor(config) {
13031
+ this.config = Object.assign({
13032
+ minify: false,
13033
+ src: '', // source dir to search
13034
+ dst: '', // destination dir
13035
+ }, config);
13036
+ this.queue = [];
13037
+ this.results = {
13038
+ script: [],
13039
+ style: [],
13040
+ asset: [],
13041
+ };
13042
+ }
13043
+ /**
13044
+ * Adds a new item to import.
13045
+ * @param {string|string[]|object|object[]} newImport
13046
+ */
13047
+ add(newImport) {
13048
+ if (!Array.isArray(newImport)) newImport = [newImport];
13049
+ for (let i = 0; i < newImport.length; i++) {
13050
+ let item = newImport[i];
13051
+ switch (typeof item) {
13052
+ case 'string':
13053
+ item = {src: item};
13054
+ break;
13055
+ case 'object':
13056
+ if (Array.isArray(item)) throw `invalid type: array`;
13057
+ break;
13058
+ default:
13059
+ throw `invalid type: ${typeof item}`;
13060
+ }
13061
+ if (!('src' in item)) throw `'src' property is missing`;
13062
+ this.queue.push(Object.assign({
13063
+ order: 0,
13064
+ resolve: 'local',
13065
+ private: false,
13066
+ }, item));
13067
+ }
13068
+ }
13069
+ /**
13070
+ * Resolves the location of the given file path
13071
+ * @param {string} file - File path
13072
+ * @param {string} method - Resolution method
13073
+ * @return {string} Resolved file path
13074
+ */
13075
+ resolve(file, method) {
13076
+ let find = [];
13077
+ if (this.config.minify) {
13078
+ let _ext = ext(file);
13079
+ find.push(ext(file, '.min' + _ext));
13080
+ }
13081
+ find.push(file);
13082
+ for (let i = 0; i < find.length; i++) {
13083
+ let r;
13084
+ switch (method) {
13085
+ case 'require':
13086
+ try {
13087
+ r = require.resolve(find[i]);
13088
+ } catch (e) {
13089
+ if (e.code == 'MODULE_NOT_FOUND') continue;
13090
+ throw e;
13091
+ }
13092
+ return r;
13093
+ case 'local':
13094
+ r = path.join(this.config.src, find[i]);
13095
+ if (fs.existsSync(r)) return r;
13096
+ break;
13097
+ case 'local:absolute':
13098
+ case 'local:abs':
13099
+ r = find[i];
13100
+ if (fs.existsSync(r)) return r;
13101
+ break;
13102
+ default:
13103
+ throw `invalid resolution method: ${method}`;
13104
+ }
13105
+ }
13106
+ throw `cannot resolve '${file}'`;
13107
+ }
13108
+ /**
13109
+ * Imports all items in the queue at once.
13110
+ * @return {Promise}
13111
+ */
13112
+ import() {
13113
+ let tasks = [];
13114
+ let typeMap = {
13115
+ '.css': 'style',
13116
+ '.js': 'script',
13117
+ };
13118
+ this.queue.sort((a, b) => (Number(a.order) - Number(b.order))); // sort by order
13119
+ while (this.queue.length) {
13120
+ let item = this.queue.shift();
13121
+ let {type, src} = item;
13122
+ let url;
13123
+
13124
+ if (!item.resolve) { // no resolution
13125
+ url = src;
13126
+ if (!type) type = typeMap[ext(src)] || 'asset';
13127
+ console.log('---- File Link ----');
13128
+ console.log(' type:', type);
13129
+ console.log(' src:', src);
13130
+
13131
+ } else { // needs resolution
13132
+ let {dst:dstDir, as:dstFile} = item;
13133
+ let create = item.resolve == 'create'; // needs creation?
13134
+ if (create) {
13135
+ if (!dstFile) throw `'as' property is required with {resolve: 'create'}`;
13136
+ } else {
13137
+ src = this.resolve(src, item.resolve);
13138
+ if (!dstFile) dstFile = path.basename(src);
13139
+ }
13140
+ if (!type) type = typeMap[ext(dstFile)] || 'asset';
13141
+ if (!dstDir) dstDir = type + 's';
13142
+
13143
+ // absolute destination
13144
+ url = path.join(dstDir, dstFile);
13145
+ let dst = path.join(this.config.dst, url);
13146
+ dstDir = path.dirname(dst);
13147
+ if (!fs.existsSync(dstDir)) fs.mkdirSync(dstDir, {recursive:true});
13148
+
13149
+ // create/copy file
13150
+ if (create) {
13151
+ console.log('---- File Creation ----');
13152
+ console.log(' type:', type);
13153
+ console.log(' dst:', dst);
13154
+ tasks.push(fsp.writeFile(dst, src));
13155
+ } else {
13156
+ console.log('---- File Import ----');
13157
+ console.log(' type:', type);
13158
+ console.log(' src:', src);
13159
+ console.log(' dst:', dst);
13160
+ tasks.push(fsp.copyFile(src, dst));
13161
+ }
13162
+ }
12850
13163
 
12851
- /**
12852
- * Returns a string representation of the given `Date` in ISO 9075 format, which is standard for MySQL.
12853
- * @param {Date} d - Date object
12854
- * @return {string} a string like `YYYY-MM-DD hh:mm:ss`
12855
- */
12856
- function iso9075(d) {
12857
- return ymd(d, '-') + ' ' + hms(d, ':');
12858
- }
13164
+ if (!item.private) {
13165
+ if (!(type in this.results)) this.results[type] = [];
13166
+ this.results[type].push({type, url});
13167
+ }
13168
+ }
12859
13169
 
12860
- var time = /*#__PURE__*/Object.freeze({
12861
- __proto__: null,
12862
- addTime: addTime,
12863
- ceil: ceil,
12864
- date: date,
12865
- floor: floor,
12866
- hms: hms,
12867
- iso9075: iso9075,
12868
- localize: localize,
12869
- ms: ms,
12870
- quantize: quantize,
12871
- round: round,
12872
- ymd: ymd
12873
- });
13170
+ return tasks.length ? Promise.all(tasks) : Promise.resolve();
13171
+ }
13172
+ /**
13173
+ * Outputs HTML tags for imported items.
13174
+ * @param {string} [type] - Type
13175
+ * @return {string} HTML
13176
+ */
13177
+ toHTML(type = null) {
13178
+ let r;
13179
+ if (type) {
13180
+ let tmpl = templates[type];
13181
+ if (!tmpl) return '';
13182
+ if (Array.isArray(tmpl)) tmpl = tmpl.join('\n');
13183
+ let items = this.results[type];
13184
+ r = new Array(items.length);
13185
+ for (let i = 0; i < items.length; i++) {
13186
+ r[i] = tmpl.replaceAll('%s', items[i].url || '');
13187
+ }
13188
+ } else {
13189
+ let keys = Object.keys(this.results);
13190
+ r = new Array(keys.length);
13191
+ for (let i = 0; i < keys.length; i++) {
13192
+ r[i] = this.toHTML(keys[i]);
13193
+ }
13194
+ }
13195
+ return r.join('\n');
13196
+ }
13197
+ }
12874
13198
 
12875
- /*!
12876
- * === @amekusa/util.js === *
12877
- * MIT License
12878
- *
12879
- * Copyright (c) 2024 Satoshi Soma
12880
- *
12881
- * Permission is hereby granted, free of charge, to any person obtaining a copy
12882
- * of this software and associated documentation files (the "Software"), to deal
12883
- * in the Software without restriction, including without limitation the rights
12884
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12885
- * copies of the Software, and to permit persons to whom the Software is
12886
- * furnished to do so, subject to the following conditions:
12887
- *
12888
- * The above copyright notice and this permission notice shall be included in all
12889
- * copies or substantial portions of the Software.
12890
- *
12891
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12892
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12893
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12894
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12895
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12896
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
12897
- * SOFTWARE.
13199
+ const templates = {
13200
+ script: [
13201
+ `<script src="%s"></script>`,
13202
+ ],
13203
+ module: [
13204
+ `<script type="module" src="%s"></script>`,
13205
+ ],
13206
+ style: [
13207
+ `<link rel="stylesheet" href="%s">`,
13208
+ ],
13209
+ };/**
13210
+ * Alias of `os.homedir()`.
13211
+ * @type {string}
12898
13212
  */
13213
+ const home = os.homedir();
12899
13214
 
12900
13215
  /**
12901
- * Coerces the given value into an array.
12902
- * @param {any} x
12903
- * @return {any[]}
13216
+ * Returns or overwrites the extension of the given file path.
13217
+ * @param {string} file - File path
13218
+ * @param {string} [set] - New extension
13219
+ * @return {string} the extension, or a modified file path with the new extension
12904
13220
  */
12905
- function arr(x) {
12906
- return Array.isArray(x) ? x : [x];
13221
+ function ext(file, set = null) {
13222
+ let dot = file.lastIndexOf('.');
13223
+ return typeof set == 'string'
13224
+ ? (dot < 0 ? (file + set) : (file.substring(0, dot) + set))
13225
+ : (dot < 0 ? '' : file.substring(dot));
12907
13226
  }
12908
13227
 
12909
13228
  /**
12910
- * Returns whether the given value can be considered as "empty".
12911
- * @param {any} x
12912
- * @return {boolean}
13229
+ * Searches the given file path in the given directories.
13230
+ * @param {string} file - File to find
13231
+ * @param {string[]} dirs - Array of directories to search
13232
+ * @param {object} [opts] - Options
13233
+ * @param {boolean} [opts.allowAbsolute=true] - If true, `file` can be an absolute path
13234
+ * @return {string|boolean} found file path, or false if not found
12913
13235
  */
12914
- function isEmpty(x) {
12915
- if (Array.isArray(x)) return x.length == 0;
12916
- switch (typeof x) {
12917
- case 'string':
12918
- return !x;
12919
- case 'object':
12920
- if (x === null) return true;
12921
- for (let i in x) return false;
12922
- case 'undefined':
12923
- return true;
13236
+ function find(file, dirs = [], opts = {}) {
13237
+ let {allowAbsolute = true} = opts;
13238
+ if (allowAbsolute && path.isAbsolute(file)) return fs.existsSync(file) ? file : false;
13239
+ for (let i = 0; i < dirs.length; i++) {
13240
+ let find = path.join(dirs[i], file);
13241
+ if (fs.existsSync(find)) return find;
12924
13242
  }
12925
13243
  return false;
12926
13244
  }
12927
13245
 
12928
13246
  /**
12929
- * Removes "empty" values from the given object or array.
12930
- * @param {object|any[]} x
12931
- * @param {number} recurse - Recursion limit
12932
- * @return {object|any[]} modified `x`
13247
+ * Replaces the beginning `~` character with `os.homedir()`.
13248
+ * @param {string} file - File path
13249
+ * @param {string} [replace=os.homedir()] - Replacement
13250
+ * @return {string} modified `file`
12933
13251
  */
12934
- function clean(x, recurse = 8) {
12935
- if (recurse) {
12936
- if (Array.isArray(x)) {
12937
- let r = [];
12938
- for (let i = 0; i < x.length; i++) {
12939
- let I = clean(x[i], recurse - 1);
12940
- if (!isEmpty(I)) r.push(I);
12941
- }
12942
- return r;
12943
- }
12944
- if (typeof x == 'object') {
12945
- let r = {};
12946
- for (let k in x) {
12947
- let v = clean(x[k], recurse - 1);
12948
- if (!isEmpty(v)) r[k] = v;
12949
- }
12950
- return r;
12951
- }
12952
- }
12953
- return x;
13252
+ function untilde(file, replace = home) {
13253
+ if (!file.startsWith('~')) return file;
13254
+ if (file.length == 1) return replace;
13255
+ if (file.startsWith(path.sep, 1)) return replace + file.substring(1);
13256
+ return file;
12954
13257
  }
12955
13258
 
12956
13259
  /**
12957
- * Merges the 2nd object into the 1st object recursively (deep-merge). The 1st object will be modified.
12958
- * @param {object} x - The 1st object
12959
- * @param {object} y - The 2nd object
13260
+ * Deletes the files in the given directory.
13261
+ * @param {string} dir - Directory to clean
13262
+ * @param {string|RegExp} [pattern] - File pattern
12960
13263
  * @param {object} [opts] - Options
12961
- * @param {number} opts.recurse=8 - Recurstion limit. Negative number means unlimited
12962
- * @param {boolean|string} opts.mergeArrays - How to merge arrays
12963
- * - `true`: merge x with y
12964
- * - 'push': push y elements to x
12965
- * - 'concat': concat x and y
12966
- * - other: replace x with y
12967
- * @return {object} The 1st object
13264
+ * @param {boolean} [opts.recursive=false] - Searches recursively
13265
+ * @param {object} [opts.types] - File types to delete
13266
+ * @param {boolean} [opts.types.any=false] - Any type
13267
+ * @param {boolean} [opts.types.file=true] - Regular file
13268
+ * @param {boolean} [opts.types.dir=false] - Directory
13269
+ * @param {boolean} [opts.types.symlink=false] - Symbolic link
13270
+ * @return {Promise} a promise resolved with the deleted file paths
12968
13271
  */
12969
- function merge(x, y, opts = {}) {
12970
- if (!('recurse' in opts)) opts.recurse = 8;
12971
- switch (Array.isArray(x) + Array.isArray(y)) {
12972
- case 0: // no array
12973
- if (opts.recurse && x && y && typeof x == 'object' && typeof y == 'object') {
12974
- opts.recurse--;
12975
- for (let k in y) x[k] = merge(x[k], y[k], opts);
12976
- opts.recurse++;
12977
- return x;
13272
+ function clean(dir, pattern = null, opts = {}) {
13273
+ if (pattern && typeof pattern == 'string') pattern = new RegExp(pattern);
13274
+ let {
13275
+ recursive = false,
13276
+ types = {file: true},
13277
+ } = opts;
13278
+ return fsp__namespace.readdir(dir, {recursive, withFileTypes: true}).then(files => {
13279
+ let tasks = [];
13280
+ for (let i = 0; i < files.length; i++) {
13281
+ let f = files[i];
13282
+ if (!types.any) {
13283
+ if (f.isFile()) {
13284
+ if (!types.file) continue;
13285
+ } else if (f.isDirectory()) {
13286
+ if (!types.dir) continue;
13287
+ } else if (f.isSymbolicLink()) {
13288
+ if (!types.symlink) continue;
13289
+ }
13290
+ }
13291
+ f = path.join(dir, f.name);
13292
+ if (pattern && !f.match(pattern)) continue;
13293
+ tasks.push(fsp__namespace.rm(f, {force: true, recursive: true}).then(() => f));
12978
13294
  }
12979
- case 1: // 1 array
12980
- return y;
12981
- }
12982
- // 2 arrays
12983
- switch (opts.mergeArrays) {
12984
- case true:
12985
- for (let i = 0; i < y.length; i++) {
12986
- if (!x.includes(y[i])) x.push(y[i]);
13295
+ return tasks.length ? Promise.all(tasks) : false;
13296
+ });
13297
+ }
13298
+
13299
+ /**
13300
+ * Copies the given file(s) to another directory
13301
+ * @param {string|object|string[]|object[]} src
13302
+ * @param {string} dst Base destination directory
13303
+ * @return {Promise}
13304
+ */
13305
+ function copy(src, dst) {
13306
+ return Promise.all((Array.isArray(src) ? src : [src]).map(item => {
13307
+ let _src, _dst;
13308
+ switch (typeof item) {
13309
+ case 'object':
13310
+ _src = item.src;
13311
+ _dst = item.dst;
13312
+ break;
13313
+ case 'string':
13314
+ _src = item;
13315
+ break;
13316
+ default:
13317
+ throw 'invalid type';
12987
13318
  }
12988
- return x;
12989
- case 'push':
12990
- x.push(...y);
12991
- return x;
12992
- case 'concat':
12993
- return x.concat(y);
12994
- }
12995
- return y;
13319
+ _dst = path.join(dst, _dst || path.basename(_src));
13320
+ return fsp__namespace.mkdir(path.dirname(_dst), {recursive: true}).then(fsp__namespace.copyFile(_src, _dst));
13321
+ }));
12996
13322
  }
12997
13323
 
13324
+ /**
13325
+ * Returns a Transform stream object with the given function as its transform() method.
13326
+ * `fn` must return a string which is to be the new content, or a Promise which resolves a string.
13327
+ *
13328
+ * @example
13329
+ * return gulp.src(src)
13330
+ * .pipe(modifyStream((data, enc) => {
13331
+ * // do stuff
13332
+ * return newData;
13333
+ * }));
13334
+ *
13335
+ * @param {function} fn
13336
+ * @return {Transform}
13337
+ */
13338
+ function modifyStream(fn) {
13339
+ return new node_stream.Transform({
13340
+ objectMode: true,
13341
+ transform(file, enc, done) {
13342
+ let r = fn(file.contents.toString(enc), enc);
13343
+ if (r instanceof Promise) {
13344
+ r.then(modified => {
13345
+ file.contents = Buffer.from(modified, enc);
13346
+ this.push(file);
13347
+ done();
13348
+ });
13349
+ } else {
13350
+ file.contents = Buffer.from(r, enc);
13351
+ this.push(file);
13352
+ done();
13353
+ }
13354
+ }
13355
+ });
13356
+ }var io=/*#__PURE__*/Object.freeze({__proto__:null,AssetImporter:AssetImporter,clean:clean,copy:copy,ext:ext,find:find,home:home,modifyStream:modifyStream,untilde:untilde});
13357
+
12998
13358
  /**
12999
13359
  * File I/O manager.
13000
13360
  */
@@ -13356,7 +13716,7 @@ function requireBundle () {
13356
13716
  if (r.modifiers) r.modifiers.mandatory = _mods.mandatory;
13357
13717
  else r.modifiers = _mods.mandatory;
13358
13718
  }
13359
- return opts ? merge(r, opts, {mergeArrays: true}) : r;
13719
+ return opts ? merge$1(r, opts, {mergeArrays: true}) : r;
13360
13720
  }
13361
13721
 
13362
13722
  /**
@@ -13478,6 +13838,44 @@ function requireBundle () {
13478
13838
  };
13479
13839
  }
13480
13840
 
13841
+ function var_touch(area = undefined) {
13842
+ let areas = {
13843
+ 'left_half_area': /^left/i,
13844
+ 'right_half_area': /^right/i,
13845
+ 'upper_half_area': /^(?:up|uppper|top)/i,
13846
+ 'lower_half_area': /^(?:low|lower|bottom)/i,
13847
+ };
13848
+ if (area) {
13849
+ for (let k in areas) {
13850
+ if (areas[k].test(area)) {
13851
+ area = k;
13852
+ break;
13853
+ }
13854
+ }
13855
+ } else area = 'total';
13856
+ return `multitouch_extension_finger_count_${area}`;
13857
+ }
13858
+
13859
+ /**
13860
+ * Returns an object with `type: 'variable_if'` property for Multitouch Extension, which can be passed to {@link Rule#cond} as a condition.
13861
+ * @param {string} count - finger count
13862
+ * @param {string} [area] - area to check (top/right/bottom/left)
13863
+ * @return {object} an object like: `{ type: 'variable_if', ... }`
13864
+ */
13865
+ function if_touched(count, area = undefined) {
13866
+ return if_var(var_touch(area), count);
13867
+ }
13868
+
13869
+ /**
13870
+ * Returns an object with `type: 'variable_unless'` property for Multitouch Extension, which can be passed to {@link Rule#cond} as a condition.
13871
+ * @param {string} count - finger count
13872
+ * @param {string} [area] - area to check (top/right/bottom/left)
13873
+ * @return {object} an object like: `{ type: 'variable_unless', ... }`
13874
+ */
13875
+ function unless_touched(count, area = undefined) {
13876
+ return unless_var(var_touch(area), count);
13877
+ }
13878
+
13481
13879
  /**
13482
13880
  * @typedef {object|string} Keymap
13483
13881
  * A keymap definition which can be passed to {@link Rule#remap} as `from` or `to` properties.
@@ -13565,7 +13963,7 @@ function requireBundle () {
13565
13963
  remap(map) {
13566
13964
  if (!map.type) map.type = 'basic';
13567
13965
  if (this.conds.length) map = Object.assign(map, {conditions: this.conds});
13568
- map = clean(remapSanitizer.sanitize(map));
13966
+ map = clean$1(remapSanitizer.sanitize(map));
13569
13967
  if (isEmpty(map)) console.warn(`Rule.remap: empty argument`);
13570
13968
  else this.remaps.push(map);
13571
13969
  return this;
@@ -13587,7 +13985,7 @@ function requireBundle () {
13587
13985
  * .remap( ... );
13588
13986
  */
13589
13987
  cond(cond) {
13590
- cond = clean(cond);
13988
+ cond = clean$1(cond);
13591
13989
  if (isEmpty(cond)) console.warn(`Rule.cond: empty argument`);
13592
13990
  else this.conds.push(cond);
13593
13991
  return this;
@@ -13922,24 +14320,26 @@ function requireBundle () {
13922
14320
  }
13923
14321
  }
13924
14322
 
13925
- bundle.Config = Config;
13926
- bundle.IO = IO;
13927
- bundle.Rule = Rule;
13928
- bundle.RuleSet = RuleSet;
13929
- bundle.click = click;
13930
- bundle.if_app = if_app;
13931
- bundle.if_lang = if_lang;
13932
- bundle.if_var = if_var;
13933
- bundle.key = key;
13934
- bundle.set_var = set_var;
13935
- bundle.unless_app = unless_app;
13936
- bundle.unless_lang = unless_lang;
13937
- bundle.unless_var = unless_var;
13938
- return bundle;
14323
+ karabinerge.Config = Config;
14324
+ karabinerge.IO = IO;
14325
+ karabinerge.Rule = Rule;
14326
+ karabinerge.RuleSet = RuleSet;
14327
+ karabinerge.click = click;
14328
+ karabinerge.if_app = if_app;
14329
+ karabinerge.if_lang = if_lang;
14330
+ karabinerge.if_touched = if_touched;
14331
+ karabinerge.if_var = if_var;
14332
+ karabinerge.key = key;
14333
+ karabinerge.set_var = set_var;
14334
+ karabinerge.unless_app = unless_app;
14335
+ karabinerge.unless_lang = unless_lang;
14336
+ karabinerge.unless_touched = unless_touched;
14337
+ karabinerge.unless_var = unless_var;
14338
+ return karabinerge;
13939
14339
  }var name = "keycomfort";
13940
- var version = "0.2.0";
14340
+ var version = "0.4.0";
13941
14341
  var description = "Comfortable keyboard remaps for Karabiner/AutoHotKey";
13942
- var require$$10 = {
14342
+ var require$$9 = {
13943
14343
  name: name,
13944
14344
  version: version,
13945
14345
  description: description};var rules_1;
@@ -13954,7 +14354,8 @@ function requireRules () {
13954
14354
  set_var,
13955
14355
  if_var, unless_var,
13956
14356
  if_lang, unless_lang,
13957
- } = requireBundle();
14357
+ if_touched, unless_touched,
14358
+ } = requireKarabinerge();
13958
14359
 
13959
14360
  const modding = if_var('keycomfort_layer', 1);
13960
14361
  const any = {optional: 'any'};
@@ -13971,7 +14372,8 @@ function requireRules () {
13971
14372
  },
13972
14373
 
13973
14374
  'cancel modifier'(c, r) {
13974
- r.remap({
14375
+ r.cond(if_var('keycomfort_layer_disable', 0))
14376
+ .remap({
13975
14377
  from: key(c.key, any),
13976
14378
  to: [
13977
14379
  set_var('keycomfort_layer_disable', 1),
@@ -13981,6 +14383,23 @@ function requireRules () {
13981
14383
  });
13982
14384
  },
13983
14385
 
14386
+ 'disable modifier'(c, r) {
14387
+ r.cond(modding)
14388
+ .cond(if_var('keycomfort_layer_disable', 0))
14389
+ .remap({
14390
+ from: key(c.key),
14391
+ to: set_var('keycomfort_layer_disable', 1)
14392
+ });
14393
+ },
14394
+
14395
+ 'enable modifier'(c, r) {
14396
+ r.cond(if_var('keycomfort_layer_disable', 1))
14397
+ .remap({
14398
+ from: key(c.key),
14399
+ to: set_var('keycomfort_layer_disable', 0)
14400
+ });
14401
+ },
14402
+
13984
14403
  'arrows'(c, r) {
13985
14404
  r.cond(modding)
13986
14405
  .remap({
@@ -14118,6 +14537,14 @@ function requireRules () {
14118
14537
  });
14119
14538
  },
14120
14539
 
14540
+ 'delete word'(c, r) {
14541
+ r.cond(modding)
14542
+ .remap({
14543
+ from: key(c.key),
14544
+ to: key('delete_or_backspace', 'option')
14545
+ });
14546
+ },
14547
+
14121
14548
  'edit'(c, r) {
14122
14549
  r.cond(modding)
14123
14550
  .remap({
@@ -14413,6 +14840,14 @@ function requireRules () {
14413
14840
  });
14414
14841
  },
14415
14842
 
14843
+ 'underscore'(c, r) {
14844
+ r.cond(modding)
14845
+ .remap({
14846
+ from: key(c.from),
14847
+ to: key(c.to)
14848
+ });
14849
+ },
14850
+
14416
14851
  'custom'(c, r) {
14417
14852
  if (!c.rules.length) return;
14418
14853
  r.cond(modding);
@@ -14482,6 +14917,30 @@ function requireRules () {
14482
14917
  });
14483
14918
  },
14484
14919
 
14920
+ 'l-click'(c, r) {
14921
+ r.cond(if_touched(1))
14922
+ .remap({
14923
+ from: key(c.from, any),
14924
+ to: {pointing_button: c.to}
14925
+ });
14926
+ },
14927
+
14928
+ 'r-click'(c, r) {
14929
+ r.cond(if_touched(1))
14930
+ .remap({
14931
+ from: key(c.from, any),
14932
+ to: {pointing_button: c.to}
14933
+ });
14934
+ },
14935
+
14936
+ 'm-click'(c, r) {
14937
+ r.cond(if_touched(1))
14938
+ .remap({
14939
+ from: key(c.from, any),
14940
+ to: {pointing_button: c.to}
14941
+ });
14942
+ },
14943
+
14485
14944
  };
14486
14945
 
14487
14946
  rules_1 = rules;
@@ -14494,17 +14953,16 @@ function requireMain () {
14494
14953
  const {env, cwd, stdin, stdout} = require$$0$1;
14495
14954
  const {spawnSync: spawn} = require$$1;
14496
14955
  const fs = require$$3;
14497
- const path = require$$2;
14956
+ const path = require$$3$1;
14498
14957
  const readline = require$$4$1;
14499
14958
 
14500
14959
  const {Command, Argument} = requireCommander();
14501
14960
  const yaml = require$$6;
14502
- const {merge, isEmpty} = requireBundle$2();
14503
- const {io} = requireBundle$1();
14961
+ const {io, merge, isEmpty} = requireAmekusa_util();
14504
14962
  const {
14505
14963
  RuleSet, Config,
14506
14964
  if_app, unless_app,
14507
- } = requireBundle();
14965
+ } = requireKarabinerge();
14508
14966
 
14509
14967
  /*!
14510
14968
  * === KEYCOMFORT === *
@@ -14535,9 +14993,9 @@ function requireMain () {
14535
14993
  *
14536
14994
  */
14537
14995
 
14538
- const pkg = require$$10;
14996
+ const pkg = require$$9;
14539
14997
  const rules = requireRules();
14540
- const defaultsYML = "# === KEYCOMFORT CONFIG ===\n# NOTE:\n# 0 means \"No\"\n# 1 means \"Yes\"\n\npaths:\n karabiner:\n save_as: ~/.config/karabiner/assets/complex_modifications/keycomfort.json\n apply_to: ~/.config/karabiner/karabiner.json\n ahk:\n save_as: ~/Desktop/keycomfort.ahk\n apply_to:\n\nvim_like: 0 # prefer vim-like mappings?\n\nrules: # mapping rules\n\n modifier:\n desc: Use [key] as a special modifier key (Required)\n enable: 1\n key: spacebar\n alone: spacebar\n\n cancel modifier:\n desc: Cancel modifier (<modifier>) with [key]\n enable: 1\n key: left_shift\n\n arrows:\n desc: <modifier> + [up]/[right]/[down]/[left] = Up/Right/Down/Left\n enable: 1\n up: e\n right: f\n down: d\n left: s\n\n page up/down:\n desc: <modifier> + [up]/[down] = Page Up/Down\n enable: 1\n up: w\n down: r\n\n prev/next word:\n desc: <modifier> + [prev]/[next] = Prev/Next Word\n enable: 1\n prev: a\n next: g\n apps:\n sonicpi: 1\n others: 1\n\n line start/end:\n desc: <modifier> + [start]/[end] = Line Start/End\n enable: 1\n start: q\n end: t\n apps:\n terminal: 1\n sonicpi: 1\n others: 1\n\n select:\n desc: <modifier> + [up]/[right]/[down]/[left] = Select Up/Right/Down/Left\n enable: 1\n up: i\n right: l\n down: k\n left: j\n\n vim:\n left: h\n down: j\n up: k\n right: l\n\n indent/outdent:\n desc: <modifier> + [indent]/[outdent] = Indent/Outdent\n enable: 1\n indent: o\n outdent: u\n\n backspace/delete:\n desc: <modifier> + [backspace]/[delete] = Backspace/Delete\n enable: 1\n backspace: n\n delete: m\n\n edit:\n desc: <modifier> + [undo]/[cut]/[copy]/[paste] = Undo/Cut/Copy/Paste\n enable: 1\n undo: z\n cut: x\n copy: c\n paste: v\n\n delete line:\n desc: <modifier> + [key] = Delete Line\n enable: 1\n key: shift + m\n apps:\n atom: 1\n vscode: 1\n eclipse: 1\n\n insert line:\n desc: <modifier> + [key] = New Line Below\n enable: 1\n key: return_or_enter\n apps:\n atom: 1\n vscode: 1\n eclipse: 1\n\n move line:\n desc: <modifier> + [up]/[down] = Move Line Up/Down\n enable: 1\n up: comma\n down: period\n apps:\n atom: 1\n vscode: 1\n eclipse: 1\n sonicpi: 1\n\n left/right tab:\n desc: <modifier> + [left]/[right] = Left/Right Tab\n enable: 1\n left: 2\n right: 3\n apps:\n vscode: 1\n eclipse: 1\n others: 1\n\n close/open tab:\n desc: <modifier> + [close]/[open] = Close/Open Tab\n enable: 1\n close: 1\n open: 4\n\n numpad:\n desc: <modifier> + [trigger] = Numpad Mode ([num1]=1, [num5]=5, [num9]=9)\n enable: 1\n trigger: left_control\n\n num0: b\n num1: n\n num2: m\n num3: comma\n\n num4: j\n num5: k\n num6: l\n\n num7: u\n num8: i\n num9: o\n\n slash: 8\n asterisk: 9\n hyphen: 0\n plus: p\n\n enter: slash\n delete: semicolon\n backspace: h\n\n plus/minus:\n desc: <modifier> + [plus]/[minus] = Plus/Minus\n enable: 1\n plus: p\n minus: shift + p\n to:\n plus: shift + equal_sign\n minus: hyphen\n\n backslash:\n desc: <modifier> + [from] = Backslash\n enable: 1\n from: slash\n to: backslash\n\n backtick:\n desc: <modifier> + [from] = Backtick\n enable: 1\n from: quote\n to: grave_accent_and_tilde\n\n tilde:\n desc: <modifier> + [from] = Tilde\n enable: 1\n from: hyphen\n to: shift + grave_accent_and_tilde\n\n pipe:\n desc: <modifier> + [from] = Pipe\n enable: 1\n from: 7\n to: shift + backslash\n\n equal:\n desc: <modifier> + [from] = Equal Sign\n enable: 1\n from: semicolon\n to: equal_sign\n\n enter:\n desc: <modifier> + [from] = Enter\n enable: 1\n from: tab\n to: return_or_enter\n\n custom:\n desc: <modifier> + Custom Keys\n enable: 1\n rules:\n # Examples\n # - from: p\n # to: shift + equal_sign\n\n remap capslock:\n desc: Caps Lock = [to]/[alone]\n enable: 1\n to: left_control\n alone: escape\n\n remap l-control:\n desc: Left Control = [to]/[alone]\n enable: 1\n to: left_control\n alone: escape\n\n remap r-control:\n desc: Right Control = [to]/[alone]\n enable: 0\n to: right_control\n alone: escape\n\n remap l-command:\n desc: Left Command = [to]/[alone]\n enable: 0\n to: left_command\n alone: left_command\n\n remap r-command:\n desc: Right Command = [to]/[alone]\n enable: 0\n to: right_command\n alone: right_command\n\n remap l-shift:\n desc: Left Shift = [to]/[alone]\n enable: 0\n to: left_shift\n alone: left_shift\n\n remap r-shift:\n desc: Right Shift = [to]/[alone]\n enable: 0\n to: right_shift\n alone: right_shift\n\n\napps:\n others:\n enable: 1\n\n login:\n enable: 1\n id:\n - com.apple.loginwindow\n\n terminal:\n enable: 1\n id:\n - com.apple.Terminal\n - com.googlecode.iterm2\n - org.alacritty\n exe:\n - cmd.exe\n\n vscode:\n enable: 0\n id:\n - com.microsoft.VSCode\n - com.vscodium\n exe:\n - Code.exe\n\n atom:\n enable: 0\n id:\n - com.github.atom\n - dev.pulsar-edit.pulsar\n\n eclipse:\n enable: 0\n id:\n - org.eclipse.platform.ide\n exe:\n - eclipse.exe\n\n sonicpi:\n enable: 0\n id:\n - net.sonic-pi.app\n\n\nkey_labels: # display names for key codes\n spacebar: Space\n return_or_enter: Enter\n grave_accent_and_tilde: Backtick\n japanese_eisuu: 英数\n japanese_kana: かな\n\n";
14998
+ const defaultsYML = "# === KEYCOMFORT CONFIG ===\n# NOTE:\n# 0 means \"No\"\n# 1 means \"Yes\"\n\npaths:\n karabiner:\n save_as: ~/.config/karabiner/assets/complex_modifications/keycomfort.json\n apply_to: ~/.config/karabiner/karabiner.json\n ahk:\n save_as: ~/Desktop/keycomfort.ahk\n apply_to:\n\nvim_like: 0 # prefer vim-like mappings?\n\nrules: # mapping rules\n\n modifier:\n desc: Use [key] as a special modifier key (Required)\n enable: 1\n key: spacebar\n alone: spacebar\n\n cancel modifier:\n desc: Cancel modifier (<modifier>) with [key]\n enable: 1\n key: left_shift\n\n disable modifier:\n desc: Disable modifier (<modifier>) with <modifier> + [key]\n enable: 1\n key: right_shift + escape\n\n enable modifier:\n desc: Enable modifier (<modifier>) with [key]\n enable: 1\n key: right_shift + escape\n\n arrows:\n desc: <modifier> + { [up] / [right] / [down] / [left] } = Up / Right / Down / Left\n enable: 1\n up: e\n right: f\n down: d\n left: s\n\n page up/down:\n desc: <modifier> + { [up] / [down] } = Page Up / Down\n enable: 1\n up: w\n down: r\n\n prev/next word:\n desc: <modifier> + { [prev] / [next] } = Prev / Next Word\n enable: 1\n prev: a\n next: g\n apps:\n sonicpi: 1\n others: 1\n\n line start/end:\n desc: <modifier> + { [start] / [end] } = Line Start / End\n enable: 1\n start: q\n end: t\n apps:\n terminal: 1\n sonicpi: 1\n others: 1\n\n select:\n desc: <modifier> + { [up] / [right] / [down] / [left] } = Select Up / Right / Down / Left\n enable: 1\n up: i\n right: l\n down: k\n left: j\n vim:\n left: h\n down: j\n up: k\n right: l\n\n indent/outdent:\n desc: <modifier> + { [indent] / [outdent] } = Indent / Outdent\n enable: 1\n indent: o\n outdent: u\n\n backspace/delete:\n desc: <modifier> + { [backspace] / [delete] } = Backspace / Delete\n enable: 1\n backspace: n\n delete: m\n\n delete word:\n desc: <modifier> + [key] = Delete Word\n enable: 1\n key: b\n\n edit:\n desc: <modifier> + { [undo] / [cut] / [copy] / [paste] } = Undo / Cut / Copy / Paste\n enable: 1\n undo: z\n cut: x\n copy: c\n paste: v\n\n delete line:\n desc: <modifier> + [key] = Delete Line\n enable: 1\n key: shift + m\n apps:\n atom: 1\n vscode: 1\n eclipse: 1\n\n insert line:\n desc: <modifier> + [key] = New Line Below\n enable: 1\n key: return_or_enter\n apps:\n atom: 1\n vscode: 1\n eclipse: 1\n\n move line:\n desc: <modifier> + { [up] / [down] } = Move Line Up / Down\n enable: 1\n up: shift + i\n down: shift + k\n vim:\n up: shift + k\n down: shift + j\n apps:\n atom: 1\n vscode: 1\n eclipse: 1\n sonicpi: 1\n\n left/right tab:\n desc: <modifier> + { [left] / [right] } = Left / Right Tab\n enable: 1\n left: 2\n right: 3\n apps:\n vscode: 1\n eclipse: 1\n others: 1\n\n close/open tab:\n desc: <modifier> + { [close] / [open] } = Close / Open Tab\n enable: 1\n close: 1\n open: 4\n\n numpad:\n desc: <modifier> + [trigger] = Numpad Mode ([num1]=1, [num5]=5, [num9]=9)\n enable: 1\n trigger: left_control\n\n num0: b\n num1: n\n num2: m\n num3: comma\n\n num4: j\n num5: k\n num6: l\n\n num7: u\n num8: i\n num9: o\n\n slash: 8\n asterisk: 9\n hyphen: 0\n plus: p\n\n enter: slash\n delete: semicolon\n backspace: h\n\n plus/minus:\n desc: <modifier> + { [plus] / [minus] } = Plus / Minus\n enable: 1\n plus: p\n minus: shift + p\n to:\n plus: shift + equal_sign\n minus: hyphen\n\n backslash:\n desc: <modifier> + [from] = Backslash\n enable: 1\n from: slash\n to: backslash\n\n backtick:\n desc: <modifier> + [from] = Backtick\n enable: 1\n from: quote\n to: grave_accent_and_tilde\n\n tilde:\n desc: <modifier> + [from] = Tilde\n enable: 1\n from: hyphen\n to: shift + grave_accent_and_tilde\n\n pipe:\n desc: <modifier> + [from] = Pipe\n enable: 1\n from: 7\n to: shift + backslash\n\n equal:\n desc: <modifier> + [from] = Equal Sign\n enable: 1\n from: semicolon\n to: equal_sign\n\n enter:\n desc: <modifier> + [from] = Enter\n enable: 1\n from: tab\n to: return_or_enter\n\n underscore:\n desc: <modifier> + [from] = Underscore\n enable: 1\n from: period\n to: shift + hyphen\n\n custom:\n desc: <modifier> + Custom Keys\n enable: 1\n rules:\n # Examples\n # - from: p\n # to: shift + equal_sign\n\n remap capslock:\n desc: Caps Lock = [to] / [alone]\n enable: 1\n to: left_control\n alone: escape\n\n remap l-control:\n desc: Left Control = [to] / [alone]\n enable: 1\n to: left_control\n alone: escape\n\n remap r-control:\n desc: Right Control = [to] / [alone]\n enable: 0\n to: right_control\n alone: escape\n\n remap l-command:\n desc: Left Command = [to] / [alone]\n enable: 0\n to: left_command\n alone: left_command\n\n remap r-command:\n desc: Right Command = [to] / [alone]\n enable: 0\n to: right_command\n alone: right_command\n\n remap l-shift:\n desc: Left Shift = [to] / [alone]\n enable: 0\n to: left_shift\n alone: left_shift\n\n remap r-shift:\n desc: Right Shift = [to] / [alone]\n enable: 0\n to: right_shift\n alone: right_shift\n\n l-click:\n desc: (MultiTouchExtension) Touchpad + [from] = [to]\n enable: 1\n from: j\n to: button1\n\n r-click:\n desc: (MultiTouchExtension) Touchpad + [from] = [to]\n enable: 1\n from: l\n to: button2\n\n m-click:\n desc: (MultiTouchExtension) Touchpad + [from] = [to]\n enable: 1\n from: k\n to: button3\n\n\napps:\n others:\n enable: 1\n\n login:\n enable: 1\n id:\n - com.apple.loginwindow\n\n terminal:\n enable: 1\n id:\n - com.apple.Terminal\n - com.googlecode.iterm2\n - org.alacritty\n exe:\n - cmd.exe\n\n vscode:\n enable: 0\n id:\n - com.microsoft.VSCode\n - com.vscodium\n exe:\n - Code.exe\n\n atom:\n enable: 0\n id:\n - com.github.atom\n - dev.pulsar-edit.pulsar\n\n eclipse:\n enable: 0\n id:\n - org.eclipse.platform.ide\n exe:\n - eclipse.exe\n\n sonicpi:\n enable: 0\n id:\n - net.sonic-pi.app\n\n\nkey_labels: # display names for key codes\n spacebar: Space\n return_or_enter: Enter\n grave_accent_and_tilde: Backtick\n button1: Left Click\n button2: Right Click\n button3: Middle Click\n japanese_eisuu: 英数\n japanese_kana: かな\n\n";
14541
14999
  const defaults = yaml.parse(defaultsYML);
14542
15000
  const defaultConfig = loc(io.home, '.config', 'keycomfort', 'config.yml');
14543
15001
 
@@ -14579,10 +15037,18 @@ function requireMain () {
14579
15037
  }
14580
15038
 
14581
15039
  function label(key, dict) {
14582
- if (Array.isArray(key)) return key.map(I => label(I, dict)).join(',');
14583
- key += '';
15040
+ if (Array.isArray(key)) return key.map(I => label(I.trim(), dict)).join(', ');
15041
+ key = `${key}`.trim();
15042
+ if (key.includes(',')) return label(key.split(','), dict);
15043
+ if (key.includes('+')) return key.split('+').map(I => label(I.trim(), dict)).join(' + ');
14584
15044
  if (key in dict) return dict[key];
14585
- return key.split('_').map(I => I.charAt(0).toUpperCase() + I.slice(1)).join(' ');
15045
+ let lr = ''; // left or right
15046
+ let m = key.match(/^(left|right)_([_a-z0-9]+)$/i);
15047
+ if (m) {
15048
+ lr = m[1] == 'left' ? 'L-' : 'R-';
15049
+ key = m[2];
15050
+ }
15051
+ return lr + key.split('_').map(I => I.charAt(0).toUpperCase() + I.slice(1)).join(' ');
14586
15052
  }
14587
15053
 
14588
15054
  const app = new Command();
@@ -14727,8 +15193,9 @@ function requireMain () {
14727
15193
  if (rc.vim && vim) rc = merge(rc, rc.vim);
14728
15194
 
14729
15195
  // format rule description
14730
- let desc = rc.desc.replaceAll('<modifier>', label(modifier, labels));
14731
- for (let i in rc) desc = desc.replaceAll(`[${i}]`, label(rc[i], labels));
15196
+ let desc = rc.desc.replaceAll(/(?:<modifier>|\[([_0-9a-z]+)\])/gi, (_, m1) => {
15197
+ return label(m1 ? rc[m1] : modifier, labels);
15198
+ });
14732
15199
 
14733
15200
  let rule = rules[i];
14734
15201
  let newRule;