@thi.ng/file-io 0.1.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2022-05-18T12:59:20Z
3
+ - **Last updated**: 2022-05-20T09:18:30Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,25 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ ## [0.3.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/file-io@0.3.0) (2022-05-20)
13
+
14
+ #### 🚀 Features
15
+
16
+ - add more fns (hashing, masking etc.) ([95b9e2b](https://github.com/thi-ng/umbrella/commit/95b9e2b))
17
+ - add fileHash(), stringHash()
18
+ - add maskHomeDir()
19
+ - add fileExt(), isDirectory()
20
+
21
+ #### 🩹 Bug fixes
22
+
23
+ - fix ensureDir() for local file paths ([4ae95c2](https://github.com/thi-ng/umbrella/commit/4ae95c2))
24
+
25
+ ## [0.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/file-io@0.2.0) (2022-05-19)
26
+
27
+ #### 🚀 Features
28
+
29
+ - add dirs() iterator, add writeFile(), dry-run handling ([0279db8](https://github.com/thi-ng/umbrella/commit/0279db8))
30
+
12
31
  ## [0.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/file-io@0.1.0) (2022-05-18)
13
32
 
14
33
  #### 🚀 Features
package/delete.d.ts CHANGED
@@ -1,3 +1,12 @@
1
1
  import type { ILogger } from "@thi.ng/logger";
2
- export declare const deleteFile: (path: string, logger?: ILogger | undefined) => void;
2
+ /**
3
+ * Deletes file at given path. If `dryRun` is true (default: false), the file
4
+ * WON'T be deleted, however if a `logger` is provided then at least a dry-run
5
+ * log message will be emitted.
6
+ *
7
+ * @param path
8
+ * @param logger
9
+ * @param dryRun
10
+ */
11
+ export declare const deleteFile: (path: string, logger?: ILogger | undefined, dryRun?: boolean) => void;
3
12
  //# sourceMappingURL=delete.d.ts.map
package/delete.js CHANGED
@@ -1,5 +1,16 @@
1
1
  import { unlinkSync } from "fs";
2
- export const deleteFile = (path, logger) => {
3
- logger && logger.debug("deleting file:", path);
2
+ /**
3
+ * Deletes file at given path. If `dryRun` is true (default: false), the file
4
+ * WON'T be deleted, however if a `logger` is provided then at least a dry-run
5
+ * log message will be emitted.
6
+ *
7
+ * @param path
8
+ * @param logger
9
+ * @param dryRun
10
+ */
11
+ export const deleteFile = (path, logger, dryRun = false) => {
12
+ logger && logger.info(`${dryRun ? "[dryrun] " : ""}deleting file: ${path}`);
13
+ if (dryRun)
14
+ return;
4
15
  unlinkSync(path);
5
16
  };
package/dir.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Checks if the directory for given file `path` already exists, and if not the
3
+ * case, creates it. Returns true if the latter case.
4
+ *
5
+ * @remarks
6
+ * If `path` only contains a filename (without any directory structure), the
7
+ * function does nothing.
8
+ *
9
+ * @param path
10
+ */
11
+ export declare const ensureDirForFile: (path: string) => boolean;
12
+ /**
13
+ * Returns true if `path` is a directory (assumes path exists).
14
+ *
15
+ * @param path
16
+ */
17
+ export declare const isDirectory: (path: string) => boolean;
18
+ //# sourceMappingURL=dir.d.ts.map
package/dir.js ADDED
@@ -0,0 +1,24 @@
1
+ import { existsSync, mkdirSync, statSync } from "fs";
2
+ import { sep } from "path";
3
+ /**
4
+ * Checks if the directory for given file `path` already exists, and if not the
5
+ * case, creates it. Returns true if the latter case.
6
+ *
7
+ * @remarks
8
+ * If `path` only contains a filename (without any directory structure), the
9
+ * function does nothing.
10
+ *
11
+ * @param path
12
+ */
13
+ export const ensureDirForFile = (path) => {
14
+ const dir = path.substring(0, path.lastIndexOf(sep));
15
+ return dir.length > 0 && !existsSync(dir)
16
+ ? (mkdirSync(dir, { recursive: true }), true)
17
+ : false;
18
+ };
19
+ /**
20
+ * Returns true if `path` is a directory (assumes path exists).
21
+ *
22
+ * @param path
23
+ */
24
+ export const isDirectory = (path) => statSync(path).isDirectory();
package/ext.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Returns file extension of given file `path`.
3
+ *
4
+ * @param path
5
+ */
6
+ export declare const fileExt: (path: string) => string;
7
+ //# sourceMappingURL=ext.d.ts.map
package/ext.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Returns file extension of given file `path`.
3
+ *
4
+ * @param path
5
+ */
6
+ export const fileExt = (path) => {
7
+ const match = /\.(\w+)$/.exec(path);
8
+ return match ? match[1].toLowerCase() : "";
9
+ };
package/files.d.ts CHANGED
@@ -3,10 +3,31 @@ import type { ILogger } from "@thi.ng/logger";
3
3
  * Recursively reads given directory (up to given max. depth, default: infinite)
4
4
  * and yields sequence of file names matching given extension (or regexp).
5
5
  *
6
+ * @remarks
7
+ * If NO `match` is given, all files will be matched. Directory names will not
8
+ * be tested and are always traversed (up to given `maxDepth`).
9
+ *
10
+ * The optional `logger` is only used to log errors for files which couldn't be
11
+ * accessed.
12
+ *
13
+ * @param dir
14
+ * @param match
15
+ * @param maxDepth
16
+ * @param logger
17
+ */
18
+ export declare const files: (dir: string, match?: string | RegExp, maxDepth?: number, logger?: ILogger | undefined) => IterableIterator<string>;
19
+ /**
20
+ * Similar to {@link files}, however yields iterator of only matching
21
+ * sub-directories in given `dir`. Normal files are being ignored.
22
+ *
23
+ * @remarks
24
+ * Unlike the regex matching in {@link files}, here the regex will be applied to
25
+ * the _full_ sub-path (starting with `dir`) in order to determine a match.
26
+ *
6
27
  * @param dir
7
28
  * @param match
8
29
  * @param maxDepth
9
30
  * @param logger
10
31
  */
11
- export declare const files: (dir: string, match: string | RegExp, maxDepth?: number, logger?: ILogger | undefined) => IterableIterator<string>;
32
+ export declare const dirs: (dir: string, match?: string | RegExp, maxDepth?: number, logger?: ILogger | undefined) => IterableIterator<string>;
12
33
  //# sourceMappingURL=files.d.ts.map
package/files.js CHANGED
@@ -1,31 +1,37 @@
1
1
  import { isString } from "@thi.ng/checks/is-string";
2
2
  import { readdirSync, statSync } from "fs";
3
3
  import { sep } from "path";
4
+ import { isDirectory } from "./dir.js";
4
5
  /**
5
6
  * Recursively reads given directory (up to given max. depth, default: infinite)
6
7
  * and yields sequence of file names matching given extension (or regexp).
7
8
  *
9
+ * @remarks
10
+ * If NO `match` is given, all files will be matched. Directory names will not
11
+ * be tested and are always traversed (up to given `maxDepth`).
12
+ *
13
+ * The optional `logger` is only used to log errors for files which couldn't be
14
+ * accessed.
15
+ *
8
16
  * @param dir
9
17
  * @param match
10
18
  * @param maxDepth
11
19
  * @param logger
12
20
  */
13
- export const files = (dir, match, maxDepth = Infinity, logger) => __files(dir, match, logger, maxDepth, 0);
14
- function* __files(dir, match, logger, maxDepth = Infinity, depth = 0) {
21
+ export const files = (dir, match = "", maxDepth = Infinity, logger) => __files(dir, match, logger, maxDepth, 0);
22
+ function* __files(dir, match = "", logger, maxDepth = Infinity, depth = 0) {
15
23
  if (depth >= maxDepth)
16
24
  return;
17
- const re = isString(match)
18
- ? new RegExp(`${match.replace(/\./g, "\\.")}$`)
19
- : match;
25
+ const re = __ensureRegEx(match);
20
26
  for (let f of readdirSync(dir)) {
21
27
  const curr = dir + sep + f;
22
28
  try {
23
- if (re.test(f)) {
24
- yield curr;
25
- }
26
- else if (statSync(curr).isDirectory()) {
29
+ if (isDirectory(curr)) {
27
30
  yield* __files(curr, match, logger, maxDepth, depth + 1);
28
31
  }
32
+ else if (re.test(f)) {
33
+ yield curr;
34
+ }
29
35
  }
30
36
  catch (e) {
31
37
  logger &&
@@ -33,3 +39,38 @@ function* __files(dir, match, logger, maxDepth = Infinity, depth = 0) {
33
39
  }
34
40
  }
35
41
  }
42
+ /**
43
+ * Similar to {@link files}, however yields iterator of only matching
44
+ * sub-directories in given `dir`. Normal files are being ignored.
45
+ *
46
+ * @remarks
47
+ * Unlike the regex matching in {@link files}, here the regex will be applied to
48
+ * the _full_ sub-path (starting with `dir`) in order to determine a match.
49
+ *
50
+ * @param dir
51
+ * @param match
52
+ * @param maxDepth
53
+ * @param logger
54
+ */
55
+ export const dirs = (dir, match = "", maxDepth = Infinity, logger) => __dirs(dir, match, logger, maxDepth, 0);
56
+ function* __dirs(dir, match = "", logger, maxDepth = Infinity, depth = 0) {
57
+ if (depth >= maxDepth)
58
+ return;
59
+ const re = __ensureRegEx(match);
60
+ for (let f of readdirSync(dir)) {
61
+ const curr = dir + sep + f;
62
+ try {
63
+ if (statSync(curr).isDirectory()) {
64
+ if (re.test(curr))
65
+ yield curr;
66
+ yield* __dirs(curr, match, logger, maxDepth, depth + 1);
67
+ }
68
+ }
69
+ catch (e) {
70
+ logger &&
71
+ logger.warn(`ignoring file/dir: ${f} (${e.message})`);
72
+ }
73
+ }
74
+ }
75
+ /** @internal */
76
+ const __ensureRegEx = (match) => isString(match) ? new RegExp(`${match.replace(/\./g, "\\.")}$`) : match;
package/hash.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { ILogger } from "@thi.ng/logger";
2
+ export declare type HashAlgo = "gost-mac" | "md4" | "md5" | "md_gost94" | "ripemd160" | "sha1" | "sha224" | "sha256" | "sha384" | "sha512" | "streebog256" | "streebog512" | "whirlpool";
3
+ export declare const fileHash: (path: string, logger?: ILogger | undefined, algo?: HashAlgo) => string;
4
+ export declare const stringHash: (src: string, logger?: ILogger | undefined, algo?: HashAlgo) => string;
5
+ //# sourceMappingURL=hash.d.ts.map
package/hash.js ADDED
@@ -0,0 +1,16 @@
1
+ import { createHash } from "crypto";
2
+ import { readFileSync } from "fs";
3
+ export const fileHash = (path, logger, algo = "sha256") => {
4
+ const sum = createHash(algo);
5
+ sum.update(readFileSync(path));
6
+ const hash = sum.digest("hex");
7
+ logger && logger.info(`${algo} hash for ${path}: ${hash}`);
8
+ return hash;
9
+ };
10
+ export const stringHash = (src, logger, algo = "sha256") => {
11
+ const sum = createHash(algo);
12
+ sum.update(src);
13
+ const hash = sum.digest("hex");
14
+ logger && logger.info(`${algo} hash for string: ${hash}`);
15
+ return hash;
16
+ };
package/index.d.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  export * from "./delete.js";
2
- export * from "./ensure-dir.js";
2
+ export * from "./dir.js";
3
+ export * from "./ext.js";
3
4
  export * from "./files.js";
5
+ export * from "./hash.js";
4
6
  export * from "./json.js";
7
+ export * from "./mask.js";
5
8
  export * from "./temp.js";
6
9
  export * from "./text.js";
10
+ export * from "./write.js";
7
11
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  export * from "./delete.js";
2
- export * from "./ensure-dir.js";
2
+ export * from "./dir.js";
3
+ export * from "./ext.js";
3
4
  export * from "./files.js";
5
+ export * from "./hash.js";
4
6
  export * from "./json.js";
7
+ export * from "./mask.js";
5
8
  export * from "./temp.js";
6
9
  export * from "./text.js";
10
+ export * from "./write.js";
package/json.d.ts CHANGED
@@ -1,5 +1,20 @@
1
1
  import type { Fn3, NumOrString } from "@thi.ng/api";
2
2
  import type { ILogger } from "@thi.ng/logger";
3
3
  export declare const readJSON: (path: string, logger?: ILogger | undefined) => any;
4
- export declare const writeJSON: (path: string, obj: any, replacer?: Fn3<any, string, any, any> | NumOrString[] | null | undefined, space?: NumOrString | undefined, logger?: ILogger | undefined) => void;
4
+ /**
5
+ * Serializes `obj` to JSON and writes result to UTF-8 file `path`. See
6
+ * {@link writeText} for more details.
7
+ *
8
+ * @remarks
9
+ * The `replacer` and `space` args are the same as supported by
10
+ * `JSON.stringify()`.
11
+ *
12
+ * @param path
13
+ * @param obj
14
+ * @param replacer
15
+ * @param space
16
+ * @param logger
17
+ * @param dryRun
18
+ */
19
+ export declare const writeJSON: (path: string, obj: any, replacer?: Fn3<any, string, any, any> | NumOrString[] | null | undefined, space?: NumOrString | undefined, logger?: ILogger | undefined, dryRun?: boolean) => void;
5
20
  //# sourceMappingURL=json.d.ts.map
package/json.js CHANGED
@@ -1,3 +1,18 @@
1
1
  import { readText, writeText } from "./text.js";
2
2
  export const readJSON = (path, logger) => JSON.parse(readText(path, logger));
3
- export const writeJSON = (path, obj, replacer, space, logger) => writeText(path, JSON.stringify(obj, replacer, space), logger);
3
+ /**
4
+ * Serializes `obj` to JSON and writes result to UTF-8 file `path`. See
5
+ * {@link writeText} for more details.
6
+ *
7
+ * @remarks
8
+ * The `replacer` and `space` args are the same as supported by
9
+ * `JSON.stringify()`.
10
+ *
11
+ * @param path
12
+ * @param obj
13
+ * @param replacer
14
+ * @param space
15
+ * @param logger
16
+ * @param dryRun
17
+ */
18
+ export const writeJSON = (path, obj, replacer, space, logger, dryRun = false) => writeText(path, JSON.stringify(obj, replacer, space) + "\n", logger, dryRun);
package/mask.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Replaces `home` (default: `process.env.HOME`) sub-path with given `mask`
3
+ * (default: `~`).
4
+ *
5
+ * @param path
6
+ * @param home
7
+ */
8
+ export declare const maskHomeDir: (path: string, home?: string | undefined, mask?: string) => string;
9
+ //# sourceMappingURL=mask.d.ts.map
package/mask.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Replaces `home` (default: `process.env.HOME`) sub-path with given `mask`
3
+ * (default: `~`).
4
+ *
5
+ * @param path
6
+ * @param home
7
+ */
8
+ export const maskHomeDir = (path, home = process.env.HOME, mask = "~") => (home ? path.replace(home, mask) : path);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/file-io",
3
- "version": "0.1.0",
3
+ "version": "0.3.1",
4
4
  "description": "Assorted file I/O utils (with logging support) for NodeJS",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -37,11 +37,11 @@
37
37
  "@thi.ng/api": "^8.3.6",
38
38
  "@thi.ng/checks": "^3.1.6",
39
39
  "@thi.ng/logger": "^1.1.6",
40
- "@thi.ng/random": "^3.2.6"
40
+ "@thi.ng/random": "^3.3.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@microsoft/api-extractor": "^7.23.1",
44
- "@thi.ng/testament": "^0.2.6",
44
+ "@thi.ng/testament": "^0.2.7",
45
45
  "rimraf": "^3.0.2",
46
46
  "tools": "^0.0.1",
47
47
  "typedoc": "^0.22.15",
@@ -49,6 +49,9 @@
49
49
  },
50
50
  "keywords": [
51
51
  "file",
52
+ "hash",
53
+ "json",
54
+ "logger",
52
55
  "node-only",
53
56
  "typescript"
54
57
  ],
@@ -73,25 +76,37 @@
73
76
  "./delete": {
74
77
  "default": "./delete.js"
75
78
  },
76
- "./ensure-dir": {
77
- "default": "./ensure-dir.js"
79
+ "./dir": {
80
+ "default": "./dir.js"
81
+ },
82
+ "./ext": {
83
+ "default": "./ext.js"
78
84
  },
79
85
  "./files": {
80
86
  "default": "./files.js"
81
87
  },
88
+ "./hash": {
89
+ "default": "./hash.js"
90
+ },
82
91
  "./json": {
83
92
  "default": "./json.js"
84
93
  },
94
+ "./mask": {
95
+ "default": "./mask.js"
96
+ },
85
97
  "./temp": {
86
98
  "default": "./temp.js"
87
99
  },
88
100
  "./text": {
89
101
  "default": "./text.js"
102
+ },
103
+ "./write": {
104
+ "default": "./write.js"
90
105
  }
91
106
  },
92
107
  "thi.ng": {
93
108
  "status": "stable",
94
109
  "year": 2022
95
110
  },
96
- "gitHead": "f696c94665a3adef4fa475d99dd2e18ceb15863f\n"
111
+ "gitHead": "e23901b8582af71d8a29e0ce4929f15ac509f9e5\n"
97
112
  }
package/temp.js CHANGED
@@ -3,7 +3,7 @@ import { randomID } from "@thi.ng/random/random-id";
3
3
  import { realpathSync, writeFileSync } from "fs";
4
4
  import { tmpdir } from "os";
5
5
  import { sep } from "path";
6
- import { ensureDirForFile } from "./ensure-dir.js";
6
+ import { ensureDirForFile } from "./dir.js";
7
7
  export const createTempFile = (body, logger, name) => {
8
8
  const path = tempFilePath(name);
9
9
  logger && logger.debug("creating temp file:", path);
package/text.d.ts CHANGED
@@ -1,4 +1,14 @@
1
1
  import type { ILogger } from "@thi.ng/logger";
2
2
  export declare const readText: (path: string, logger?: ILogger | undefined) => string;
3
- export declare const writeText: (path: string, body: string | string[], logger?: ILogger | undefined) => void;
3
+ /**
4
+ * Writes `body` as UTF-8 file to given `path`. If `dryRun` is true (default:
5
+ * false), the file WON'T be written, however if a `logger` is provided then at
6
+ * least a dry-run log message will be emitted.
7
+ *
8
+ * @param path
9
+ * @param body
10
+ * @param logger
11
+ * @param dryRun
12
+ */
13
+ export declare const writeText: (path: string, body: string | string[], logger?: ILogger | undefined, dryRun?: boolean) => void;
4
14
  //# sourceMappingURL=text.d.ts.map
package/text.js CHANGED
@@ -1,12 +1,18 @@
1
1
  import { isArray } from "@thi.ng/checks/is-array";
2
- import { readFileSync, writeFileSync } from "fs";
3
- import { ensureDirForFile } from "./ensure-dir.js";
2
+ import { readFileSync } from "fs";
3
+ import { writeFile } from "./write.js";
4
4
  export const readText = (path, logger) => {
5
5
  logger && logger.debug("reading file:", path);
6
6
  return readFileSync(path, "utf-8");
7
7
  };
8
- export const writeText = (path, body, logger) => {
9
- logger && logger.debug("writing file:", path);
10
- ensureDirForFile(path);
11
- writeFileSync(path, isArray(body) ? body.join("\n") : body, "utf-8");
12
- };
8
+ /**
9
+ * Writes `body` as UTF-8 file to given `path`. If `dryRun` is true (default:
10
+ * false), the file WON'T be written, however if a `logger` is provided then at
11
+ * least a dry-run log message will be emitted.
12
+ *
13
+ * @param path
14
+ * @param body
15
+ * @param logger
16
+ * @param dryRun
17
+ */
18
+ export const writeText = (path, body, logger, dryRun = false) => writeFile(path, isArray(body) ? body.join("\n") : body, "utf-8", logger, dryRun);
package/write.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ /// <reference types="node" />
2
+ import type { TypedArray } from "@thi.ng/api";
3
+ import type { ILogger } from "@thi.ng/logger";
4
+ import { WriteFileOptions } from "fs";
5
+ /**
6
+ * Writes `body` as to given `path` (using optional `opts` to define encoding).
7
+ * If `dryRun` is true (default: false), the file WON'T be written, however if a
8
+ * `logger` is provided then at least a dry-run log message will be emitted.
9
+ *
10
+ * @param path
11
+ * @param body
12
+ * @param opts
13
+ * @param logger
14
+ * @param dryRun
15
+ */
16
+ export declare const writeFile: (path: string, body: string | TypedArray, opts?: WriteFileOptions | undefined, logger?: ILogger | undefined, dryRun?: boolean) => void;
17
+ //# sourceMappingURL=write.d.ts.map
package/write.js ADDED
@@ -0,0 +1,21 @@
1
+ import { isString } from "@thi.ng/checks/is-string";
2
+ import { writeFileSync } from "fs";
3
+ import { ensureDirForFile } from "./dir.js";
4
+ /**
5
+ * Writes `body` as to given `path` (using optional `opts` to define encoding).
6
+ * If `dryRun` is true (default: false), the file WON'T be written, however if a
7
+ * `logger` is provided then at least a dry-run log message will be emitted.
8
+ *
9
+ * @param path
10
+ * @param body
11
+ * @param opts
12
+ * @param logger
13
+ * @param dryRun
14
+ */
15
+ export const writeFile = (path, body, opts, logger, dryRun = false) => {
16
+ logger && logger.info(`${dryRun ? "[dryrun] " : ""}writing file: ${path}`);
17
+ if (dryRun)
18
+ return;
19
+ ensureDirForFile(path);
20
+ writeFileSync(path, body, !opts && isString(body) ? "utf-8" : opts);
21
+ };
package/ensure-dir.d.ts DELETED
@@ -1,8 +0,0 @@
1
- /**
2
- * Checks if the directory for given file path already exists, and if not the
3
- * case, creates it. Returns true if the latter case.
4
- *
5
- * @param path
6
- */
7
- export declare const ensureDirForFile: (path: string) => boolean;
8
- //# sourceMappingURL=ensure-dir.d.ts.map
package/ensure-dir.js DELETED
@@ -1,14 +0,0 @@
1
- import { existsSync, mkdirSync } from "fs";
2
- import { sep } from "path";
3
- /**
4
- * Checks if the directory for given file path already exists, and if not the
5
- * case, creates it. Returns true if the latter case.
6
- *
7
- * @param path
8
- */
9
- export const ensureDirForFile = (path) => {
10
- const dir = path.substring(0, path.lastIndexOf(sep));
11
- return !existsSync(dir)
12
- ? (mkdirSync(dir, { recursive: true }), true)
13
- : false;
14
- };