@neurodevs/meta-node 0.11.0 → 0.12.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,7 +1,33 @@
1
- import AbstractSpruceTest from '@sprucelabs/test-utils';
2
- export default class VscodeSnippetKeybinderTest extends AbstractSpruceTest {
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 = __importStar(require("@sprucelabs/test-utils"));
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
- class VscodeSnippetKeybinderTest extends test_utils_1.default {
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: 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qEAAyE;AACzE,kGAE6C;AAE7C,MAAqB,0BAA2B,SAAQ,oBAAkB;IAG5D,MAAM,CAAC,KAAK,CAAC,UAAU;QAC7B,MAAM,KAAK,CAAC,UAAU,EAAE,CAAA;QAExB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAA;IACjD,CAAC;IAGsB,AAAb,MAAM,CAAC,KAAK,CAAC,eAAe;QAClC,mBAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,4BAA4B,CAAC,CAAA;IAChE,CAAC;IAEO,MAAM,CAAC,sBAAsB;QACjC,OAAO,gCAAsB,CAAC,MAAM,EAAE,CAAA;IAC1C,CAAC;CACJ;AAjBD,6CAiBC;AAP0B;IADtB,IAAA,iBAAI,GAAE;uDAGN"}
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
- protected constructor();
4
- static Create(): VscodeSnippetKeybinder;
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
- static Create() {
6
- return new (this.Class ?? this)();
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: 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":";;AAAA,MAAqB,sBAAsB;IAGvC,gBAAyB,CAAC;IAEnB,MAAM,CAAC,MAAM;QAChB,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,EAAE,CAAA;IACrC,CAAC;CACJ;AARD,yCAQC"}
1
+ {"version":3,"file":"VscodeSnippetKeybinder.js","sourceRoot":"","sources":["../../src/modules/VscodeSnippetKeybinder.ts"],"names":[],"mappings":"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"}
@@ -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 numCallsToConstructor: number;
4
- constructor();
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.numCallsToConstructor++;
4
+ constructor(options) {
5
+ FakeSnippetKeybinder.callsToConstructor.push(options);
6
+ }
7
+ async run() {
8
+ FakeSnippetKeybinder.numCallsToRun++;
6
9
  }
7
10
  static resetTestDouble() {
8
- FakeSnippetKeybinder.numCallsToConstructor = 0;
11
+ FakeSnippetKeybinder.callsToConstructor = [];
12
+ FakeSnippetKeybinder.numCallsToRun = 0;
9
13
  }
10
14
  }
11
- FakeSnippetKeybinder.numCallsToConstructor = 0;
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":";;AAEA,MAAqB,oBAAoB;IAGrC;QACI,oBAAoB,CAAC,qBAAqB,EAAE,CAAA;IAChD,CAAC;IAEM,MAAM,CAAC,eAAe;QACzB,oBAAoB,CAAC,qBAAqB,GAAG,CAAC,CAAA;IAClD,CAAC;;AARa,0CAAqB,GAAG,CAAC,CAAA;kBADtB,oBAAoB"}
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@neurodevs/meta-node",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Meta-layer utilities for maintaining Node.js package ecosystems.",
5
5
  "keywords": [
6
6
  "nodejs",
@@ -1,14 +1,30 @@
1
- import AbstractSpruceTest, { test, assert } from '@sprucelabs/test-utils'
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 AbstractSpruceTest {
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: 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: 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
- protected constructor() {}
53
+ private readonly vscodeDir = expandHomeDir(
54
+ '~/Library/Application Support/Code/User'
55
+ )
5
56
 
6
- public static Create() {
7
- return new (this.Class ?? this)()
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 type SnippetKeybinderConstructor = new () => SnippetKeybinder
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 { SnippetKeybinder } from '../../modules/VscodeSnippetKeybinder'
1
+ import {
2
+ SnippetKeybinder,
3
+ SnippetKeybinderOptions,
4
+ } from '../../modules/VscodeSnippetKeybinder'
2
5
 
3
6
  export default class FakeSnippetKeybinder implements SnippetKeybinder {
4
- public static numCallsToConstructor = 0
7
+ public static callsToConstructor: SnippetKeybinderOptions[]
8
+ public static numCallsToRun = 0
5
9
 
6
- public constructor() {
7
- FakeSnippetKeybinder.numCallsToConstructor++
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.numCallsToConstructor = 0
19
+ FakeSnippetKeybinder.callsToConstructor = []
20
+ FakeSnippetKeybinder.numCallsToRun = 0
12
21
  }
13
22
  }