datagrok-tools 6.1.9 → 6.1.11

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,277 @@
1
+ "use strict";
2
+
3
+ var _vitest = require("vitest");
4
+ var os = _interopRequireWildcard(require("os"));
5
+ var fs = _interopRequireWildcard(require("fs"));
6
+ var path = _interopRequireWildcard(require("path"));
7
+ var _server = require("../commands/server");
8
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
9
+ (0, _vitest.describe)('parseFuncCall', () => {
10
+ (0, _vitest.it)('parses a single string argument', () => {
11
+ (0, _vitest.expect)((0, _server.parseFuncCall)('Chem:smilesToMw("ccc")')).toEqual({
12
+ name: 'Chem:smilesToMw',
13
+ params: {
14
+ '0': 'ccc'
15
+ }
16
+ });
17
+ });
18
+ (0, _vitest.it)('parses a single-quoted string argument', () => {
19
+ (0, _vitest.expect)((0, _server.parseFuncCall)("Pkg:fn('hello')")).toEqual({
20
+ name: 'Pkg:fn',
21
+ params: {
22
+ '0': 'hello'
23
+ }
24
+ });
25
+ });
26
+ (0, _vitest.it)('parses a numeric argument', () => {
27
+ (0, _vitest.expect)((0, _server.parseFuncCall)('Pkg:fn(42)')).toEqual({
28
+ name: 'Pkg:fn',
29
+ params: {
30
+ '0': 42
31
+ }
32
+ });
33
+ });
34
+ (0, _vitest.it)('parses multiple positional arguments', () => {
35
+ (0, _vitest.expect)((0, _server.parseFuncCall)('Pkg:fn(1, "hello", 3.14)')).toEqual({
36
+ name: 'Pkg:fn',
37
+ params: {
38
+ '0': 1,
39
+ '1': 'hello',
40
+ '2': 3.14
41
+ }
42
+ });
43
+ });
44
+ (0, _vitest.it)('parses an object argument with quoted keys', () => {
45
+ (0, _vitest.expect)((0, _server.parseFuncCall)('Pkg:fn({"a":5,"b":22})')).toEqual({
46
+ name: 'Pkg:fn',
47
+ params: {
48
+ a: 5,
49
+ b: 22
50
+ }
51
+ });
52
+ });
53
+ (0, _vitest.it)('parses an object argument with unquoted keys', () => {
54
+ (0, _vitest.expect)((0, _server.parseFuncCall)('Pkg:fn({a:5,b:22})')).toEqual({
55
+ name: 'Pkg:fn',
56
+ params: {
57
+ a: 5,
58
+ b: 22
59
+ }
60
+ });
61
+ });
62
+ (0, _vitest.it)('parses an object argument with a boolean value', () => {
63
+ (0, _vitest.expect)((0, _server.parseFuncCall)('Pkg:fn({unquoted:true})')).toEqual({
64
+ name: 'Pkg:fn',
65
+ params: {
66
+ unquoted: true
67
+ }
68
+ });
69
+ });
70
+ (0, _vitest.it)('returns empty params for a no-argument call', () => {
71
+ (0, _vitest.expect)((0, _server.parseFuncCall)('Pkg:fn()')).toEqual({
72
+ name: 'Pkg:fn',
73
+ params: {}
74
+ });
75
+ });
76
+ (0, _vitest.it)('returns empty params when there are no parentheses', () => {
77
+ (0, _vitest.expect)((0, _server.parseFuncCall)('Pkg:fn')).toEqual({
78
+ name: 'Pkg:fn',
79
+ params: {}
80
+ });
81
+ });
82
+ (0, _vitest.it)('handles a package-less function name', () => {
83
+ (0, _vitest.expect)((0, _server.parseFuncCall)('myFunc("arg")')).toEqual({
84
+ name: 'myFunc',
85
+ params: {
86
+ '0': 'arg'
87
+ }
88
+ });
89
+ });
90
+ });
91
+ (0, _vitest.describe)('buildInlineManifest', () => {
92
+ (0, _vitest.it)('sets action to entity.verb', () => {
93
+ const result = (0, _server.buildInlineManifest)('users', 'delete', ['abc']);
94
+ (0, _vitest.expect)(result.operations[0].action).toBe('users.delete');
95
+ });
96
+ (0, _vitest.it)('maps string args to {id} param for non-file entities', () => {
97
+ const result = (0, _server.buildInlineManifest)('users', 'delete', ['id1', 'id2']);
98
+ (0, _vitest.expect)(result.operations).toEqual([{
99
+ id: 'op0',
100
+ action: 'users.delete',
101
+ params: {
102
+ id: 'id1'
103
+ }
104
+ }, {
105
+ id: 'op1',
106
+ action: 'users.delete',
107
+ params: {
108
+ id: 'id2'
109
+ }
110
+ }]);
111
+ });
112
+ (0, _vitest.it)('maps string args to {path} param for the files entity', () => {
113
+ const result = (0, _server.buildInlineManifest)('files', 'delete', ['System:AppData/a.txt', 'System:AppData/b.txt']);
114
+ (0, _vitest.expect)(result.operations).toEqual([{
115
+ id: 'op0',
116
+ action: 'files.delete',
117
+ params: {
118
+ path: 'System:AppData/a.txt'
119
+ }
120
+ }, {
121
+ id: 'op1',
122
+ action: 'files.delete',
123
+ params: {
124
+ path: 'System:AppData/b.txt'
125
+ }
126
+ }]);
127
+ });
128
+ (0, _vitest.it)('passes object array args through as params directly', () => {
129
+ const objs = [{
130
+ name: 'Alice',
131
+ email: 'a@x.com'
132
+ }, {
133
+ name: 'Bob',
134
+ email: 'b@x.com'
135
+ }];
136
+ const result = (0, _server.buildInlineManifest)('users', 'create', objs);
137
+ (0, _vitest.expect)(result.operations).toEqual([{
138
+ id: 'op0',
139
+ action: 'users.create',
140
+ params: {
141
+ name: 'Alice',
142
+ email: 'a@x.com'
143
+ }
144
+ }, {
145
+ id: 'op1',
146
+ action: 'users.create',
147
+ params: {
148
+ name: 'Bob',
149
+ email: 'b@x.com'
150
+ }
151
+ }]);
152
+ });
153
+ (0, _vitest.it)('assigns sequential op ids starting at op0', () => {
154
+ const result = (0, _server.buildInlineManifest)('groups', 'delete', ['x', 'y', 'z']);
155
+ (0, _vitest.expect)(result.operations.map(o => o.id)).toEqual(['op0', 'op1', 'op2']);
156
+ });
157
+ (0, _vitest.it)('returns a single operation for a single arg', () => {
158
+ const result = (0, _server.buildInlineManifest)('connections', 'delete', ['conn-id']);
159
+ (0, _vitest.expect)(result.operations).toHaveLength(1);
160
+ });
161
+ });
162
+ (0, _vitest.describe)('resolveManifestSources', () => {
163
+ let tmpFile;
164
+ (0, _vitest.beforeEach)(() => {
165
+ tmpFile = path.join(os.tmpdir(), `grok-batch-test-${Date.now()}.bin`);
166
+ });
167
+ (0, _vitest.afterEach)(() => {
168
+ if (fs.existsSync(tmpFile)) fs.unlinkSync(tmpFile);
169
+ });
170
+ (0, _vitest.it)('passes through a manifest with no files.put operations unchanged', () => {
171
+ const manifest = {
172
+ operations: [{
173
+ id: 'op0',
174
+ action: 'users.delete',
175
+ params: {
176
+ id: 'abc'
177
+ }
178
+ }]
179
+ };
180
+ (0, _vitest.expect)((0, _server.resolveManifestSources)(manifest)).toEqual(manifest);
181
+ });
182
+ (0, _vitest.it)('passes through a files.put operation that has no source field', () => {
183
+ const manifest = {
184
+ operations: [{
185
+ id: 'op0',
186
+ action: 'files.put',
187
+ params: {
188
+ path: 'System:AppData/f.txt',
189
+ content: 'aGk='
190
+ }
191
+ }]
192
+ };
193
+ (0, _vitest.expect)((0, _server.resolveManifestSources)(manifest)).toEqual(manifest);
194
+ });
195
+ (0, _vitest.it)('reads the source file, base64-encodes its contents, and removes the source key', () => {
196
+ const data = 'hello world';
197
+ fs.writeFileSync(tmpFile, data);
198
+ const manifest = {
199
+ operations: [{
200
+ id: 'op0',
201
+ action: 'files.put',
202
+ params: {
203
+ path: 'System:AppData/f.txt',
204
+ source: tmpFile
205
+ }
206
+ }]
207
+ };
208
+ const result = (0, _server.resolveManifestSources)(manifest);
209
+ const params = result.operations[0].params;
210
+ (0, _vitest.expect)(params.content).toBe(Buffer.from(data).toString('base64'));
211
+ (0, _vitest.expect)(params.source).toBeUndefined();
212
+ });
213
+ (0, _vitest.it)('preserves other params alongside the injected content', () => {
214
+ fs.writeFileSync(tmpFile, 'data');
215
+ const manifest = {
216
+ operations: [{
217
+ id: 'op0',
218
+ action: 'files.put',
219
+ params: {
220
+ path: 'System:AppData/f.txt',
221
+ source: tmpFile,
222
+ extra: 'val'
223
+ }
224
+ }]
225
+ };
226
+ const result = (0, _server.resolveManifestSources)(manifest);
227
+ const params = result.operations[0].params;
228
+ (0, _vitest.expect)(params.path).toBe('System:AppData/f.txt');
229
+ (0, _vitest.expect)(params.extra).toBe('val');
230
+ });
231
+ (0, _vitest.it)('leaves non-files.put operations untouched in a mixed manifest', () => {
232
+ fs.writeFileSync(tmpFile, 'x');
233
+ const manifest = {
234
+ operations: [{
235
+ id: 'op0',
236
+ action: 'users.delete',
237
+ params: {
238
+ id: 'u1'
239
+ }
240
+ }, {
241
+ id: 'op1',
242
+ action: 'files.put',
243
+ params: {
244
+ path: 'System:AppData/f.txt',
245
+ source: tmpFile
246
+ }
247
+ }]
248
+ };
249
+ const result = (0, _server.resolveManifestSources)(manifest);
250
+ (0, _vitest.expect)(result.operations[0]).toEqual({
251
+ id: 'op0',
252
+ action: 'users.delete',
253
+ params: {
254
+ id: 'u1'
255
+ }
256
+ });
257
+ (0, _vitest.expect)(result.operations[1].params.source).toBeUndefined();
258
+ (0, _vitest.expect)(result.operations[1].params.content).toBeDefined();
259
+ });
260
+ (0, _vitest.it)('correctly encodes binary file contents', () => {
261
+ const bytes = Buffer.from([0x00, 0xff, 0x10, 0xab]);
262
+ fs.writeFileSync(tmpFile, bytes);
263
+ const manifest = {
264
+ operations: [{
265
+ id: 'op0',
266
+ action: 'files.put',
267
+ params: {
268
+ path: 'System:AppData/f.bin',
269
+ source: tmpFile
270
+ }
271
+ }]
272
+ };
273
+ const result = (0, _server.resolveManifestSources)(manifest);
274
+ const decoded = Buffer.from(result.operations[0].params.content, 'base64');
275
+ (0, _vitest.expect)(decoded).toEqual(bytes);
276
+ });
277
+ });
@@ -0,0 +1,197 @@
1
+ import {describe, it, expect, beforeEach, afterEach} from 'vitest';
2
+ import * as os from 'os';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ import {parseFuncCall, buildInlineManifest, resolveManifestSources} from '../commands/server';
6
+
7
+ describe('parseFuncCall', () => {
8
+ it('parses a single string argument', () => {
9
+ expect(parseFuncCall('Chem:smilesToMw("ccc")')).toEqual({
10
+ name: 'Chem:smilesToMw',
11
+ params: {'0': 'ccc'},
12
+ });
13
+ });
14
+
15
+ it('parses a single-quoted string argument', () => {
16
+ expect(parseFuncCall("Pkg:fn('hello')")).toEqual({
17
+ name: 'Pkg:fn',
18
+ params: {'0': 'hello'},
19
+ });
20
+ });
21
+
22
+ it('parses a numeric argument', () => {
23
+ expect(parseFuncCall('Pkg:fn(42)')).toEqual({
24
+ name: 'Pkg:fn',
25
+ params: {'0': 42},
26
+ });
27
+ });
28
+
29
+ it('parses multiple positional arguments', () => {
30
+ expect(parseFuncCall('Pkg:fn(1, "hello", 3.14)')).toEqual({
31
+ name: 'Pkg:fn',
32
+ params: {'0': 1, '1': 'hello', '2': 3.14},
33
+ });
34
+ });
35
+
36
+ it('parses an object argument with quoted keys', () => {
37
+ expect(parseFuncCall('Pkg:fn({"a":5,"b":22})')).toEqual({
38
+ name: 'Pkg:fn',
39
+ params: {a: 5, b: 22},
40
+ });
41
+ });
42
+
43
+ it('parses an object argument with unquoted keys', () => {
44
+ expect(parseFuncCall('Pkg:fn({a:5,b:22})')).toEqual({
45
+ name: 'Pkg:fn',
46
+ params: {a: 5, b: 22},
47
+ });
48
+ });
49
+
50
+ it('parses an object argument with a boolean value', () => {
51
+ expect(parseFuncCall('Pkg:fn({unquoted:true})')).toEqual({
52
+ name: 'Pkg:fn',
53
+ params: {unquoted: true},
54
+ });
55
+ });
56
+
57
+ it('returns empty params for a no-argument call', () => {
58
+ expect(parseFuncCall('Pkg:fn()')).toEqual({
59
+ name: 'Pkg:fn',
60
+ params: {},
61
+ });
62
+ });
63
+
64
+ it('returns empty params when there are no parentheses', () => {
65
+ expect(parseFuncCall('Pkg:fn')).toEqual({
66
+ name: 'Pkg:fn',
67
+ params: {},
68
+ });
69
+ });
70
+
71
+ it('handles a package-less function name', () => {
72
+ expect(parseFuncCall('myFunc("arg")')).toEqual({
73
+ name: 'myFunc',
74
+ params: {'0': 'arg'},
75
+ });
76
+ });
77
+ });
78
+
79
+ describe('buildInlineManifest', () => {
80
+ it('sets action to entity.verb', () => {
81
+ const result = buildInlineManifest('users', 'delete', ['abc']);
82
+ expect(result.operations[0].action).toBe('users.delete');
83
+ });
84
+
85
+ it('maps string args to {id} param for non-file entities', () => {
86
+ const result = buildInlineManifest('users', 'delete', ['id1', 'id2']);
87
+ expect(result.operations).toEqual([
88
+ {id: 'op0', action: 'users.delete', params: {id: 'id1'}},
89
+ {id: 'op1', action: 'users.delete', params: {id: 'id2'}},
90
+ ]);
91
+ });
92
+
93
+ it('maps string args to {path} param for the files entity', () => {
94
+ const result = buildInlineManifest('files', 'delete', ['System:AppData/a.txt', 'System:AppData/b.txt']);
95
+ expect(result.operations).toEqual([
96
+ {id: 'op0', action: 'files.delete', params: {path: 'System:AppData/a.txt'}},
97
+ {id: 'op1', action: 'files.delete', params: {path: 'System:AppData/b.txt'}},
98
+ ]);
99
+ });
100
+
101
+ it('passes object array args through as params directly', () => {
102
+ const objs = [{name: 'Alice', email: 'a@x.com'}, {name: 'Bob', email: 'b@x.com'}];
103
+ const result = buildInlineManifest('users', 'create', objs);
104
+ expect(result.operations).toEqual([
105
+ {id: 'op0', action: 'users.create', params: {name: 'Alice', email: 'a@x.com'}},
106
+ {id: 'op1', action: 'users.create', params: {name: 'Bob', email: 'b@x.com'}},
107
+ ]);
108
+ });
109
+
110
+ it('assigns sequential op ids starting at op0', () => {
111
+ const result = buildInlineManifest('groups', 'delete', ['x', 'y', 'z']);
112
+ expect(result.operations.map((o) => o.id)).toEqual(['op0', 'op1', 'op2']);
113
+ });
114
+
115
+ it('returns a single operation for a single arg', () => {
116
+ const result = buildInlineManifest('connections', 'delete', ['conn-id']);
117
+ expect(result.operations).toHaveLength(1);
118
+ });
119
+ });
120
+
121
+ describe('resolveManifestSources', () => {
122
+ let tmpFile: string;
123
+
124
+ beforeEach(() => {
125
+ tmpFile = path.join(os.tmpdir(), `grok-batch-test-${Date.now()}.bin`);
126
+ });
127
+
128
+ afterEach(() => {
129
+ if (fs.existsSync(tmpFile)) fs.unlinkSync(tmpFile);
130
+ });
131
+
132
+ it('passes through a manifest with no files.put operations unchanged', () => {
133
+ const manifest = {
134
+ operations: [{id: 'op0', action: 'users.delete', params: {id: 'abc'}}],
135
+ };
136
+ expect(resolveManifestSources(manifest)).toEqual(manifest);
137
+ });
138
+
139
+ it('passes through a files.put operation that has no source field', () => {
140
+ const manifest = {
141
+ operations: [{id: 'op0', action: 'files.put', params: {path: 'System:AppData/f.txt', content: 'aGk='}}],
142
+ };
143
+ expect(resolveManifestSources(manifest)).toEqual(manifest);
144
+ });
145
+
146
+ it('reads the source file, base64-encodes its contents, and removes the source key', () => {
147
+ const data = 'hello world';
148
+ fs.writeFileSync(tmpFile, data);
149
+
150
+ const manifest = {
151
+ operations: [{id: 'op0', action: 'files.put', params: {path: 'System:AppData/f.txt', source: tmpFile}}],
152
+ };
153
+ const result = resolveManifestSources(manifest);
154
+ const params = result.operations[0].params as any;
155
+ expect(params.content).toBe(Buffer.from(data).toString('base64'));
156
+ expect(params.source).toBeUndefined();
157
+ });
158
+
159
+ it('preserves other params alongside the injected content', () => {
160
+ fs.writeFileSync(tmpFile, 'data');
161
+
162
+ const manifest = {
163
+ operations: [{id: 'op0', action: 'files.put', params: {path: 'System:AppData/f.txt', source: tmpFile, extra: 'val'}}],
164
+ };
165
+ const result = resolveManifestSources(manifest);
166
+ const params = result.operations[0].params as any;
167
+ expect(params.path).toBe('System:AppData/f.txt');
168
+ expect(params.extra).toBe('val');
169
+ });
170
+
171
+ it('leaves non-files.put operations untouched in a mixed manifest', () => {
172
+ fs.writeFileSync(tmpFile, 'x');
173
+
174
+ const manifest = {
175
+ operations: [
176
+ {id: 'op0', action: 'users.delete', params: {id: 'u1'}},
177
+ {id: 'op1', action: 'files.put', params: {path: 'System:AppData/f.txt', source: tmpFile}},
178
+ ],
179
+ };
180
+ const result = resolveManifestSources(manifest);
181
+ expect(result.operations[0]).toEqual({id: 'op0', action: 'users.delete', params: {id: 'u1'}});
182
+ expect((result.operations[1].params as any).source).toBeUndefined();
183
+ expect((result.operations[1].params as any).content).toBeDefined();
184
+ });
185
+
186
+ it('correctly encodes binary file contents', () => {
187
+ const bytes = Buffer.from([0x00, 0xff, 0x10, 0xab]);
188
+ fs.writeFileSync(tmpFile, bytes);
189
+
190
+ const manifest = {
191
+ operations: [{id: 'op0', action: 'files.put', params: {path: 'System:AppData/f.bin', source: tmpFile}}],
192
+ };
193
+ const result = resolveManifestSources(manifest);
194
+ const decoded = Buffer.from((result.operations[0].params as any).content, 'base64');
195
+ expect(decoded).toEqual(bytes);
196
+ });
197
+ });
@@ -46,7 +46,11 @@ function generateQueryWrappers() {
46
46
  const description = utils.getScriptDescription(q, utils.commentMap[utils.queryExtension]);
47
47
  const inputs = utils.getScriptInputs(q, utils.commentMap[utils.queryExtension]);
48
48
  const outputType = utils.getScriptOutputType(q, utils.commentMap[utils.queryExtension]);
49
- tb.replace('PARAMS_OBJECT', inputs).replace('TYPED_PARAMS', inputs).replace('FUNC_DESCRIPTION', description).replace('OUTPUT_TYPE', outputType === 'void' ? utils.dgToTsTypeMap['dataframe'] : outputType);
49
+ const resolvedOutputType = outputType === 'void' ? utils.dgToTsTypeMap['dataframe'] : outputType;
50
+ tb.replace('PARAMS_OBJECT', inputs).replace('TYPED_PARAMS', inputs).replace('FUNC_JSDOC', {
51
+ description,
52
+ inputs
53
+ }).replace('OUTPUT_TYPE', resolvedOutputType);
50
54
  wrappers.push(tb.build(1));
51
55
  }
52
56
  }
@@ -76,7 +80,10 @@ function generateScriptWrappers() {
76
80
  const tb = new utils.TemplateBuilder(utils.scriptWrapperTemplate).replace('FUNC_NAME', name).replace('FUNC_NAME_LOWERCASE', name).replace('PACKAGE_NAMESPACE', _package?.friendlyName ?? '');
77
81
  const inputs = utils.getScriptInputs(script);
78
82
  const outputType = utils.getScriptOutputType(script);
79
- tb.replace('PARAMS_OBJECT', inputs).replace('TYPED_PARAMS', inputs).replace('FUNC_DESCRIPTION', description).replace('OUTPUT_TYPE', outputType);
83
+ tb.replace('PARAMS_OBJECT', inputs).replace('TYPED_PARAMS', inputs).replace('FUNC_JSDOC', {
84
+ description,
85
+ inputs
86
+ }).replace('OUTPUT_TYPE', outputType);
80
87
  wrappers.push(tb.build(1));
81
88
  }
82
89
  }
@@ -100,7 +107,10 @@ function generateFunctionWrappers() {
100
107
  let outputType = '';
101
108
  outputType = annotationOutputDir ?? 'any';
102
109
  checkNameColision(name);
103
- const tb = new utils.TemplateBuilder(utils.scriptWrapperTemplate).replace('FUNC_NAME', name).replace('FUNC_NAME_LOWERCASE', name).replace('PACKAGE_NAMESPACE', _package?.friendlyName ?? '').replace('PARAMS_OBJECT', annotationInputs).replace('FUNC_DESCRIPTION', description).replace('TYPED_PARAMS', annotationInputs).replace('OUTPUT_TYPE', outputType);
110
+ const tb = new utils.TemplateBuilder(utils.scriptWrapperTemplate).replace('FUNC_NAME', name).replace('FUNC_NAME_LOWERCASE', name).replace('PACKAGE_NAMESPACE', _package?.friendlyName ?? '').replace('PARAMS_OBJECT', annotationInputs).replace('FUNC_JSDOC', {
111
+ description,
112
+ inputs: annotationInputs
113
+ }).replace('TYPED_PARAMS', annotationInputs).replace('OUTPUT_TYPE', outputType);
104
114
  wrappers.push(tb.build(1));
105
115
  }
106
116
  }
@@ -54,7 +54,7 @@ async function buildRecursive(baseDir, args, buildCmd) {
54
54
  return false;
55
55
  }
56
56
  console.log(`Found ${filtered.length} package(s): ${filtered.map(p => p.friendlyName).join(', ')}`);
57
- if (!args.silent) {
57
+ if (!args.silent && !args.s) {
58
58
  const confirmed = await confirm(`\nBuild ${filtered.length} package(s)?`);
59
59
  if (!confirmed) {
60
60
  console.log('Aborted.');
@@ -26,7 +26,7 @@ const confTemplate = _jsYaml.default.load(_fs.default.readFileSync(confTemplateD
26
26
  encoding: 'utf-8'
27
27
  }));
28
28
  const dependencies = [];
29
- function createDirectoryContents(name, config, templateDir, packageDir, ide = '', ts = true, eslint = false, test = false) {
29
+ function createDirectoryContents(name, friendlyName, config, templateDir, packageDir, ide = '', ts = true, eslint = false, test = false) {
30
30
  const filesToCreate = _fs.default.readdirSync(templateDir);
31
31
  filesToCreate.forEach(file => {
32
32
  const origFilePath = _path.default.join(templateDir, file);
@@ -38,6 +38,7 @@ function createDirectoryContents(name, config, templateDir, packageDir, ide = ''
38
38
  return false;
39
39
  }
40
40
  let contents = _fs.default.readFileSync(file === 'webpack.config.js' && ts ? _path.default.join(templateDir, 'ts.webpack.config.js') : origFilePath, 'utf8');
41
+ contents = contents.replace(/#{PACKAGE_FRIENDLY_NAME}/g, friendlyName);
41
42
  contents = contents.replace(/#{PACKAGE_NAME}/g, name);
42
43
  contents = contents.replace(/#{PACKAGE_DETECTORS_NAME}/g, utils.kebabToCamelCase(name));
43
44
  contents = contents.replace(/#{PACKAGE_NAME_LOWERCASE}/g, name.toLowerCase());
@@ -114,7 +115,7 @@ function createDirectoryContents(name, config, templateDir, packageDir, ide = ''
114
115
  _fs.default.mkdirSync(copyFilePath);
115
116
  // recursive call
116
117
  if (_path.default.basename(origFilePath) === 'node_modules') return;
117
- createDirectoryContents(name, config, origFilePath, copyFilePath, ide, ts, eslint, test);
118
+ createDirectoryContents(name, friendlyName, config, origFilePath, copyFilePath, ide, ts, eslint, test);
118
119
  }
119
120
  });
120
121
  }
@@ -138,8 +139,10 @@ function create(args) {
138
139
  color.error(confTest.message);
139
140
  return false;
140
141
  }
141
- const name = nArgs === 2 ? args['_'][1] : curFolder;
142
- const validName = /^([A-Za-z\-_\d])+$/.test(name);
142
+ const rawName = nArgs === 2 ? args['_'][1] : curFolder;
143
+ const validName = /^([A-Za-z\-_\d])+$/.test(rawName);
144
+ const friendlyName = rawName;
145
+ const name = rawName.charAt(0).toUpperCase() + rawName.slice(1).toLowerCase();
143
146
  if (validName) {
144
147
  let packageDir = curDir;
145
148
  let repositoryInfo = null;
@@ -183,7 +186,7 @@ function create(args) {
183
186
  }
184
187
  process.exit();
185
188
  });
186
- createDirectoryContents(name, config, templateDir, packageDir, args.ide, ts, !!args.eslint, !!args.test);
189
+ createDirectoryContents(name, friendlyName, config, templateDir, packageDir, args.ide, ts, !!args.eslint, !!args.test);
187
190
  color.success('Successfully created package ' + name);
188
191
  console.log(_entHelpers.help.package(ts));
189
192
  console.log(`\nThe package has the following dependencies:\n${dependencies.join(' ')}\n`);