git-stack-cli 2.2.6 → 2.2.7
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/README.md +5 -1
- package/dist/js/index.js +44 -28
- package/package.json +1 -1
- package/scripts/bun-build.ts +34 -23
- package/scripts/git-sequence-editor.sh +18 -6
- package/src/core/GitReviseTodo.ts +7 -11
- package/src/core/Metadata.ts +0 -3
- package/src/core/safe_quote.ts +4 -0
package/README.md
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://github.com/user-attachments/assets/3fba8b2d-2cb2-446b-8bf4-523643636565" alt="Logo" height=240>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# `git stack`
|
|
2
6
|
|
|
3
7
|
- ✨ **[Stacked diffs](https://graphite.dev/guides/stacked-diffs) for `git`**
|
|
4
8
|
- 🚀 **Simple one-branch workflow**
|
package/dist/js/index.js
CHANGED
|
@@ -37974,16 +37974,6 @@ function CheckGitRevise(props) {
|
|
|
37974
37974
|
var React25 = __toESM(require_react(), 1);
|
|
37975
37975
|
var import_cloneDeep = __toESM(require_cloneDeep(), 1);
|
|
37976
37976
|
|
|
37977
|
-
// src/core/safe_quote.ts
|
|
37978
|
-
function safe_quote(value) {
|
|
37979
|
-
let result = value;
|
|
37980
|
-
result = result.replace(RE2.all_double_quote, "\\\"");
|
|
37981
|
-
return result;
|
|
37982
|
-
}
|
|
37983
|
-
var RE2 = {
|
|
37984
|
-
all_double_quote: /"/g
|
|
37985
|
-
};
|
|
37986
|
-
|
|
37987
37977
|
// src/core/Metadata.ts
|
|
37988
37978
|
function write(message, values) {
|
|
37989
37979
|
let result = message;
|
|
@@ -37994,17 +37984,16 @@ function write(message, values) {
|
|
|
37994
37984
|
}
|
|
37995
37985
|
let new_message = line_list.join(`
|
|
37996
37986
|
`);
|
|
37997
|
-
new_message = safe_quote(new_message);
|
|
37998
37987
|
return new_message;
|
|
37999
37988
|
}
|
|
38000
37989
|
function read(message) {
|
|
38001
37990
|
const values = { id: null, title: null };
|
|
38002
|
-
const match_id = message.match(
|
|
37991
|
+
const match_id = message.match(RE2.stack_id);
|
|
38003
37992
|
if (match_id?.groups) {
|
|
38004
37993
|
values.id = match_id.groups["id"];
|
|
38005
37994
|
invariant(values.id, "id must exist");
|
|
38006
37995
|
}
|
|
38007
|
-
const match_title = message.match(
|
|
37996
|
+
const match_title = message.match(RE2.group_title);
|
|
38008
37997
|
if (match_title?.groups) {
|
|
38009
37998
|
values.title = match_title.groups["title"];
|
|
38010
37999
|
}
|
|
@@ -38012,8 +38001,8 @@ function read(message) {
|
|
|
38012
38001
|
}
|
|
38013
38002
|
function remove(message) {
|
|
38014
38003
|
let result = message;
|
|
38015
|
-
result = result.replace(new RegExp(
|
|
38016
|
-
result = result.replace(new RegExp(
|
|
38004
|
+
result = result.replace(new RegExp(RE2.stack_id, "gmi"), "");
|
|
38005
|
+
result = result.replace(new RegExp(RE2.group_title, "gmi"), "");
|
|
38017
38006
|
result = result.trimEnd();
|
|
38018
38007
|
return result;
|
|
38019
38008
|
}
|
|
@@ -38025,7 +38014,7 @@ var TEMPLATE = {
|
|
|
38025
38014
|
return `git-stack-title: ${title}`;
|
|
38026
38015
|
}
|
|
38027
38016
|
};
|
|
38028
|
-
var
|
|
38017
|
+
var RE2 = {
|
|
38029
38018
|
stack_id: new RegExp(`${TEMPLATE.stack_id("(?<id>[^\\s]+)")}`, "i"),
|
|
38030
38019
|
group_title: new RegExp(TEMPLATE.group_title("(?<title>[^\\n^\\r]+)"), "i")
|
|
38031
38020
|
};
|
|
@@ -38046,6 +38035,20 @@ async function get_tmp_dir() {
|
|
|
38046
38035
|
return dir;
|
|
38047
38036
|
}
|
|
38048
38037
|
|
|
38038
|
+
// src/core/safe_quote.ts
|
|
38039
|
+
function safe_quote(value) {
|
|
38040
|
+
let result = value;
|
|
38041
|
+
result = result.replace(RE3.all_backslash, "\\\\");
|
|
38042
|
+
result = result.replace(RE3.all_double_quote, "\\\"");
|
|
38043
|
+
result = result.replace(RE3.all_backtick, "\\`");
|
|
38044
|
+
return result;
|
|
38045
|
+
}
|
|
38046
|
+
var RE3 = {
|
|
38047
|
+
all_double_quote: /"/g,
|
|
38048
|
+
all_backtick: /`/g,
|
|
38049
|
+
all_backslash: /\\/g
|
|
38050
|
+
};
|
|
38051
|
+
|
|
38049
38052
|
// src/core/github.tsx
|
|
38050
38053
|
async function pr_list() {
|
|
38051
38054
|
const state = Store.getState();
|
|
@@ -38391,7 +38394,6 @@ GitReviseTodo.todo = function todo(args) {
|
|
|
38391
38394
|
const metadata = { id, title };
|
|
38392
38395
|
const unsafe_message_with_id = write(commit2.full_message, metadata);
|
|
38393
38396
|
let message_with_id = unsafe_message_with_id;
|
|
38394
|
-
message_with_id = message_with_id.replace(/[^\\]"/g, "\\\"");
|
|
38395
38397
|
const sha = commit2.sha.slice(0, 12);
|
|
38396
38398
|
const entry_lines = [`++ pick ${sha}`, message_with_id];
|
|
38397
38399
|
const entry = entry_lines.join(`
|
|
@@ -38404,7 +38406,6 @@ GitReviseTodo.todo = function todo(args) {
|
|
|
38404
38406
|
return todo2;
|
|
38405
38407
|
};
|
|
38406
38408
|
GitReviseTodo.execute = async function grt_execute(args) {
|
|
38407
|
-
const tmp_git_sequence_editor_path = path7.join(await get_tmp_dir(), "git-sequence-editor.sh");
|
|
38408
38409
|
const GIT_SEQUENCE_EDITOR_SCRIPT = `#!/bin/sh
|
|
38409
38410
|
|
|
38410
38411
|
# Example
|
|
@@ -38424,30 +38425,44 @@ echo "CLI=$0 $*"
|
|
|
38424
38425
|
echo "PWD=$(pwd)"
|
|
38425
38426
|
|
|
38426
38427
|
# ensure \\\`GIT_REVISE_TODO\\\` is not empty
|
|
38427
|
-
if [ -
|
|
38428
|
-
echo "\uD83D\uDEA8 GIT_REVISE_TODO
|
|
38428
|
+
if [ ! -f "$GIT_REVISE_TODO" ]; then
|
|
38429
|
+
echo "\uD83D\uDEA8 GIT_REVISE_TODO file must exist" >&2
|
|
38429
38430
|
exit 1
|
|
38430
38431
|
fi
|
|
38431
38432
|
|
|
38432
38433
|
# first argument into git sequence editor is git-revise-todo file
|
|
38433
38434
|
git_revise_todo_path="$1"
|
|
38434
38435
|
|
|
38435
|
-
#
|
|
38436
|
-
echo
|
|
38436
|
+
# print content of git-revise-todo file passed into command
|
|
38437
|
+
echo
|
|
38438
|
+
echo "BEFORE git_revise_todo_path=$git_revise_todo_path"
|
|
38437
38439
|
echo "----- START -----"
|
|
38438
38440
|
cat "$git_revise_todo_path"
|
|
38441
|
+
echo
|
|
38439
38442
|
echo "------ END ------"
|
|
38443
|
+
echo
|
|
38444
|
+
|
|
38445
|
+
# copy content of file at \\\`GIT_REVISE_TODO\\\` env variable to \\\`git_revise_todo_path\\\`
|
|
38446
|
+
cp "$GIT_REVISE_TODO" "$git_revise_todo_path"
|
|
38440
38447
|
|
|
38441
|
-
#
|
|
38442
|
-
echo
|
|
38448
|
+
# print content of git-revise-todo file after copy above
|
|
38449
|
+
echo
|
|
38450
|
+
echo "AFTER git_revise_todo_path=$git_revise_todo_path"
|
|
38451
|
+
echo "----- START -----"
|
|
38452
|
+
cat "$git_revise_todo_path"
|
|
38453
|
+
echo
|
|
38454
|
+
echo "------ END ------"
|
|
38455
|
+
echo
|
|
38443
38456
|
`;
|
|
38444
38457
|
invariant(GIT_SEQUENCE_EDITOR_SCRIPT, "GIT_SEQUENCE_EDITOR_SCRIPT must exist");
|
|
38458
|
+
const tmp_git_sequence_editor_path = path7.join(await get_tmp_dir(), "git-sequence-editor.sh");
|
|
38445
38459
|
await fs10.writeFile(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
|
|
38446
38460
|
await fs10.chmod(tmp_git_sequence_editor_path, "755");
|
|
38447
|
-
const
|
|
38461
|
+
const tmp_path_git_revise_todo = path7.join(await get_tmp_dir(), "git-revise-todo.txt");
|
|
38462
|
+
await fs10.writeFile(tmp_path_git_revise_todo, GitReviseTodo(args));
|
|
38448
38463
|
const command = [
|
|
38449
38464
|
`GIT_EDITOR="${tmp_git_sequence_editor_path}"`,
|
|
38450
|
-
`GIT_REVISE_TODO="${
|
|
38465
|
+
`GIT_REVISE_TODO="${tmp_path_git_revise_todo}"`,
|
|
38451
38466
|
`git`,
|
|
38452
38467
|
`revise --edit -i ${args.rebase_merge_base}`
|
|
38453
38468
|
];
|
|
@@ -40024,7 +40039,8 @@ function SelectCommitRangesInternal(props) {
|
|
|
40024
40039
|
let branch_prefix = "";
|
|
40025
40040
|
if (argv["branch-prefix"]) {
|
|
40026
40041
|
branch_prefix = argv["branch-prefix"];
|
|
40027
|
-
} else if (
|
|
40042
|
+
} else if (process.env.GIT_STACK_BRANCH_PREFIX) {
|
|
40043
|
+
branch_prefix = process.env.GIT_STACK_BRANCH_PREFIX;
|
|
40028
40044
|
}
|
|
40029
40045
|
return `${branch_prefix}${gs_short_id()}`;
|
|
40030
40046
|
}
|
|
@@ -45646,7 +45662,7 @@ var yargs_default = Yargs;
|
|
|
45646
45662
|
|
|
45647
45663
|
// src/command.ts
|
|
45648
45664
|
async function command2() {
|
|
45649
|
-
return yargs_default(hideBin(process.argv)).usage("Usage: git stack [command] [options]").command("$0", "Sync commit ranges to Github", (yargs) => yargs.options(DefaultOptions)).command("fixup [commit]", "Amend staged changes to a specific commit in history", (yargs) => yargs.positional("commit", FixupOptions.commit)).command("log [args...]", "Print an abbreviated log with numbered commits, useful for git stack fixup", (yargs) => yargs.strict(false)).command("rebase", "Update local branch via rebase with latest changes from origin master branch", (yargs) => yargs).option("verbose", GlobalOptions.verbose).wrap(123).strict().version("2.2.
|
|
45665
|
+
return yargs_default(hideBin(process.argv)).usage("Usage: git stack [command] [options]").command("$0", "Sync commit ranges to Github", (yargs) => yargs.options(DefaultOptions)).command("fixup [commit]", "Amend staged changes to a specific commit in history", (yargs) => yargs.positional("commit", FixupOptions.commit)).command("log [args...]", "Print an abbreviated log with numbered commits, useful for git stack fixup", (yargs) => yargs.strict(false)).command("rebase", "Update local branch via rebase with latest changes from origin master branch", (yargs) => yargs).option("verbose", GlobalOptions.verbose).wrap(123).strict().version("2.2.7").showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`").help("help", "Show usage via `git stack help`").argv;
|
|
45650
45666
|
}
|
|
45651
45667
|
var GlobalOptions = {
|
|
45652
45668
|
verbose: {
|
package/package.json
CHANGED
package/scripts/bun-build.ts
CHANGED
|
@@ -24,36 +24,43 @@ const parsed_args = util.parseArgs({
|
|
|
24
24
|
const WATCH = parsed_args.values.watch;
|
|
25
25
|
const VERBOSE = parsed_args.values.verbose;
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
function log(...args: any[]) {
|
|
28
|
+
const timestamp = new Date().toISOString();
|
|
29
|
+
console.debug(`[${timestamp}]`, ...args);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
log("📦 bundle", WATCH ? "watch" : "build");
|
|
28
33
|
|
|
29
34
|
if (VERBOSE) {
|
|
30
|
-
|
|
35
|
+
log(parsed_args);
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
const REPO_ROOT = (await spawn.sync("git rev-parse --show-toplevel")).stdout;
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
let GITIGNORE = (await file.read_text(path.join(REPO_ROOT, ".gitignore"))).split("\n");
|
|
41
|
-
GITIGNORE = GITIGNORE.filter((line) => line.trim() && !line.startsWith("#"));
|
|
42
|
-
GITIGNORE.push(".git");
|
|
40
|
+
async function get_define() {
|
|
41
|
+
const PACKAGE_JSON = await file.read_json(path.join(REPO_ROOT, "package.json"));
|
|
42
|
+
const GIT_SEQUENCE_EDITOR_SCRIPT_PATH = path.join(REPO_ROOT, "scripts", "git-sequence-editor.sh");
|
|
43
|
+
const UNSAFE_GIT_SEQUENCE_EDITOR_SCRIPT = await file.read_text(GIT_SEQUENCE_EDITOR_SCRIPT_PATH);
|
|
44
|
+
const GIT_SEQUENCE_EDITOR_SCRIPT = UNSAFE_GIT_SEQUENCE_EDITOR_SCRIPT.replace(/`/g, "\\`");
|
|
43
45
|
|
|
44
|
-
const define = {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
};
|
|
46
|
+
const define = {
|
|
47
|
+
"process.env.NODE_ENV": JSON.stringify("production"),
|
|
48
|
+
"process.env.CLI_VERSION": JSON.stringify(String(PACKAGE_JSON.version)),
|
|
49
|
+
"process.env.GIT_SEQUENCE_EDITOR_SCRIPT": JSON.stringify(GIT_SEQUENCE_EDITOR_SCRIPT),
|
|
50
|
+
};
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
console.debug({ define });
|
|
52
|
+
return define;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
async function run_build() {
|
|
55
56
|
const start = Date.now();
|
|
56
57
|
|
|
58
|
+
const define = await get_define();
|
|
59
|
+
|
|
60
|
+
if (VERBOSE) {
|
|
61
|
+
log({ define });
|
|
62
|
+
}
|
|
63
|
+
|
|
57
64
|
const result = await Bun.build({
|
|
58
65
|
entrypoints: ["./src/index.tsx"],
|
|
59
66
|
outdir: "./dist/js",
|
|
@@ -65,10 +72,10 @@ async function run_build() {
|
|
|
65
72
|
|
|
66
73
|
const duration_ms = Date.now() - start;
|
|
67
74
|
|
|
68
|
-
|
|
75
|
+
log(`✅ Build (${duration_ms}ms)`);
|
|
69
76
|
|
|
70
77
|
if (VERBOSE) {
|
|
71
|
-
|
|
78
|
+
log({ result });
|
|
72
79
|
}
|
|
73
80
|
}
|
|
74
81
|
|
|
@@ -77,11 +84,15 @@ if (!WATCH) {
|
|
|
77
84
|
} else {
|
|
78
85
|
await run_build();
|
|
79
86
|
|
|
80
|
-
|
|
87
|
+
let GITIGNORE = (await file.read_text(path.join(REPO_ROOT, ".gitignore"))).split("\n");
|
|
88
|
+
GITIGNORE = GITIGNORE.filter((line) => line.trim() && !line.startsWith("#"));
|
|
89
|
+
GITIGNORE.push(".git");
|
|
81
90
|
|
|
82
|
-
|
|
91
|
+
log("👀 Watching for changes…");
|
|
83
92
|
|
|
93
|
+
const { signal } = new AbortController();
|
|
84
94
|
const watcher = fs.watch(REPO_ROOT, { recursive: true, signal });
|
|
95
|
+
|
|
85
96
|
for await (const event of watcher) {
|
|
86
97
|
const filename = event.filename;
|
|
87
98
|
|
|
@@ -100,10 +111,10 @@ if (!WATCH) {
|
|
|
100
111
|
continue;
|
|
101
112
|
}
|
|
102
113
|
|
|
103
|
-
|
|
114
|
+
log(`⚠️ Change ${filename}`);
|
|
104
115
|
|
|
105
116
|
if (VERBOSE) {
|
|
106
|
-
|
|
117
|
+
log({ ignored, filename, event });
|
|
107
118
|
}
|
|
108
119
|
|
|
109
120
|
await run_build();
|
|
@@ -17,19 +17,31 @@ echo "CLI=$0 $*"
|
|
|
17
17
|
echo "PWD=$(pwd)"
|
|
18
18
|
|
|
19
19
|
# ensure `GIT_REVISE_TODO` is not empty
|
|
20
|
-
if [ -
|
|
21
|
-
echo "🚨 GIT_REVISE_TODO
|
|
20
|
+
if [ ! -f "$GIT_REVISE_TODO" ]; then
|
|
21
|
+
echo "🚨 GIT_REVISE_TODO file must exist" >&2
|
|
22
22
|
exit 1
|
|
23
23
|
fi
|
|
24
24
|
|
|
25
25
|
# first argument into git sequence editor is git-revise-todo file
|
|
26
26
|
git_revise_todo_path="$1"
|
|
27
27
|
|
|
28
|
-
#
|
|
29
|
-
echo
|
|
28
|
+
# print content of git-revise-todo file passed into command
|
|
29
|
+
echo
|
|
30
|
+
echo "BEFORE git_revise_todo_path=$git_revise_todo_path"
|
|
30
31
|
echo "----- START -----"
|
|
31
32
|
cat "$git_revise_todo_path"
|
|
33
|
+
echo
|
|
32
34
|
echo "------ END ------"
|
|
35
|
+
echo
|
|
33
36
|
|
|
34
|
-
#
|
|
35
|
-
|
|
37
|
+
# copy content of file at `GIT_REVISE_TODO` env variable to `git_revise_todo_path`
|
|
38
|
+
cp "$GIT_REVISE_TODO" "$git_revise_todo_path"
|
|
39
|
+
|
|
40
|
+
# print content of git-revise-todo file after copy above
|
|
41
|
+
echo
|
|
42
|
+
echo "AFTER git_revise_todo_path=$git_revise_todo_path"
|
|
43
|
+
echo "----- START -----"
|
|
44
|
+
cat "$git_revise_todo_path"
|
|
45
|
+
echo
|
|
46
|
+
echo "------ END ------"
|
|
47
|
+
echo
|
|
@@ -91,8 +91,6 @@ GitReviseTodo.todo = function todo(args: CommitListArgs) {
|
|
|
91
91
|
|
|
92
92
|
let message_with_id = unsafe_message_with_id;
|
|
93
93
|
|
|
94
|
-
message_with_id = message_with_id.replace(/[^\\]"/g, '\\"');
|
|
95
|
-
|
|
96
94
|
// get first 12 characters of commit sha
|
|
97
95
|
const sha = commit.sha.slice(0, 12);
|
|
98
96
|
|
|
@@ -108,27 +106,25 @@ GitReviseTodo.todo = function todo(args: CommitListArgs) {
|
|
|
108
106
|
};
|
|
109
107
|
|
|
110
108
|
GitReviseTodo.execute = async function grt_execute(args: ExecuteArgs) {
|
|
111
|
-
// generate temporary directory and drop sequence editor script
|
|
112
|
-
const tmp_git_sequence_editor_path = path.join(await get_tmp_dir(), "git-sequence-editor.sh");
|
|
113
|
-
|
|
114
109
|
// replaced at build time with literal contents of `scripts/git-sequence-editor.sh`
|
|
115
110
|
const GIT_SEQUENCE_EDITOR_SCRIPT = process.env.GIT_SEQUENCE_EDITOR_SCRIPT;
|
|
116
|
-
|
|
117
111
|
invariant(GIT_SEQUENCE_EDITOR_SCRIPT, "GIT_SEQUENCE_EDITOR_SCRIPT must exist");
|
|
118
112
|
|
|
119
|
-
//
|
|
113
|
+
// generate temporary directory and drop sequence editor script
|
|
114
|
+
// write script to temporary path and ensure script is executable
|
|
115
|
+
const tmp_git_sequence_editor_path = path.join(await get_tmp_dir(), "git-sequence-editor.sh");
|
|
120
116
|
await fs.writeFile(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
|
|
121
|
-
|
|
122
|
-
// ensure script is executable
|
|
123
117
|
await fs.chmod(tmp_git_sequence_editor_path, "755");
|
|
124
118
|
|
|
125
|
-
|
|
119
|
+
// write git revise todo to a temp path for use by sequence editor script
|
|
120
|
+
const tmp_path_git_revise_todo = path.join(await get_tmp_dir(), "git-revise-todo.txt");
|
|
121
|
+
await fs.writeFile(tmp_path_git_revise_todo, GitReviseTodo(args));
|
|
126
122
|
|
|
127
123
|
// execute cli with temporary git sequence editor script
|
|
128
124
|
// revise from merge base to pick correct commits
|
|
129
125
|
const command = [
|
|
130
126
|
`GIT_EDITOR="${tmp_git_sequence_editor_path}"`,
|
|
131
|
-
`GIT_REVISE_TODO="${
|
|
127
|
+
`GIT_REVISE_TODO="${tmp_path_git_revise_todo}"`,
|
|
132
128
|
`git`,
|
|
133
129
|
`revise --edit -i ${args.rebase_merge_base}`,
|
|
134
130
|
];
|
package/src/core/Metadata.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { invariant } from "~/core/invariant";
|
|
2
|
-
import { safe_quote } from "~/core/safe_quote";
|
|
3
2
|
|
|
4
3
|
type InputMetadataValues = {
|
|
5
4
|
id: string;
|
|
@@ -25,8 +24,6 @@ export function write(message: string, values: InputMetadataValues) {
|
|
|
25
24
|
|
|
26
25
|
let new_message = line_list.join("\n");
|
|
27
26
|
|
|
28
|
-
new_message = safe_quote(new_message);
|
|
29
|
-
|
|
30
27
|
return new_message;
|
|
31
28
|
}
|
|
32
29
|
|
package/src/core/safe_quote.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
// escape double-quote for cli
|
|
2
2
|
export function safe_quote(value: string) {
|
|
3
3
|
let result = value;
|
|
4
|
+
result = result.replace(RE.all_backslash, "\\\\");
|
|
4
5
|
result = result.replace(RE.all_double_quote, '\\"');
|
|
6
|
+
result = result.replace(RE.all_backtick, "\\`");
|
|
5
7
|
return result;
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
const RE = {
|
|
9
11
|
all_double_quote: /"/g,
|
|
12
|
+
all_backtick: /`/g,
|
|
13
|
+
all_backslash: /\\/g,
|
|
10
14
|
};
|