@harmoniclabs/monaco-editor 0.1.0-dev0

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.
@@ -0,0 +1,463 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+
6
+ import path = require('path');
7
+ import fs = require('fs');
8
+ import { REPO_ROOT, readFiles, writeFiles, IFile, readFile } from '../build/utils';
9
+ import { removeDir } from '../build/fs';
10
+ import ts = require('typescript');
11
+ import { generateMetadata } from './releaseMetadata';
12
+
13
+ removeDir(`out/monaco-editor`);
14
+
15
+ // dev folder
16
+ AMD_releaseOne('dev');
17
+
18
+ // min folder
19
+ AMD_releaseOne('min');
20
+
21
+ // esm folder
22
+ ESM_release();
23
+
24
+ // monaco.d.ts, editor.api.d.ts
25
+ releaseDTS();
26
+
27
+ // ThirdPartyNotices.txt
28
+ releaseThirdPartyNotices();
29
+
30
+ // esm/metadata.d.ts, esm/metadata.js
31
+ generateMetadata();
32
+
33
+ // package.json
34
+ (() => {
35
+ const packageJSON = readFiles('package.json', { base: '' })[0];
36
+ const json = JSON.parse(packageJSON.contents.toString());
37
+
38
+ json.private = false;
39
+ delete json.scripts['postinstall'];
40
+
41
+ packageJSON.contents = Buffer.from(JSON.stringify(json, null, ' '));
42
+ writeFiles([packageJSON], `out/monaco-editor`);
43
+ })();
44
+
45
+ (() => {
46
+ /** @type {IFile[]} */
47
+ let otherFiles = [];
48
+
49
+ otherFiles = otherFiles.concat(readFiles('README.md', { base: '' }));
50
+ otherFiles = otherFiles.concat(readFiles('CHANGELOG.md', { base: '' }));
51
+ otherFiles = otherFiles.concat(
52
+ readFiles('node_modules/monaco-editor-core/min-maps/**/*', {
53
+ base: 'node_modules/monaco-editor-core/'
54
+ })
55
+ );
56
+ otherFiles = otherFiles.concat(
57
+ readFiles('node_modules/monaco-editor-core/LICENSE', {
58
+ base: 'node_modules/monaco-editor-core/'
59
+ })
60
+ );
61
+
62
+ writeFiles(otherFiles, `out/monaco-editor`);
63
+ })();
64
+
65
+ /**
66
+ * Release to `dev` or `min`.
67
+ */
68
+ function AMD_releaseOne(type: 'dev' | 'min') {
69
+ let coreFiles = readFiles(`node_modules/monaco-editor-core/${type}/**/*`, {
70
+ base: `node_modules/monaco-editor-core/${type}`
71
+ });
72
+ coreFiles = fixNlsFiles(coreFiles);
73
+ AMD_addPluginContribs(type, coreFiles);
74
+ writeFiles(coreFiles, `out/monaco-editor/${type}`);
75
+
76
+ const pluginFiles = readFiles(`out/languages/bundled/amd-${type}/**/*`, {
77
+ base: `out/languages/bundled/amd-${type}`,
78
+ ignore: ['**/monaco.contribution.js']
79
+ });
80
+ writeFiles(pluginFiles, `out/monaco-editor/${type}`);
81
+ }
82
+
83
+ function fixNlsFiles(files: IFile[]): IFile[] {
84
+ return files.map((f) => {
85
+ if (!f.path.match(/nls\.messages\.[a-z\-]+\.js/)) {
86
+ return f;
87
+ }
88
+
89
+ const dirName = path.dirname(f.path);
90
+ const fileName = path.basename(f.path);
91
+
92
+ const newPath = path.join(dirName, 'vs', fileName);
93
+ let contentStr = f.contents.toString('utf-8');
94
+
95
+ contentStr = `
96
+ define([], function () {
97
+ ${contentStr}
98
+ });
99
+ `;
100
+
101
+ const newContents = Buffer.from(contentStr, 'utf-8');
102
+
103
+ return {
104
+ path: newPath,
105
+ contents: newContents
106
+ };
107
+ });
108
+ }
109
+
110
+ /**
111
+ * Edit editor.main.js:
112
+ * - rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
113
+ * - append monaco.contribution modules from plugins
114
+ * - append new AMD module 'vs/editor/editor.main' that stiches things together
115
+ */
116
+ function AMD_addPluginContribs(type: 'dev' | 'min', files: IFile[]) {
117
+ for (const file of files) {
118
+ if (!/editor\.main\.js$/.test(file.path)) {
119
+ continue;
120
+ }
121
+
122
+ let contents = file.contents.toString();
123
+
124
+ // Rename the AMD module 'vs/editor/editor.main' to 'vs/editor/edcore.main'
125
+ contents = contents.replace(/"vs\/editor\/editor\.main\"/, '"vs/editor/edcore.main"');
126
+
127
+ // This ensures that old nls-plugin configurations are still respected by the new localization solution.
128
+ const contentPrefixSource = readFile('src/nls-fix.js')
129
+ .contents.toString('utf-8')
130
+ .replace(/\r\n|\n/g, ' ');
131
+
132
+ // TODO: Instead of adding this source to the header to maintain the source map indices, it should rewrite the sourcemap!
133
+ const searchValue = 'https://github.com/microsoft/vscode/blob/main/LICENSE.txt';
134
+ contents = contents.replace(searchValue, searchValue + ' */ ' + contentPrefixSource + ' /*');
135
+
136
+ const pluginFiles = readFiles(`out/languages/bundled/amd-${type}/**/monaco.contribution.js`, {
137
+ base: `out/languages/bundled/amd-${type}`
138
+ });
139
+
140
+ const extraContent = pluginFiles.map((file) => {
141
+ return file.contents
142
+ .toString()
143
+ .replace(
144
+ /define\((['"][a-z\/\-]+\/fillers\/monaco-editor-core['"]),\[\],/,
145
+ "define($1,['vs/editor/editor.api'],"
146
+ );
147
+ });
148
+
149
+ const allPluginsModuleIds = pluginFiles.map((file) => {
150
+ return file.path.replace(/\.js$/, '');
151
+ });
152
+
153
+ extraContent.push(
154
+ `define("vs/editor/editor.main", ["vs/editor/edcore.main","${allPluginsModuleIds.join(
155
+ '","'
156
+ )}"], function(api) { return api; });`
157
+ );
158
+ let insertIndex = contents.lastIndexOf('//# sourceMappingURL=');
159
+ if (insertIndex === -1) {
160
+ insertIndex = contents.length;
161
+ }
162
+ contents =
163
+ contents.substring(0, insertIndex) +
164
+ '\n' +
165
+ extraContent.join('\n') +
166
+ '\n' +
167
+ contents.substring(insertIndex);
168
+
169
+ file.contents = Buffer.from(contents);
170
+ }
171
+ }
172
+
173
+ function ESM_release() {
174
+ const coreFiles = readFiles(`node_modules/monaco-editor-core/esm/**/*`, {
175
+ base: 'node_modules/monaco-editor-core/esm',
176
+ // we will create our own editor.api.d.ts which also contains the plugins API
177
+ ignore: ['node_modules/monaco-editor-core/esm/vs/editor/editor.api.d.ts']
178
+ });
179
+ ESM_addImportSuffix(coreFiles);
180
+ ESM_addPluginContribs(coreFiles);
181
+ writeFiles(coreFiles, `out/monaco-editor/esm`);
182
+
183
+ ESM_releasePlugins();
184
+ }
185
+
186
+ /**
187
+ * Release a plugin to `esm`.
188
+ * Adds a dependency to 'vs/editor/editor.api' in contrib files in order for `monaco` to be defined.
189
+ * Rewrites imports for 'monaco-editor-core/**'
190
+ */
191
+ function ESM_releasePlugins() {
192
+ const files = readFiles(`out/languages/bundled/esm/**/*`, { base: 'out/languages/bundled/esm/' });
193
+
194
+ for (const file of files) {
195
+ if (!/(\.js$)|(\.ts$)/.test(file.path)) {
196
+ continue;
197
+ }
198
+
199
+ let contents = file.contents.toString();
200
+
201
+ const info = ts.preProcessFile(contents);
202
+ for (let i = info.importedFiles.length - 1; i >= 0; i--) {
203
+ let importText = info.importedFiles[i].fileName;
204
+ const pos = info.importedFiles[i].pos;
205
+ const end = info.importedFiles[i].end;
206
+
207
+ if (!/(^\.\/)|(^\.\.\/)/.test(importText)) {
208
+ // non-relative import
209
+ if (!/^monaco-editor-core/.test(importText)) {
210
+ console.error(`Non-relative import for unknown module: ${importText} in ${file.path}`);
211
+ process.exit(1);
212
+ }
213
+
214
+ if (importText === 'monaco-editor-core') {
215
+ importText = 'monaco-editor-core/esm/vs/editor/editor.api';
216
+ }
217
+
218
+ const importFilePath = importText.substring('monaco-editor-core/esm/'.length);
219
+ let relativePath = path
220
+ .relative(path.dirname(file.path), importFilePath)
221
+ .replace(/\\/g, '/');
222
+ if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
223
+ relativePath = './' + relativePath;
224
+ }
225
+
226
+ contents = contents.substring(0, pos + 1) + relativePath + contents.substring(end + 1);
227
+ }
228
+ }
229
+
230
+ file.contents = Buffer.from(contents);
231
+ }
232
+
233
+ for (const file of files) {
234
+ if (!/monaco\.contribution\.js$/.test(file.path)) {
235
+ continue;
236
+ }
237
+
238
+ const apiFilePath = 'vs/editor/editor.api';
239
+ let relativePath = path.relative(path.dirname(file.path), apiFilePath).replace(/\\/g, '/');
240
+ if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
241
+ relativePath = './' + relativePath;
242
+ }
243
+
244
+ let contents = file.contents.toString();
245
+ contents = `import '${relativePath}';\n` + contents;
246
+ file.contents = Buffer.from(contents);
247
+ }
248
+
249
+ ESM_addImportSuffix(files);
250
+ writeFiles(files, `out/monaco-editor/esm`);
251
+ }
252
+
253
+ /**
254
+ * Adds `.js` to all import statements.
255
+ */
256
+ function ESM_addImportSuffix(files: IFile[]) {
257
+ for (const file of files) {
258
+ if (!/\.js$/.test(file.path)) {
259
+ continue;
260
+ }
261
+
262
+ let contents = file.contents.toString();
263
+
264
+ const info = ts.preProcessFile(contents);
265
+ for (let i = info.importedFiles.length - 1; i >= 0; i--) {
266
+ const importText = info.importedFiles[i].fileName;
267
+ const pos = info.importedFiles[i].pos;
268
+ const end = info.importedFiles[i].end;
269
+
270
+ if (/(\.css)|(\.js)$/.test(importText)) {
271
+ // A CSS import or an import already using .js
272
+ continue;
273
+ }
274
+
275
+ contents = contents.substring(0, pos + 1) + importText + '.js' + contents.substring(end + 1);
276
+ }
277
+
278
+ file.contents = Buffer.from(contents);
279
+ }
280
+ }
281
+
282
+ /**
283
+ * - Rename esm/vs/editor/editor.main.js to esm/vs/editor/edcore.main.js
284
+ * - Create esm/vs/editor/editor.main.js that that stiches things together
285
+ */
286
+ function ESM_addPluginContribs(files: IFile[]) {
287
+ for (const file of files) {
288
+ if (!/editor\.main\.js$/.test(file.path)) {
289
+ continue;
290
+ }
291
+ file.path = file.path.replace(/editor\.main/, 'edcore.main');
292
+ }
293
+
294
+ const mainFileDestPath = 'vs/editor/editor.main.js';
295
+
296
+ const mainFileImports = readFiles(`out/languages/bundled/esm/**/monaco.contribution.js`, {
297
+ base: `out/languages/bundled/esm`
298
+ }).map((file) => {
299
+ let relativePath = path
300
+ .relative(path.dirname(mainFileDestPath), file.path)
301
+ .replace(/\\/g, '/')
302
+ .replace(/\.js$/, '');
303
+
304
+ if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) {
305
+ relativePath = './' + relativePath;
306
+ }
307
+
308
+ return relativePath;
309
+ });
310
+
311
+ const mainFileContents =
312
+ mainFileImports.map((name) => `import '${name}';`).join('\n') +
313
+ `\n\nexport * from './edcore.main';`;
314
+
315
+ files.push({
316
+ path: mainFileDestPath,
317
+ contents: Buffer.from(mainFileContents)
318
+ });
319
+ }
320
+
321
+ /**
322
+ * Edit monaco.d.ts:
323
+ * - append monaco.d.ts from plugins
324
+ */
325
+ function releaseDTS() {
326
+ const monacodts = readFiles('node_modules/monaco-editor-core/monaco.d.ts', {
327
+ base: 'node_modules/monaco-editor-core'
328
+ })[0];
329
+
330
+ let contents = monacodts.contents.toString();
331
+
332
+ const extraContent = readFiles('out/languages/bundled/*.d.ts', {
333
+ base: 'out/languages/bundled/'
334
+ }).map((file) => {
335
+ return file.contents.toString().replace(/\/\/\/ <reference.*\n/m, '');
336
+ });
337
+
338
+ contents =
339
+ [
340
+ '/*!-----------------------------------------------------------',
341
+ ' * Copyright (c) Microsoft Corporation. All rights reserved.',
342
+ ' * Type definitions for monaco-editor',
343
+ ' * Released under the MIT license',
344
+ '*-----------------------------------------------------------*/'
345
+ ].join('\n') +
346
+ '\n' +
347
+ contents +
348
+ '\n' +
349
+ extraContent.join('\n');
350
+
351
+ // Ensure consistent indentation and line endings
352
+ contents = cleanFile(contents);
353
+
354
+ monacodts.contents = Buffer.from(contents);
355
+
356
+ const editorapidts = {
357
+ path: 'esm/vs/editor/editor.api.d.ts',
358
+ contents: Buffer.from(toExternalDTS(contents))
359
+ };
360
+
361
+ writeFiles([monacodts, editorapidts], `out/monaco-editor`);
362
+
363
+ // fs.writeFileSync('website/typedoc/monaco.d.ts', contents);
364
+ }
365
+
366
+ /**
367
+ * Transforms a .d.ts which uses internal modules (namespaces) to one which is usable with external modules
368
+ * This function is duplicated in the `vscode` repo.
369
+ */
370
+ function toExternalDTS(contents: string): string {
371
+ let lines = contents.split(/\r\n|\r|\n/);
372
+ let killNextCloseCurlyBrace = false;
373
+ for (let i = 0; i < lines.length; i++) {
374
+ let line = lines[i];
375
+
376
+ if (killNextCloseCurlyBrace) {
377
+ if ('}' === line) {
378
+ lines[i] = '';
379
+ killNextCloseCurlyBrace = false;
380
+ continue;
381
+ }
382
+
383
+ if (line.indexOf(' ') === 0) {
384
+ lines[i] = line.substr(4);
385
+ } else if (line.charAt(0) === '\t') {
386
+ lines[i] = line.substr(1);
387
+ }
388
+
389
+ continue;
390
+ }
391
+
392
+ if ('declare namespace monaco {' === line) {
393
+ lines[i] = '';
394
+ killNextCloseCurlyBrace = true;
395
+ continue;
396
+ }
397
+
398
+ if (line.indexOf('declare namespace monaco.') === 0) {
399
+ lines[i] = line.replace('declare namespace monaco.', 'export namespace ');
400
+ }
401
+
402
+ if (line.indexOf('declare let MonacoEnvironment') === 0) {
403
+ lines[i] = [
404
+ 'declare global {',
405
+ ' let MonacoEnvironment: Environment | undefined;',
406
+ '',
407
+ ' interface Window {',
408
+ ' MonacoEnvironment?: Environment | undefined;',
409
+ ' }',
410
+ '}',
411
+ ''
412
+ ].join('\n');
413
+ }
414
+ if (line.indexOf(' MonacoEnvironment?') === 0) {
415
+ lines[i] = ` MonacoEnvironment?: Environment | undefined;`;
416
+ }
417
+ }
418
+ return lines.join('\n').replace(/\n\n\n+/g, '\n\n');
419
+ }
420
+
421
+ /**
422
+ * Normalize line endings and ensure consistent 4 spaces indentation
423
+ */
424
+ function cleanFile(contents: string): string {
425
+ return contents
426
+ .split(/\r\n|\r|\n/)
427
+ .map(function (line) {
428
+ const m = line.match(/^(\t+)/);
429
+ if (!m) {
430
+ return line;
431
+ }
432
+ const tabsCount = m[1].length;
433
+ let newIndent = '';
434
+ for (let i = 0; i < 4 * tabsCount; i++) {
435
+ newIndent += ' ';
436
+ }
437
+ return newIndent + line.substring(tabsCount);
438
+ })
439
+ .join('\n');
440
+ }
441
+
442
+ /**
443
+ * Edit ThirdPartyNotices.txt:
444
+ * - append ThirdPartyNotices.txt from plugins
445
+ */
446
+ function releaseThirdPartyNotices() {
447
+ const tpn = readFiles('node_modules/monaco-editor-core/ThirdPartyNotices.txt', {
448
+ base: 'node_modules/monaco-editor-core'
449
+ })[0];
450
+
451
+ let contents = tpn.contents.toString();
452
+
453
+ console.log('ADDING ThirdPartyNotices from ./ThirdPartyNotices.txt');
454
+ let thirdPartyNoticeContent = fs
455
+ .readFileSync(path.join(REPO_ROOT, 'ThirdPartyNotices.txt'))
456
+ .toString();
457
+ thirdPartyNoticeContent = thirdPartyNoticeContent.split('\n').slice(8).join('\n');
458
+
459
+ contents += '\n' + thirdPartyNoticeContent;
460
+ tpn.contents = Buffer.from(contents);
461
+
462
+ writeFiles([tpn], `out/monaco-editor`);
463
+ }
@@ -0,0 +1,53 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+
6
+ import * as fs from 'fs';
7
+ import * as glob from 'glob';
8
+ import * as path from 'path';
9
+ import { REPO_ROOT } from './utils';
10
+
11
+ checkEveryMonacoLanguageHasASample();
12
+
13
+ function checkEveryMonacoLanguageHasASample() {
14
+ let languages = glob
15
+ .sync('src/basic-languages/*/*.contribution.ts', { cwd: REPO_ROOT })
16
+ .map((f) => path.dirname(f))
17
+ .map((f) => f.substring('src/basic-languages/'.length));
18
+ languages.push('css');
19
+ languages.push('html');
20
+ languages.push('json');
21
+ languages.push('typescript');
22
+
23
+ // some languages have a different id than their folder
24
+ languages = languages.map((l) => {
25
+ switch (l) {
26
+ case 'coffee':
27
+ return 'coffeescript';
28
+ case 'protobuf':
29
+ return 'proto';
30
+ case 'solidity':
31
+ return 'sol';
32
+ case 'sophia':
33
+ return 'aes';
34
+ default:
35
+ return l;
36
+ }
37
+ });
38
+
39
+ let fail = false;
40
+ for (const language of languages) {
41
+ const expectedSamplePath = path.join(
42
+ REPO_ROOT,
43
+ `website/src/website/data/home-samples/sample.${language}.txt`
44
+ );
45
+ if (!fs.existsSync(expectedSamplePath)) {
46
+ console.error(`Missing sample for ${language} at ${expectedSamplePath}`);
47
+ fail = true;
48
+ }
49
+ }
50
+ if (fail) {
51
+ process.exit(1);
52
+ }
53
+ }
@@ -0,0 +1,46 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+
6
+ export interface Options {
7
+ locale?: string;
8
+ cacheLanguageResolution?: boolean;
9
+ }
10
+ export interface LocalizeInfo {
11
+ key: string;
12
+ comment: string[];
13
+ }
14
+ export interface LocalizeFunc {
15
+ (info: LocalizeInfo, message: string, ...args: any[]): string;
16
+ (key: string, message: string, ...args: any[]): string;
17
+ }
18
+ export interface LoadFunc {
19
+ (file?: string): LocalizeFunc;
20
+ }
21
+
22
+ function format(message: string, args: any[]): string {
23
+ let result: string;
24
+
25
+ if (args.length === 0) {
26
+ result = message;
27
+ } else {
28
+ result = message.replace(/\{(\d+)\}/g, (match, rest) => {
29
+ let index = rest[0];
30
+ return typeof args[index] !== 'undefined' ? args[index] : match;
31
+ });
32
+ }
33
+ return result;
34
+ }
35
+
36
+ function localize(key: string | LocalizeInfo, message: string, ...args: any[]): string {
37
+ return format(message, args);
38
+ }
39
+
40
+ export function loadMessageBundle(file?: string): LocalizeFunc {
41
+ return localize;
42
+ }
43
+
44
+ export function config(opt?: Options | string): LoadFunc {
45
+ return loadMessageBundle;
46
+ }
package/build/fs.ts ADDED
@@ -0,0 +1,80 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+
6
+ import * as fs from 'fs';
7
+ import * as path from 'path';
8
+
9
+ const REPO_ROOT = path.join(__dirname, '../');
10
+
11
+ const existingDirCache = new Set();
12
+
13
+ export function ensureDir(dirname: string) {
14
+ /** @type {string[]} */
15
+ const dirs = [];
16
+
17
+ while (dirname.length > REPO_ROOT.length) {
18
+ dirs.push(dirname);
19
+ dirname = path.dirname(dirname);
20
+ }
21
+ dirs.reverse();
22
+ dirs.forEach((dir) => {
23
+ if (!existingDirCache.has(dir)) {
24
+ try {
25
+ fs.mkdirSync(dir);
26
+ } catch (err) {}
27
+ existingDirCache.add(dir);
28
+ }
29
+ });
30
+ }
31
+
32
+ /**
33
+ * Copy a file.
34
+ */
35
+ export function copyFile(_source: string, _destination: string) {
36
+ const source = path.join(REPO_ROOT, _source);
37
+ const destination = path.join(REPO_ROOT, _destination);
38
+
39
+ ensureDir(path.dirname(destination));
40
+ fs.writeFileSync(destination, fs.readFileSync(source));
41
+
42
+ console.log(`Copied ${_source} to ${_destination}`);
43
+ }
44
+
45
+ /**
46
+ * Remove a directory and all its contents.
47
+ */
48
+ export function removeDir(_dirPath: string, keep?: (filename: string) => boolean) {
49
+ if (typeof keep === 'undefined') {
50
+ keep = () => false;
51
+ }
52
+ const dirPath = path.join(REPO_ROOT, _dirPath);
53
+ if (!fs.existsSync(dirPath)) {
54
+ return;
55
+ }
56
+ rmDir(dirPath, _dirPath);
57
+ console.log(`Deleted ${_dirPath}`);
58
+
59
+ function rmDir(dirPath: string, relativeDirPath: string): boolean {
60
+ let keepsFiles = false;
61
+ const entries = fs.readdirSync(dirPath);
62
+ for (const entry of entries) {
63
+ const filePath = path.join(dirPath, entry);
64
+ const relativeFilePath = path.join(relativeDirPath, entry);
65
+ if (keep!(relativeFilePath)) {
66
+ keepsFiles = true;
67
+ continue;
68
+ }
69
+ if (fs.statSync(filePath).isFile()) {
70
+ fs.unlinkSync(filePath);
71
+ } else {
72
+ keepsFiles = rmDir(filePath, relativeFilePath) || keepsFiles;
73
+ }
74
+ }
75
+ if (!keepsFiles) {
76
+ fs.rmdirSync(dirPath);
77
+ }
78
+ return keepsFiles;
79
+ }
80
+ }