@neurodevs/meta-node 0.11.0 → 0.12.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/build/__tests__/modules/VscodeSnippetKeybinder.test.d.ts +28 -2
- package/build/__tests__/modules/VscodeSnippetKeybinder.test.js +142 -36
- package/build/__tests__/modules/VscodeSnippetKeybinder.test.js.map +1 -1
- package/build/modules/VscodeSnippetKeybinder.d.ts +26 -3
- package/build/modules/VscodeSnippetKeybinder.js +69 -3
- package/build/modules/VscodeSnippetKeybinder.js.map +1 -1
- package/build/scripts/runSnippetKeybinder.d.ts +1 -0
- package/build/scripts/runSnippetKeybinder.js +21 -0
- package/build/scripts/runSnippetKeybinder.js.map +1 -0
- package/build/testDoubles/SnippetKeybinder/FakeSnippetKeybinder.d.ts +5 -3
- package/build/testDoubles/SnippetKeybinder/FakeSnippetKeybinder.js +8 -4
- package/build/testDoubles/SnippetKeybinder/FakeSnippetKeybinder.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/modules/VscodeSnippetKeybinder.test.ts +183 -3
- package/src/modules/VscodeSnippetKeybinder.ts +107 -5
- package/src/scripts/runSnippetKeybinder.ts +19 -0
- package/src/testDoubles/SnippetKeybinder/FakeSnippetKeybinder.ts +14 -5
|
@@ -1,7 +1,33 @@
|
|
|
1
|
-
import
|
|
2
|
-
export default class VscodeSnippetKeybinderTest extends
|
|
1
|
+
import AbstractPackageTest from '../AbstractPackageTest';
|
|
2
|
+
export default class VscodeSnippetKeybinderTest extends AbstractPackageTest {
|
|
3
3
|
private static instance;
|
|
4
4
|
protected static beforeEach(): Promise<void>;
|
|
5
5
|
protected static createsInstance(): Promise<void>;
|
|
6
|
+
protected static updatesGlobalSnippetsInVscode(): Promise<void>;
|
|
7
|
+
protected static updatesGlobalKeybindingsInVscode(): Promise<void>;
|
|
8
|
+
protected static updateSnippetsUsesJsoncParserToAllowComments(): Promise<void>;
|
|
9
|
+
protected static updateKeybindingsUsesJsoncParserToAllowComments(): Promise<void>;
|
|
10
|
+
private static run;
|
|
11
|
+
private static toCommandId;
|
|
12
|
+
private static setFakeReadFile;
|
|
13
|
+
private static setFakeWriteFile;
|
|
14
|
+
private static setFakeSnippetsFile;
|
|
15
|
+
private static setFakeKeybindingsFile;
|
|
16
|
+
private static readonly fakeName;
|
|
17
|
+
private static readonly fakePrefix;
|
|
18
|
+
private static readonly fakeLines;
|
|
19
|
+
private static readonly fakeKeybinding;
|
|
20
|
+
private static readonly fakeDescription;
|
|
21
|
+
private static readonly vscodeDir;
|
|
22
|
+
private static get snippetsPath();
|
|
23
|
+
private static readonly originalSnippet;
|
|
24
|
+
private static readonly originalSnippetsFile;
|
|
25
|
+
private static get updatedSnippetsFile();
|
|
26
|
+
private static readonly originalSnippetsFileCommented;
|
|
27
|
+
private static get keybindingsPath();
|
|
28
|
+
private static readonly originalKeybinding;
|
|
29
|
+
private static readonly originalKeybindingsFile;
|
|
30
|
+
private static readonly updatedKeybindingsFile;
|
|
31
|
+
private static readonly originalKeybindingsFileCommented;
|
|
6
32
|
private static VscodeSnippetKeybinder;
|
|
7
33
|
}
|
|
@@ -1,63 +1,169 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
2
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
3
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
4
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
5
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
6
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
7
|
};
|
|
24
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
-
var ownKeys = function(o) {
|
|
26
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
-
var ar = [];
|
|
28
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
-
return ar;
|
|
30
|
-
};
|
|
31
|
-
return ownKeys(o);
|
|
32
|
-
};
|
|
33
|
-
return function (mod) {
|
|
34
|
-
if (mod && mod.__esModule) return mod;
|
|
35
|
-
var result = {};
|
|
36
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
-
__setModuleDefault(result, mod);
|
|
38
|
-
return result;
|
|
39
|
-
};
|
|
40
|
-
})();
|
|
41
8
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
42
9
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
43
10
|
};
|
|
11
|
+
var _a;
|
|
44
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
-
const test_utils_1 =
|
|
13
|
+
const test_utils_1 = require("@sprucelabs/test-utils");
|
|
14
|
+
const fake_node_core_1 = require("@neurodevs/fake-node-core");
|
|
46
15
|
const VscodeSnippetKeybinder_1 = __importDefault(require("../../modules/VscodeSnippetKeybinder"));
|
|
47
|
-
|
|
16
|
+
const expandHomeDir_1 = __importDefault(require("../../scripts/expandHomeDir"));
|
|
17
|
+
const AbstractPackageTest_1 = __importDefault(require("../AbstractPackageTest"));
|
|
18
|
+
class VscodeSnippetKeybinderTest extends AbstractPackageTest_1.default {
|
|
48
19
|
static async beforeEach() {
|
|
49
20
|
await super.beforeEach();
|
|
21
|
+
this.setFakeReadFile();
|
|
22
|
+
this.setFakeWriteFile();
|
|
23
|
+
this.setFakeSnippetsFile();
|
|
24
|
+
this.setFakeKeybindingsFile();
|
|
50
25
|
this.instance = this.VscodeSnippetKeybinder();
|
|
51
26
|
}
|
|
52
27
|
static async createsInstance() {
|
|
53
28
|
test_utils_1.assert.isTruthy(this.instance, 'Failed to create instance!');
|
|
54
29
|
}
|
|
30
|
+
static async updatesGlobalSnippetsInVscode() {
|
|
31
|
+
await this.run();
|
|
32
|
+
test_utils_1.assert.isEqualDeep(fake_node_core_1.callsToWriteFile[0], {
|
|
33
|
+
file: this.snippetsPath,
|
|
34
|
+
data: JSON.stringify(this.updatedSnippetsFile, null, 4),
|
|
35
|
+
options: undefined,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
static async updatesGlobalKeybindingsInVscode() {
|
|
39
|
+
await this.run();
|
|
40
|
+
test_utils_1.assert.isEqualDeep(fake_node_core_1.callsToWriteFile[1], {
|
|
41
|
+
file: this.keybindingsPath,
|
|
42
|
+
data: JSON.stringify(this.updatedKeybindingsFile, null, 4),
|
|
43
|
+
options: undefined,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
static async updateSnippetsUsesJsoncParserToAllowComments() {
|
|
47
|
+
(0, fake_node_core_1.setFakeReadFileResult)(this.snippetsPath, this.originalSnippetsFileCommented);
|
|
48
|
+
await this.run();
|
|
49
|
+
test_utils_1.assert.isEqualDeep(fake_node_core_1.callsToWriteFile[0], {
|
|
50
|
+
file: this.snippetsPath,
|
|
51
|
+
data: JSON.stringify(this.updatedSnippetsFile, null, 4),
|
|
52
|
+
options: undefined,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
static async updateKeybindingsUsesJsoncParserToAllowComments() {
|
|
56
|
+
(0, fake_node_core_1.setFakeReadFileResult)(this.keybindingsPath, this.originalKeybindingsFileCommented);
|
|
57
|
+
await this.run();
|
|
58
|
+
test_utils_1.assert.isEqualDeep(fake_node_core_1.callsToWriteFile[1], {
|
|
59
|
+
file: this.keybindingsPath,
|
|
60
|
+
data: JSON.stringify(this.updatedKeybindingsFile, null, 4),
|
|
61
|
+
options: undefined,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
static async run() {
|
|
65
|
+
await this.instance.run();
|
|
66
|
+
}
|
|
67
|
+
static toCommandId(name) {
|
|
68
|
+
return name
|
|
69
|
+
.trim()
|
|
70
|
+
.toLowerCase()
|
|
71
|
+
.replace(/[-_\s]+/g, '.')
|
|
72
|
+
.replace(/[^a-z0-9.]/g, '')
|
|
73
|
+
.replace(/\.+/g, '.')
|
|
74
|
+
.replace(/^\.+|\.+$/g, '');
|
|
75
|
+
}
|
|
76
|
+
static setFakeReadFile() {
|
|
77
|
+
VscodeSnippetKeybinder_1.default.readFile =
|
|
78
|
+
fake_node_core_1.fakeReadFile;
|
|
79
|
+
(0, fake_node_core_1.resetCallsToReadFile)();
|
|
80
|
+
}
|
|
81
|
+
static setFakeWriteFile() {
|
|
82
|
+
VscodeSnippetKeybinder_1.default.writeFile =
|
|
83
|
+
fake_node_core_1.fakeWriteFile;
|
|
84
|
+
(0, fake_node_core_1.resetCallsToWriteFile)();
|
|
85
|
+
}
|
|
86
|
+
static setFakeSnippetsFile() {
|
|
87
|
+
(0, fake_node_core_1.setFakeReadFileResult)(this.snippetsPath, JSON.stringify(this.originalSnippetsFile, null, 4));
|
|
88
|
+
}
|
|
89
|
+
static setFakeKeybindingsFile() {
|
|
90
|
+
(0, fake_node_core_1.setFakeReadFileResult)(this.keybindingsPath, JSON.stringify(this.originalKeybindingsFile, null, 4));
|
|
91
|
+
}
|
|
92
|
+
static get snippetsPath() {
|
|
93
|
+
return `${this.vscodeDir}/snippets/custom.code-snippets`;
|
|
94
|
+
}
|
|
95
|
+
static get updatedSnippetsFile() {
|
|
96
|
+
return {
|
|
97
|
+
...this.originalSnippet,
|
|
98
|
+
[this.fakeName]: {
|
|
99
|
+
scope: 'javascript,typescript',
|
|
100
|
+
prefix: this.fakePrefix,
|
|
101
|
+
body: JSON.stringify(this.fakeLines),
|
|
102
|
+
description: this.fakeDescription,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
static get keybindingsPath() {
|
|
107
|
+
return `${this.vscodeDir}/keybindings.json`;
|
|
108
|
+
}
|
|
55
109
|
static VscodeSnippetKeybinder() {
|
|
56
|
-
return VscodeSnippetKeybinder_1.default.Create(
|
|
110
|
+
return VscodeSnippetKeybinder_1.default.Create({
|
|
111
|
+
name: this.fakeName,
|
|
112
|
+
description: this.fakeDescription,
|
|
113
|
+
lines: this.fakeLines,
|
|
114
|
+
keybinding: this.fakeKeybinding,
|
|
115
|
+
});
|
|
57
116
|
}
|
|
58
117
|
}
|
|
118
|
+
_a = VscodeSnippetKeybinderTest;
|
|
119
|
+
VscodeSnippetKeybinderTest.fakeName = `${(0, test_utils_1.generateId)()}-${(0, test_utils_1.generateId)()}_${(0, test_utils_1.generateId)()} ${(0, test_utils_1.generateId)()}`;
|
|
120
|
+
VscodeSnippetKeybinderTest.fakePrefix = _a.toCommandId(_a.fakeName);
|
|
121
|
+
VscodeSnippetKeybinderTest.fakeLines = [(0, test_utils_1.generateId)(), (0, test_utils_1.generateId)()];
|
|
122
|
+
VscodeSnippetKeybinderTest.fakeKeybinding = (0, test_utils_1.generateId)();
|
|
123
|
+
VscodeSnippetKeybinderTest.fakeDescription = (0, test_utils_1.generateId)();
|
|
124
|
+
VscodeSnippetKeybinderTest.vscodeDir = (0, expandHomeDir_1.default)('~/Library/Application Support/Code/User');
|
|
125
|
+
VscodeSnippetKeybinderTest.originalSnippet = { [(0, test_utils_1.generateId)()]: {} };
|
|
126
|
+
VscodeSnippetKeybinderTest.originalSnippetsFile = {
|
|
127
|
+
..._a.originalSnippet,
|
|
128
|
+
};
|
|
129
|
+
VscodeSnippetKeybinderTest.originalSnippetsFileCommented = `
|
|
130
|
+
// ${(0, test_utils_1.generateId)()}
|
|
131
|
+
${JSON.stringify(_a.originalSnippetsFile, null, 4)}
|
|
132
|
+
`;
|
|
133
|
+
VscodeSnippetKeybinderTest.originalKeybinding = {
|
|
134
|
+
key: (0, test_utils_1.generateId)(),
|
|
135
|
+
command: (0, test_utils_1.generateId)(),
|
|
136
|
+
};
|
|
137
|
+
VscodeSnippetKeybinderTest.originalKeybindingsFile = [_a.originalKeybinding];
|
|
138
|
+
VscodeSnippetKeybinderTest.updatedKeybindingsFile = [
|
|
139
|
+
_a.originalKeybinding,
|
|
140
|
+
{
|
|
141
|
+
key: _a.fakeKeybinding,
|
|
142
|
+
command: 'editor.action.insertSnippet',
|
|
143
|
+
when: 'editorTextFocus',
|
|
144
|
+
args: {
|
|
145
|
+
name: _a.fakeName,
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
];
|
|
149
|
+
VscodeSnippetKeybinderTest.originalKeybindingsFileCommented = `
|
|
150
|
+
// ${(0, test_utils_1.generateId)()}
|
|
151
|
+
${JSON.stringify(_a.originalKeybindingsFile, null, 4)}
|
|
152
|
+
`;
|
|
59
153
|
exports.default = VscodeSnippetKeybinderTest;
|
|
60
154
|
__decorate([
|
|
61
155
|
(0, test_utils_1.test)()
|
|
62
156
|
], VscodeSnippetKeybinderTest, "createsInstance", null);
|
|
157
|
+
__decorate([
|
|
158
|
+
(0, test_utils_1.test)()
|
|
159
|
+
], VscodeSnippetKeybinderTest, "updatesGlobalSnippetsInVscode", null);
|
|
160
|
+
__decorate([
|
|
161
|
+
(0, test_utils_1.test)()
|
|
162
|
+
], VscodeSnippetKeybinderTest, "updatesGlobalKeybindingsInVscode", null);
|
|
163
|
+
__decorate([
|
|
164
|
+
(0, test_utils_1.test)()
|
|
165
|
+
], VscodeSnippetKeybinderTest, "updateSnippetsUsesJsoncParserToAllowComments", null);
|
|
166
|
+
__decorate([
|
|
167
|
+
(0, test_utils_1.test)()
|
|
168
|
+
], VscodeSnippetKeybinderTest, "updateKeybindingsUsesJsoncParserToAllowComments", null);
|
|
63
169
|
//# sourceMappingURL=VscodeSnippetKeybinder.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VscodeSnippetKeybinder.test.js","sourceRoot":"","sources":["../../../src/__tests__/modules/VscodeSnippetKeybinder.test.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VscodeSnippetKeybinder.test.js","sourceRoot":"","sources":["../../../src/__tests__/modules/VscodeSnippetKeybinder.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,31 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
1
2
|
export default class VscodeSnippetKeybinder implements SnippetKeybinder {
|
|
2
3
|
static Class?: SnippetKeybinderConstructor;
|
|
3
|
-
|
|
4
|
-
static
|
|
4
|
+
static readFile: typeof readFile;
|
|
5
|
+
static writeFile: typeof writeFile;
|
|
6
|
+
private name;
|
|
7
|
+
private description;
|
|
8
|
+
private lines;
|
|
9
|
+
private keybinding;
|
|
10
|
+
protected constructor(options: SnippetKeybinderOptions);
|
|
11
|
+
static Create(options: SnippetKeybinderOptions): SnippetKeybinder;
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
private updateGlobalSnippets;
|
|
14
|
+
private readonly vscodeDir;
|
|
15
|
+
private readonly snippetsPath;
|
|
16
|
+
private toCommandId;
|
|
17
|
+
private updateGlobalKeybindings;
|
|
18
|
+
private readonly keybindingsPath;
|
|
19
|
+
private get readFile();
|
|
20
|
+
private get writeFile();
|
|
5
21
|
}
|
|
6
22
|
export interface SnippetKeybinder {
|
|
23
|
+
run(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export type SnippetKeybinderConstructor = new (options: SnippetKeybinderOptions) => SnippetKeybinder;
|
|
26
|
+
export interface SnippetKeybinderOptions {
|
|
27
|
+
name: string;
|
|
28
|
+
description: string;
|
|
29
|
+
lines: string[];
|
|
30
|
+
keybinding: string;
|
|
7
31
|
}
|
|
8
|
-
export type SnippetKeybinderConstructor = new () => SnippetKeybinder;
|
|
@@ -1,10 +1,76 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const promises_1 = require("fs/promises");
|
|
7
|
+
const jsonc_parser_1 = require("jsonc-parser");
|
|
8
|
+
const expandHomeDir_1 = __importDefault(require("../scripts/expandHomeDir"));
|
|
3
9
|
class VscodeSnippetKeybinder {
|
|
4
|
-
constructor() {
|
|
5
|
-
|
|
6
|
-
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.vscodeDir = (0, expandHomeDir_1.default)('~/Library/Application Support/Code/User');
|
|
12
|
+
this.snippetsPath = `${this.vscodeDir}/snippets/custom.code-snippets`;
|
|
13
|
+
this.keybindingsPath = `${this.vscodeDir}/keybindings.json`;
|
|
14
|
+
const { name, description, lines, keybinding } = options;
|
|
15
|
+
this.name = name;
|
|
16
|
+
this.description = description;
|
|
17
|
+
this.lines = lines;
|
|
18
|
+
this.keybinding = keybinding;
|
|
19
|
+
}
|
|
20
|
+
static Create(options) {
|
|
21
|
+
return new (this.Class ?? this)(options);
|
|
22
|
+
}
|
|
23
|
+
async run() {
|
|
24
|
+
await this.updateGlobalSnippets();
|
|
25
|
+
await this.updateGlobalKeybindings();
|
|
26
|
+
}
|
|
27
|
+
async updateGlobalSnippets() {
|
|
28
|
+
const raw = await this.readFile(this.snippetsPath, 'utf-8');
|
|
29
|
+
const snippets = (0, jsonc_parser_1.parse)(raw);
|
|
30
|
+
const updated = {
|
|
31
|
+
...snippets,
|
|
32
|
+
[this.name]: {
|
|
33
|
+
scope: 'javascript,typescript',
|
|
34
|
+
prefix: this.toCommandId(this.name),
|
|
35
|
+
body: JSON.stringify(this.lines),
|
|
36
|
+
description: this.description,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
await this.writeFile(this.snippetsPath, JSON.stringify(updated, null, 4));
|
|
40
|
+
}
|
|
41
|
+
toCommandId(name) {
|
|
42
|
+
return name
|
|
43
|
+
.trim()
|
|
44
|
+
.toLowerCase()
|
|
45
|
+
.replace(/[-_\s]+/g, '.')
|
|
46
|
+
.replace(/[^a-z0-9.]/g, '')
|
|
47
|
+
.replace(/\.+/g, '.')
|
|
48
|
+
.replace(/^\.+|\.+$/g, '');
|
|
49
|
+
}
|
|
50
|
+
async updateGlobalKeybindings() {
|
|
51
|
+
const raw = await this.readFile(this.keybindingsPath, 'utf-8');
|
|
52
|
+
const keybindings = (0, jsonc_parser_1.parse)(raw);
|
|
53
|
+
const updated = [
|
|
54
|
+
...keybindings,
|
|
55
|
+
{
|
|
56
|
+
key: this.keybinding,
|
|
57
|
+
command: `editor.action.insertSnippet`,
|
|
58
|
+
when: 'editorTextFocus',
|
|
59
|
+
args: {
|
|
60
|
+
name: this.name,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
await this.writeFile(this.keybindingsPath, JSON.stringify(updated, null, 4));
|
|
65
|
+
}
|
|
66
|
+
get readFile() {
|
|
67
|
+
return VscodeSnippetKeybinder.readFile;
|
|
68
|
+
}
|
|
69
|
+
get writeFile() {
|
|
70
|
+
return VscodeSnippetKeybinder.writeFile;
|
|
7
71
|
}
|
|
8
72
|
}
|
|
73
|
+
VscodeSnippetKeybinder.readFile = promises_1.readFile;
|
|
74
|
+
VscodeSnippetKeybinder.writeFile = promises_1.writeFile;
|
|
9
75
|
exports.default = VscodeSnippetKeybinder;
|
|
10
76
|
//# sourceMappingURL=VscodeSnippetKeybinder.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VscodeSnippetKeybinder.js","sourceRoot":"","sources":["../../src/modules/VscodeSnippetKeybinder.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VscodeSnippetKeybinder.js","sourceRoot":"","sources":["../../src/modules/VscodeSnippetKeybinder.ts"],"names":[],"mappings":";;;;;AAAA,0CAAiD;AACjD,+CAAoC;AACpC,6EAAoD;AAEpD,MAAqB,sBAAsB;IAUvC,YAAsB,OAAgC;QAsCrC,cAAS,GAAG,IAAA,uBAAa,EACtC,yCAAyC,CAC5C,CAAA;QAEgB,iBAAY,GAAG,GAAG,IAAI,CAAC,SAAS,gCAAgC,CAAA;QAkChE,oBAAe,GAAG,GAAG,IAAI,CAAC,SAAS,mBAAmB,CAAA;QA3EnE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,OAAO,CAAA;QAExD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;QAC9B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IAChC,CAAC;IAEM,MAAM,CAAC,MAAM,CAAC,OAAgC;QACjD,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,CAAA;IAC5C,CAAC;IAEM,KAAK,CAAC,GAAG;QACZ,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAA;QACjC,MAAM,IAAI,CAAC,uBAAuB,EAAE,CAAA;IACxC,CAAC;IAEO,KAAK,CAAC,oBAAoB;QAC9B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;QAC3D,MAAM,QAAQ,GAAG,IAAA,oBAAK,EAAC,GAAG,CAAC,CAAA;QAE3B,MAAM,OAAO,GAAG;YACZ,GAAG,QAAQ;YACX,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACT,KAAK,EAAE,uBAAuB;gBAC9B,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;gBACnC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;gBAChC,WAAW,EAAE,IAAI,CAAC,WAAW;aAChC;SACJ,CAAA;QAED,MAAM,IAAI,CAAC,SAAS,CAChB,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CACnC,CAAA;IACL,CAAC;IAQO,WAAW,CAAC,IAAY;QAC5B,OAAO,IAAI;aACN,IAAI,EAAE;aACN,WAAW,EAAE;aACb,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;aACxB,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;aAC1B,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;aACpB,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAA;IAClC,CAAC;IAEO,KAAK,CAAC,uBAAuB;QACjC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;QAC9D,MAAM,WAAW,GAAG,IAAA,oBAAK,EAAC,GAAG,CAAC,CAAA;QAE9B,MAAM,OAAO,GAAG;YACZ,GAAG,WAAW;YACd;gBACI,GAAG,EAAE,IAAI,CAAC,UAAU;gBACpB,OAAO,EAAE,6BAA6B;gBACtC,IAAI,EAAE,iBAAiB;gBACvB,IAAI,EAAE;oBACF,IAAI,EAAE,IAAI,CAAC,IAAI;iBAClB;aACJ;SACJ,CAAA;QAED,MAAM,IAAI,CAAC,SAAS,CAChB,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CACnC,CAAA;IACL,CAAC;IAID,IAAY,QAAQ;QAChB,OAAO,sBAAsB,CAAC,QAAQ,CAAA;IAC1C,CAAC;IAED,IAAY,SAAS;QACjB,OAAO,sBAAsB,CAAC,SAAS,CAAA;IAC3C,CAAC;;AA5Fa,+BAAQ,GAAG,mBAAQ,AAAX,CAAW;AACnB,gCAAS,GAAG,oBAAS,AAAZ,CAAY;kBAHlB,sBAAsB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const VscodeSnippetKeybinder_1 = __importDefault(require("../modules/VscodeSnippetKeybinder"));
|
|
7
|
+
async function main() {
|
|
8
|
+
console.log('Running VscodeSnippetKeybinder...');
|
|
9
|
+
const instance = VscodeSnippetKeybinder_1.default.Create({
|
|
10
|
+
name: 'Test the thingy',
|
|
11
|
+
description: 'Test the thingy! Do it!',
|
|
12
|
+
lines: ['@test()', 'protected static async exampleTest() {}'],
|
|
13
|
+
keybinding: 'f5',
|
|
14
|
+
});
|
|
15
|
+
await instance.run();
|
|
16
|
+
}
|
|
17
|
+
main().catch((err) => {
|
|
18
|
+
console.error(err);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=runSnippetKeybinder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runSnippetKeybinder.js","sourceRoot":"","sources":["../../src/scripts/runSnippetKeybinder.ts"],"names":[],"mappings":";;;;;AAAA,+FAAsE;AAEtE,KAAK,UAAU,IAAI;IACf,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAA;IAEhD,MAAM,QAAQ,GAAG,gCAAsB,CAAC,MAAM,CAAC;QAC3C,IAAI,EAAE,iBAAiB;QACvB,WAAW,EAAE,yBAAyB;QACtC,KAAK,EAAE,CAAC,SAAS,EAAE,yCAAyC,CAAC;QAC7D,UAAU,EAAE,IAAI;KACnB,CAAC,CAAA;IAEF,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAA;AACxB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACnB,CAAC,CAAC,CAAA"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { SnippetKeybinder } from '../../modules/VscodeSnippetKeybinder';
|
|
1
|
+
import { SnippetKeybinder, SnippetKeybinderOptions } from '../../modules/VscodeSnippetKeybinder';
|
|
2
2
|
export default class FakeSnippetKeybinder implements SnippetKeybinder {
|
|
3
|
-
static
|
|
4
|
-
|
|
3
|
+
static callsToConstructor: SnippetKeybinderOptions[];
|
|
4
|
+
static numCallsToRun: number;
|
|
5
|
+
constructor(options: SnippetKeybinderOptions);
|
|
6
|
+
run(): Promise<void>;
|
|
5
7
|
static resetTestDouble(): void;
|
|
6
8
|
}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
class FakeSnippetKeybinder {
|
|
4
|
-
constructor() {
|
|
5
|
-
FakeSnippetKeybinder.
|
|
4
|
+
constructor(options) {
|
|
5
|
+
FakeSnippetKeybinder.callsToConstructor.push(options);
|
|
6
|
+
}
|
|
7
|
+
async run() {
|
|
8
|
+
FakeSnippetKeybinder.numCallsToRun++;
|
|
6
9
|
}
|
|
7
10
|
static resetTestDouble() {
|
|
8
|
-
FakeSnippetKeybinder.
|
|
11
|
+
FakeSnippetKeybinder.callsToConstructor = [];
|
|
12
|
+
FakeSnippetKeybinder.numCallsToRun = 0;
|
|
9
13
|
}
|
|
10
14
|
}
|
|
11
|
-
FakeSnippetKeybinder.
|
|
15
|
+
FakeSnippetKeybinder.numCallsToRun = 0;
|
|
12
16
|
exports.default = FakeSnippetKeybinder;
|
|
13
17
|
//# sourceMappingURL=FakeSnippetKeybinder.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FakeSnippetKeybinder.js","sourceRoot":"","sources":["../../../src/testDoubles/SnippetKeybinder/FakeSnippetKeybinder.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"FakeSnippetKeybinder.js","sourceRoot":"","sources":["../../../src/testDoubles/SnippetKeybinder/FakeSnippetKeybinder.ts"],"names":[],"mappings":";;AAKA,MAAqB,oBAAoB;IAIrC,YAAmB,OAAgC;QAC/C,oBAAoB,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACzD,CAAC;IAEM,KAAK,CAAC,GAAG;QACZ,oBAAoB,CAAC,aAAa,EAAE,CAAA;IACxC,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,oBAAoB,CAAC,kBAAkB,GAAG,EAAE,CAAA;QAC5C,oBAAoB,CAAC,aAAa,GAAG,CAAC,CAAA;IAC1C,CAAC;;AAba,kCAAa,GAAG,CAAC,CAAA;kBAFd,oBAAoB"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { readFile, writeFile } from 'fs/promises'
|
|
2
|
+
import { test, assert, generateId } from '@sprucelabs/test-utils'
|
|
3
|
+
import {
|
|
4
|
+
callsToWriteFile,
|
|
5
|
+
fakeReadFile,
|
|
6
|
+
fakeWriteFile,
|
|
7
|
+
resetCallsToReadFile,
|
|
8
|
+
resetCallsToWriteFile,
|
|
9
|
+
setFakeReadFileResult,
|
|
10
|
+
} from '@neurodevs/fake-node-core'
|
|
2
11
|
import VscodeSnippetKeybinder, {
|
|
3
12
|
SnippetKeybinder,
|
|
4
13
|
} from '../../modules/VscodeSnippetKeybinder'
|
|
14
|
+
import expandHomeDir from '../../scripts/expandHomeDir'
|
|
15
|
+
import AbstractPackageTest from '../AbstractPackageTest'
|
|
5
16
|
|
|
6
|
-
export default class VscodeSnippetKeybinderTest extends
|
|
17
|
+
export default class VscodeSnippetKeybinderTest extends AbstractPackageTest {
|
|
7
18
|
private static instance: SnippetKeybinder
|
|
8
19
|
|
|
9
20
|
protected static async beforeEach() {
|
|
10
21
|
await super.beforeEach()
|
|
11
22
|
|
|
23
|
+
this.setFakeReadFile()
|
|
24
|
+
this.setFakeWriteFile()
|
|
25
|
+
this.setFakeSnippetsFile()
|
|
26
|
+
this.setFakeKeybindingsFile()
|
|
27
|
+
|
|
12
28
|
this.instance = this.VscodeSnippetKeybinder()
|
|
13
29
|
}
|
|
14
30
|
|
|
@@ -17,7 +33,171 @@ export default class VscodeSnippetKeybinderTest extends AbstractSpruceTest {
|
|
|
17
33
|
assert.isTruthy(this.instance, 'Failed to create instance!')
|
|
18
34
|
}
|
|
19
35
|
|
|
36
|
+
@test()
|
|
37
|
+
protected static async updatesGlobalSnippetsInVscode() {
|
|
38
|
+
await this.run()
|
|
39
|
+
|
|
40
|
+
assert.isEqualDeep(callsToWriteFile[0], {
|
|
41
|
+
file: this.snippetsPath,
|
|
42
|
+
data: JSON.stringify(this.updatedSnippetsFile, null, 4),
|
|
43
|
+
options: undefined,
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@test()
|
|
48
|
+
protected static async updatesGlobalKeybindingsInVscode() {
|
|
49
|
+
await this.run()
|
|
50
|
+
|
|
51
|
+
assert.isEqualDeep(callsToWriteFile[1], {
|
|
52
|
+
file: this.keybindingsPath,
|
|
53
|
+
data: JSON.stringify(this.updatedKeybindingsFile, null, 4),
|
|
54
|
+
options: undefined,
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@test()
|
|
59
|
+
protected static async updateSnippetsUsesJsoncParserToAllowComments() {
|
|
60
|
+
setFakeReadFileResult(
|
|
61
|
+
this.snippetsPath,
|
|
62
|
+
this.originalSnippetsFileCommented
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
await this.run()
|
|
66
|
+
|
|
67
|
+
assert.isEqualDeep(callsToWriteFile[0], {
|
|
68
|
+
file: this.snippetsPath,
|
|
69
|
+
data: JSON.stringify(this.updatedSnippetsFile, null, 4),
|
|
70
|
+
options: undefined,
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@test()
|
|
75
|
+
protected static async updateKeybindingsUsesJsoncParserToAllowComments() {
|
|
76
|
+
setFakeReadFileResult(
|
|
77
|
+
this.keybindingsPath,
|
|
78
|
+
this.originalKeybindingsFileCommented
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
await this.run()
|
|
82
|
+
|
|
83
|
+
assert.isEqualDeep(callsToWriteFile[1], {
|
|
84
|
+
file: this.keybindingsPath,
|
|
85
|
+
data: JSON.stringify(this.updatedKeybindingsFile, null, 4),
|
|
86
|
+
options: undefined,
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private static async run() {
|
|
91
|
+
await this.instance.run()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private static toCommandId(name: string) {
|
|
95
|
+
return name
|
|
96
|
+
.trim()
|
|
97
|
+
.toLowerCase()
|
|
98
|
+
.replace(/[-_\s]+/g, '.')
|
|
99
|
+
.replace(/[^a-z0-9.]/g, '')
|
|
100
|
+
.replace(/\.+/g, '.')
|
|
101
|
+
.replace(/^\.+|\.+$/g, '')
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private static setFakeReadFile() {
|
|
105
|
+
VscodeSnippetKeybinder.readFile =
|
|
106
|
+
fakeReadFile as unknown as typeof readFile
|
|
107
|
+
resetCallsToReadFile()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private static setFakeWriteFile() {
|
|
111
|
+
VscodeSnippetKeybinder.writeFile =
|
|
112
|
+
fakeWriteFile as unknown as typeof writeFile
|
|
113
|
+
resetCallsToWriteFile()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private static setFakeSnippetsFile() {
|
|
117
|
+
setFakeReadFileResult(
|
|
118
|
+
this.snippetsPath,
|
|
119
|
+
JSON.stringify(this.originalSnippetsFile, null, 4)
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private static setFakeKeybindingsFile() {
|
|
124
|
+
setFakeReadFileResult(
|
|
125
|
+
this.keybindingsPath,
|
|
126
|
+
JSON.stringify(this.originalKeybindingsFile, null, 4)
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private static readonly fakeName = `${generateId()}-${generateId()}_${generateId()} ${generateId()}`
|
|
131
|
+
private static readonly fakePrefix = this.toCommandId(this.fakeName)
|
|
132
|
+
private static readonly fakeLines = [generateId(), generateId()]
|
|
133
|
+
private static readonly fakeKeybinding = generateId()
|
|
134
|
+
private static readonly fakeDescription = generateId()
|
|
135
|
+
|
|
136
|
+
private static readonly vscodeDir = expandHomeDir(
|
|
137
|
+
'~/Library/Application Support/Code/User'
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
private static get snippetsPath() {
|
|
141
|
+
return `${this.vscodeDir}/snippets/custom.code-snippets`
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private static readonly originalSnippet = { [generateId()]: {} }
|
|
145
|
+
|
|
146
|
+
private static readonly originalSnippetsFile = {
|
|
147
|
+
...this.originalSnippet,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private static get updatedSnippetsFile() {
|
|
151
|
+
return {
|
|
152
|
+
...this.originalSnippet,
|
|
153
|
+
[this.fakeName]: {
|
|
154
|
+
scope: 'javascript,typescript',
|
|
155
|
+
prefix: this.fakePrefix,
|
|
156
|
+
body: JSON.stringify(this.fakeLines),
|
|
157
|
+
description: this.fakeDescription,
|
|
158
|
+
},
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private static readonly originalSnippetsFileCommented = `
|
|
163
|
+
// ${generateId()}
|
|
164
|
+
${JSON.stringify(this.originalSnippetsFile, null, 4)}
|
|
165
|
+
`
|
|
166
|
+
|
|
167
|
+
private static get keybindingsPath() {
|
|
168
|
+
return `${this.vscodeDir}/keybindings.json`
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private static readonly originalKeybinding = {
|
|
172
|
+
key: generateId(),
|
|
173
|
+
command: generateId(),
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private static readonly originalKeybindingsFile = [this.originalKeybinding]
|
|
177
|
+
|
|
178
|
+
private static readonly updatedKeybindingsFile = [
|
|
179
|
+
this.originalKeybinding,
|
|
180
|
+
{
|
|
181
|
+
key: this.fakeKeybinding,
|
|
182
|
+
command: 'editor.action.insertSnippet',
|
|
183
|
+
when: 'editorTextFocus',
|
|
184
|
+
args: {
|
|
185
|
+
name: this.fakeName,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
private static readonly originalKeybindingsFileCommented = `
|
|
191
|
+
// ${generateId()}
|
|
192
|
+
${JSON.stringify(this.originalKeybindingsFile, null, 4)}
|
|
193
|
+
`
|
|
194
|
+
|
|
20
195
|
private static VscodeSnippetKeybinder() {
|
|
21
|
-
return VscodeSnippetKeybinder.Create(
|
|
196
|
+
return VscodeSnippetKeybinder.Create({
|
|
197
|
+
name: this.fakeName,
|
|
198
|
+
description: this.fakeDescription,
|
|
199
|
+
lines: this.fakeLines,
|
|
200
|
+
keybinding: this.fakeKeybinding,
|
|
201
|
+
})
|
|
22
202
|
}
|
|
23
203
|
}
|
|
@@ -1,13 +1,115 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'fs/promises'
|
|
2
|
+
import { parse } from 'jsonc-parser'
|
|
3
|
+
import expandHomeDir from '../scripts/expandHomeDir'
|
|
4
|
+
|
|
1
5
|
export default class VscodeSnippetKeybinder implements SnippetKeybinder {
|
|
2
6
|
public static Class?: SnippetKeybinderConstructor
|
|
7
|
+
public static readFile = readFile
|
|
8
|
+
public static writeFile = writeFile
|
|
9
|
+
|
|
10
|
+
private name: string
|
|
11
|
+
private description: string
|
|
12
|
+
private lines: string[]
|
|
13
|
+
private keybinding: string
|
|
14
|
+
|
|
15
|
+
protected constructor(options: SnippetKeybinderOptions) {
|
|
16
|
+
const { name, description, lines, keybinding } = options
|
|
17
|
+
|
|
18
|
+
this.name = name
|
|
19
|
+
this.description = description
|
|
20
|
+
this.lines = lines
|
|
21
|
+
this.keybinding = keybinding
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public static Create(options: SnippetKeybinderOptions) {
|
|
25
|
+
return new (this.Class ?? this)(options)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public async run() {
|
|
29
|
+
await this.updateGlobalSnippets()
|
|
30
|
+
await this.updateGlobalKeybindings()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private async updateGlobalSnippets() {
|
|
34
|
+
const raw = await this.readFile(this.snippetsPath, 'utf-8')
|
|
35
|
+
const snippets = parse(raw)
|
|
36
|
+
|
|
37
|
+
const updated = {
|
|
38
|
+
...snippets,
|
|
39
|
+
[this.name]: {
|
|
40
|
+
scope: 'javascript,typescript',
|
|
41
|
+
prefix: this.toCommandId(this.name),
|
|
42
|
+
body: JSON.stringify(this.lines),
|
|
43
|
+
description: this.description,
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await this.writeFile(
|
|
48
|
+
this.snippetsPath,
|
|
49
|
+
JSON.stringify(updated, null, 4)
|
|
50
|
+
)
|
|
51
|
+
}
|
|
3
52
|
|
|
4
|
-
|
|
53
|
+
private readonly vscodeDir = expandHomeDir(
|
|
54
|
+
'~/Library/Application Support/Code/User'
|
|
55
|
+
)
|
|
5
56
|
|
|
6
|
-
|
|
7
|
-
|
|
57
|
+
private readonly snippetsPath = `${this.vscodeDir}/snippets/custom.code-snippets`
|
|
58
|
+
|
|
59
|
+
private toCommandId(name: string) {
|
|
60
|
+
return name
|
|
61
|
+
.trim()
|
|
62
|
+
.toLowerCase()
|
|
63
|
+
.replace(/[-_\s]+/g, '.')
|
|
64
|
+
.replace(/[^a-z0-9.]/g, '')
|
|
65
|
+
.replace(/\.+/g, '.')
|
|
66
|
+
.replace(/^\.+|\.+$/g, '')
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private async updateGlobalKeybindings() {
|
|
70
|
+
const raw = await this.readFile(this.keybindingsPath, 'utf-8')
|
|
71
|
+
const keybindings = parse(raw)
|
|
72
|
+
|
|
73
|
+
const updated = [
|
|
74
|
+
...keybindings,
|
|
75
|
+
{
|
|
76
|
+
key: this.keybinding,
|
|
77
|
+
command: `editor.action.insertSnippet`,
|
|
78
|
+
when: 'editorTextFocus',
|
|
79
|
+
args: {
|
|
80
|
+
name: this.name,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
await this.writeFile(
|
|
86
|
+
this.keybindingsPath,
|
|
87
|
+
JSON.stringify(updated, null, 4)
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private readonly keybindingsPath = `${this.vscodeDir}/keybindings.json`
|
|
92
|
+
|
|
93
|
+
private get readFile() {
|
|
94
|
+
return VscodeSnippetKeybinder.readFile
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private get writeFile() {
|
|
98
|
+
return VscodeSnippetKeybinder.writeFile
|
|
8
99
|
}
|
|
9
100
|
}
|
|
10
101
|
|
|
11
|
-
export interface SnippetKeybinder {
|
|
102
|
+
export interface SnippetKeybinder {
|
|
103
|
+
run(): Promise<void>
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export type SnippetKeybinderConstructor = new (
|
|
107
|
+
options: SnippetKeybinderOptions
|
|
108
|
+
) => SnippetKeybinder
|
|
12
109
|
|
|
13
|
-
export
|
|
110
|
+
export interface SnippetKeybinderOptions {
|
|
111
|
+
name: string
|
|
112
|
+
description: string
|
|
113
|
+
lines: string[]
|
|
114
|
+
keybinding: string
|
|
115
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import VscodeSnippetKeybinder from '../modules/VscodeSnippetKeybinder'
|
|
2
|
+
|
|
3
|
+
async function main() {
|
|
4
|
+
console.log('Running VscodeSnippetKeybinder...')
|
|
5
|
+
|
|
6
|
+
const instance = VscodeSnippetKeybinder.Create({
|
|
7
|
+
name: 'Test the thingy',
|
|
8
|
+
description: 'Test the thingy! Do it!',
|
|
9
|
+
lines: ['@test()', 'protected static async exampleTest() {}'],
|
|
10
|
+
keybinding: 'f5',
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
await instance.run()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
main().catch((err) => {
|
|
17
|
+
console.error(err)
|
|
18
|
+
process.exit(1)
|
|
19
|
+
})
|
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
SnippetKeybinder,
|
|
3
|
+
SnippetKeybinderOptions,
|
|
4
|
+
} from '../../modules/VscodeSnippetKeybinder'
|
|
2
5
|
|
|
3
6
|
export default class FakeSnippetKeybinder implements SnippetKeybinder {
|
|
4
|
-
public static
|
|
7
|
+
public static callsToConstructor: SnippetKeybinderOptions[]
|
|
8
|
+
public static numCallsToRun = 0
|
|
5
9
|
|
|
6
|
-
public constructor() {
|
|
7
|
-
FakeSnippetKeybinder.
|
|
10
|
+
public constructor(options: SnippetKeybinderOptions) {
|
|
11
|
+
FakeSnippetKeybinder.callsToConstructor.push(options)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public async run() {
|
|
15
|
+
FakeSnippetKeybinder.numCallsToRun++
|
|
8
16
|
}
|
|
9
17
|
|
|
10
18
|
public static resetTestDouble() {
|
|
11
|
-
FakeSnippetKeybinder.
|
|
19
|
+
FakeSnippetKeybinder.callsToConstructor = []
|
|
20
|
+
FakeSnippetKeybinder.numCallsToRun = 0
|
|
12
21
|
}
|
|
13
22
|
}
|