@tywalk/pcf-helper-run 1.3.0 → 1.3.2
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/dist/__tests__/argumentUtil.test.js +112 -0
- package/dist/__tests__/pcf-helper-run.test.js +14 -0
- package/dist/__tests__/performanceUtil.test.js +90 -0
- package/dist/index.js +1 -0
- package/dist/package.json +2 -2
- package/dist/util/argumentUtil.js +1 -1
- package/dist/util/performanceUtil.js +3 -1
- package/package.json +2 -2
- package/types/__tests__/argumentUtil.test.d.ts +1 -0
- package/types/__tests__/performanceUtil.test.d.ts +1 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/// <reference types="jest" />
|
|
3
|
+
/// <reference types="node" />
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
const argumentUtil_1 = require("../util/argumentUtil");
|
|
6
|
+
describe('pcf-helper-run argumentUtil', () => {
|
|
7
|
+
describe('getArg', () => {
|
|
8
|
+
it('should return the argument value if found', () => {
|
|
9
|
+
const args = ['-p', '/path/to/project', '-v'];
|
|
10
|
+
expect((0, argumentUtil_1.getArg)(args, '-p')).toBe('/path/to/project');
|
|
11
|
+
});
|
|
12
|
+
it('should return undefined if argument not found', () => {
|
|
13
|
+
const args = ['-p', '/path/to/project'];
|
|
14
|
+
expect((0, argumentUtil_1.getArg)(args, '-v')).toBeUndefined();
|
|
15
|
+
});
|
|
16
|
+
it('should return undefined if argument is at the end with no value', () => {
|
|
17
|
+
const args = ['-p', '/path/to/project', '-v'];
|
|
18
|
+
expect((0, argumentUtil_1.getArg)(args, '-v')).toBeUndefined();
|
|
19
|
+
});
|
|
20
|
+
it('should handle empty args', () => {
|
|
21
|
+
const args = [];
|
|
22
|
+
expect((0, argumentUtil_1.getArg)(args, '-p')).toBeUndefined();
|
|
23
|
+
});
|
|
24
|
+
it('should find value after flag', () => {
|
|
25
|
+
const args = ['build', '-p', '/project', 'deploy'];
|
|
26
|
+
expect((0, argumentUtil_1.getArg)(args, '-p')).toBe('/project');
|
|
27
|
+
});
|
|
28
|
+
it('should return undefined for flag at end of array', () => {
|
|
29
|
+
const args = ['build', '-v', '-p'];
|
|
30
|
+
expect((0, argumentUtil_1.getArg)(args, '-p')).toBeUndefined();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('getArgValue', () => {
|
|
34
|
+
it('should return value for matching option', () => {
|
|
35
|
+
const args = ['-n', 'controlName'];
|
|
36
|
+
expect((0, argumentUtil_1.getArgValue)(args, ['-n'])).toBe('controlName');
|
|
37
|
+
});
|
|
38
|
+
it('should return value for long form option', () => {
|
|
39
|
+
const args = ['--name', 'controlName'];
|
|
40
|
+
expect((0, argumentUtil_1.getArgValue)(args, ['--name'])).toBe('controlName');
|
|
41
|
+
});
|
|
42
|
+
it('should find first matching option from list', () => {
|
|
43
|
+
const args = ['--publisher-name', 'MyPub'];
|
|
44
|
+
expect((0, argumentUtil_1.getArgValue)(args, ['-pn', '--publisher-name'])).toBe('MyPub');
|
|
45
|
+
});
|
|
46
|
+
it('should return default if not found', () => {
|
|
47
|
+
const args = ['-p', '/path'];
|
|
48
|
+
expect((0, argumentUtil_1.getArgValue)(args, ['-n', '--name'], 'default')).toBe('default');
|
|
49
|
+
});
|
|
50
|
+
it('should return undefined if not found and no default', () => {
|
|
51
|
+
const args = ['-p', '/path'];
|
|
52
|
+
expect((0, argumentUtil_1.getArgValue)(args, ['-n'])).toBeUndefined();
|
|
53
|
+
});
|
|
54
|
+
it('should prioritize first matching option', () => {
|
|
55
|
+
const args = ['-e', 'env1', '-e', 'env2'];
|
|
56
|
+
expect((0, argumentUtil_1.getArgValue)(args, ['-e'])).toBe('env1');
|
|
57
|
+
});
|
|
58
|
+
it('should handle value at end bounds', () => {
|
|
59
|
+
const args = ['command', '-t', 'value'];
|
|
60
|
+
expect((0, argumentUtil_1.getArgValue)(args, ['-t'])).toBe('value');
|
|
61
|
+
});
|
|
62
|
+
it('should return undefined if flag has no value', () => {
|
|
63
|
+
const args = ['-n'];
|
|
64
|
+
expect((0, argumentUtil_1.getArgValue)(args, ['-n'])).toBeUndefined();
|
|
65
|
+
});
|
|
66
|
+
it('should handle multiple aliases', () => {
|
|
67
|
+
const args = ['--environment', 'prod'];
|
|
68
|
+
expect((0, argumentUtil_1.getArgValue)(args, ['-e', '--environment'])).toBe('prod');
|
|
69
|
+
});
|
|
70
|
+
it('should find short option when long form not present', () => {
|
|
71
|
+
const args = ['-e', 'test'];
|
|
72
|
+
expect((0, argumentUtil_1.getArgValue)(args, ['-e', '--environment'])).toBe('test');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('complex argument patterns', () => {
|
|
76
|
+
it('should parse build command arguments', () => {
|
|
77
|
+
const args = ['build', '-p', '/path/to/project', '-t', '30000', '-v'];
|
|
78
|
+
expect((0, argumentUtil_1.getArg)(args, '-p')).toBe('/path/to/project');
|
|
79
|
+
expect((0, argumentUtil_1.getArg)(args, '-t')).toBe('30000');
|
|
80
|
+
});
|
|
81
|
+
it('should parse deploy command with environment', () => {
|
|
82
|
+
const args = ['deploy', '-p', '/path', '-e', 'prod'];
|
|
83
|
+
expect((0, argumentUtil_1.getArg)(args, '-p')).toBe('/path');
|
|
84
|
+
expect((0, argumentUtil_1.getArg)(args, '-e')).toBe('prod');
|
|
85
|
+
});
|
|
86
|
+
it('should parse init command with multiple options', () => {
|
|
87
|
+
const args = ['init', '-p', '/path', '-n', 'MyControl', '--publisher-name', 'Publisher'];
|
|
88
|
+
expect((0, argumentUtil_1.getArg)(args, '-p')).toBe('/path');
|
|
89
|
+
expect((0, argumentUtil_1.getArg)(args, '-n')).toBe('MyControl');
|
|
90
|
+
expect((0, argumentUtil_1.getArg)(args, '--publisher-name')).toBe('Publisher');
|
|
91
|
+
});
|
|
92
|
+
it('should handle boolean flags (no value)', () => {
|
|
93
|
+
const args = ['build', '--watch'];
|
|
94
|
+
expect((0, argumentUtil_1.getArg)(args, '-v')).toBeUndefined(); // -v flag has no value
|
|
95
|
+
expect((0, argumentUtil_1.getArg)(args, '--watch')).toBeUndefined();
|
|
96
|
+
});
|
|
97
|
+
it('should parse deprecated -env flag', () => {
|
|
98
|
+
const args = ['import', '-p', '/path', '-env', 'prod'];
|
|
99
|
+
expect((0, argumentUtil_1.getArg)(args, '-env')).toBe('prod');
|
|
100
|
+
});
|
|
101
|
+
it('should handle paths with special characters', () => {
|
|
102
|
+
const args = ['-p', 'C:\\Users\\test\\project', '-n', 'My-Control.v2'];
|
|
103
|
+
expect((0, argumentUtil_1.getArg)(args, '-p')).toBe('C:\\Users\\test\\project');
|
|
104
|
+
expect((0, argumentUtil_1.getArg)(args, '-n')).toBe('My-Control.v2');
|
|
105
|
+
});
|
|
106
|
+
it('should handle URLs as argument values', () => {
|
|
107
|
+
const args = ['-u', 'https://tenant.crm.dynamics.com', '-s', 'https://cdn.example.com/bundle.js'];
|
|
108
|
+
expect((0, argumentUtil_1.getArg)(args, '-u')).toBe('https://tenant.crm.dynamics.com');
|
|
109
|
+
expect((0, argumentUtil_1.getArg)(args, '-s')).toBe('https://cdn.example.com/bundle.js');
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -36,6 +36,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
const child_process_1 = require("child_process");
|
|
37
37
|
const package_json_1 = require("../package.json");
|
|
38
38
|
const tasks = __importStar(require("@tywalk/pcf-helper"));
|
|
39
|
+
beforeAll(() => {
|
|
40
|
+
var _a;
|
|
41
|
+
const npmExecPath = process.env.npm_execpath;
|
|
42
|
+
if (!npmExecPath) {
|
|
43
|
+
throw new Error('Unable to locate npm executable path from npm_execpath.');
|
|
44
|
+
}
|
|
45
|
+
const build = (0, child_process_1.spawnSync)(process.execPath, [npmExecPath, 'run', 'build'], {
|
|
46
|
+
cwd: process.cwd(),
|
|
47
|
+
encoding: 'utf-8'
|
|
48
|
+
});
|
|
49
|
+
if (build.status !== 0) {
|
|
50
|
+
throw new Error(`Failed to build pcf-helper-run before CLI tests.\n${((_a = build.error) === null || _a === void 0 ? void 0 : _a.message) || build.stderr || build.stdout}`);
|
|
51
|
+
}
|
|
52
|
+
}, 60000);
|
|
39
53
|
test('displays version', (done) => {
|
|
40
54
|
const task = (0, child_process_1.spawn)('node', ['./dist/index.js', '--version']);
|
|
41
55
|
let output = '';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const performanceUtil_1 = require("../util/performanceUtil");
|
|
4
|
+
describe('pcf-helper-run performanceUtil', () => {
|
|
5
|
+
describe('formatMsToSec', () => {
|
|
6
|
+
it('should format milliseconds to seconds', () => {
|
|
7
|
+
const result = (0, performanceUtil_1.formatMsToSec)('Duration: %is', 5000);
|
|
8
|
+
expect(result).toBe('Duration: 5s');
|
|
9
|
+
});
|
|
10
|
+
it('should handle fractional seconds', () => {
|
|
11
|
+
const result = (0, performanceUtil_1.formatMsToSec)('Time: %is', 1500);
|
|
12
|
+
expect(result).toBe('Time: 1.5s');
|
|
13
|
+
});
|
|
14
|
+
it('should handle small durations', () => {
|
|
15
|
+
const result = (0, performanceUtil_1.formatMsToSec)('Quick: %is', 250);
|
|
16
|
+
expect(result).toBe('Quick: 0.25s');
|
|
17
|
+
});
|
|
18
|
+
it('should handle zero ms', () => {
|
|
19
|
+
const result = (0, performanceUtil_1.formatMsToSec)('Instant: %is', 0);
|
|
20
|
+
expect(result).toBe('Instant: 0s');
|
|
21
|
+
});
|
|
22
|
+
it('should handle large durations', () => {
|
|
23
|
+
const result = (0, performanceUtil_1.formatMsToSec)('Long: %is', 300000);
|
|
24
|
+
expect(result).toBe('Long: 300s');
|
|
25
|
+
});
|
|
26
|
+
it('should work with different format strings', () => {
|
|
27
|
+
const result = (0, performanceUtil_1.formatMsToSec)('Task %s took %is', 1000);
|
|
28
|
+
expect(result).toContain('1');
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('formatTime', () => {
|
|
32
|
+
it('should format Date to time string', () => {
|
|
33
|
+
const date = new Date('2024-01-15T14:30:45Z');
|
|
34
|
+
const result = (0, performanceUtil_1.formatTime)(date);
|
|
35
|
+
expect(result).toMatch(/\d{2}:\d{2}:\d{2}/);
|
|
36
|
+
});
|
|
37
|
+
it('should use 24-hour format', () => {
|
|
38
|
+
// Create a date at specific time
|
|
39
|
+
const date = new Date('2024-01-15T23:45:30Z');
|
|
40
|
+
const result = (0, performanceUtil_1.formatTime)(date);
|
|
41
|
+
expect(result).toMatch(/\d{2}:\d{2}:\d{2}/);
|
|
42
|
+
});
|
|
43
|
+
it('should handle midnight', () => {
|
|
44
|
+
const date = new Date('2024-01-15T00:00:00Z');
|
|
45
|
+
const result = (0, performanceUtil_1.formatTime)(date);
|
|
46
|
+
expect(result).toMatch(/\d{2}:\d{2}:\d{2}/);
|
|
47
|
+
});
|
|
48
|
+
it('should format consistent for same date', () => {
|
|
49
|
+
const date = new Date('2024-06-21T12:30:45Z');
|
|
50
|
+
const result1 = (0, performanceUtil_1.formatTime)(date);
|
|
51
|
+
const result2 = (0, performanceUtil_1.formatTime)(date);
|
|
52
|
+
expect(result1).toBe(result2);
|
|
53
|
+
});
|
|
54
|
+
it('should format current time', () => {
|
|
55
|
+
const now = new Date();
|
|
56
|
+
const result = (0, performanceUtil_1.formatTime)(now);
|
|
57
|
+
expect(result).toMatch(/\d{2}:\d{2}:\d{2}/);
|
|
58
|
+
});
|
|
59
|
+
it('should include leading zeros for single digit times', () => {
|
|
60
|
+
const date = new Date('2024-01-15T01:02:03Z');
|
|
61
|
+
const result = (0, performanceUtil_1.formatTime)(date);
|
|
62
|
+
expect(result).toMatch(/\d{2}:\d{2}:\d{2}/); // Always 2 digits
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('time formatting consistency', () => {
|
|
66
|
+
it('should format times consistently across calls', () => {
|
|
67
|
+
const times = [];
|
|
68
|
+
for (let i = 0; i < 5; i++) {
|
|
69
|
+
const date = new Date('2024-06-21T15:30:45Z');
|
|
70
|
+
times.push((0, performanceUtil_1.formatTime)(date));
|
|
71
|
+
}
|
|
72
|
+
// All should be identical
|
|
73
|
+
expect(new Set(times).size).toBe(1);
|
|
74
|
+
});
|
|
75
|
+
it('should format duration calculations correctly', () => {
|
|
76
|
+
const start = 1000;
|
|
77
|
+
const end = 6000;
|
|
78
|
+
const duration = end - start;
|
|
79
|
+
const result = (0, performanceUtil_1.formatMsToSec)('Duration: %is', duration);
|
|
80
|
+
expect(result).toBe('Duration: 5s');
|
|
81
|
+
});
|
|
82
|
+
it('should handle combined time and duration formatting', () => {
|
|
83
|
+
const date = new Date('2024-06-21T12:30:45Z');
|
|
84
|
+
const timeStr = (0, performanceUtil_1.formatTime)(date);
|
|
85
|
+
const durationStr = (0, performanceUtil_1.formatMsToSec)('in %is', 2500);
|
|
86
|
+
expect(timeStr).toMatch(/\d{2}:\d{2}:\d{2}/);
|
|
87
|
+
expect(durationStr).toBe('in 2.5s');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -287,6 +287,7 @@ withCommonOptions(commander_1.program.command('session'))
|
|
|
287
287
|
logger.log('[PCF Helper Run] ' + (0, performanceUtil_1.formatTime)(new Date()) + ' session started.\n');
|
|
288
288
|
if (!options.url || options.config) {
|
|
289
289
|
const config = tasks.loadConfig(options.config || 'session.config.json');
|
|
290
|
+
// Use the config values from the config file, falling back to the CLI options if the config values are not set
|
|
290
291
|
yield tasks.runSession((_a = config.remoteEnvironmentUrl) !== null && _a !== void 0 ? _a : options.url, (_b = config.remoteScriptToIntercept) !== null && _b !== void 0 ? _b : options.script, (_c = config.remoteStylesheetToIntercept) !== null && _c !== void 0 ? _c : options.stylesheet, (_d = config.localBundlePath) !== null && _d !== void 0 ? _d : options.bundle, (_e = config.localCssPath) !== null && _e !== void 0 ? _e : options.css, config.startWatch || options.watch);
|
|
291
292
|
}
|
|
292
293
|
else {
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tywalk/pcf-helper-run",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Unified CLI interface for Power Platform Component Framework (PCF) development — init, build, import, deploy, and manage PCF controls in Dataverse.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "./types/",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@tywalk/color-logger": "^1.0.3",
|
|
55
|
-
"@tywalk/pcf-helper": "^1.9.
|
|
55
|
+
"@tywalk/pcf-helper": "^1.9.2"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@semantic-release/git": "^10.0.1",
|
|
@@ -13,7 +13,7 @@ function getArgValue(args, argOpts, defaultIfExists) {
|
|
|
13
13
|
var _a;
|
|
14
14
|
const arg = args.find(a => argOpts.includes(a));
|
|
15
15
|
if (typeof arg === 'undefined') {
|
|
16
|
-
return
|
|
16
|
+
return defaultIfExists;
|
|
17
17
|
}
|
|
18
18
|
const argIndex = args.indexOf(arg) + 1;
|
|
19
19
|
return (_a = args.at(argIndex)) !== null && _a !== void 0 ? _a : defaultIfExists;
|
|
@@ -22,7 +22,9 @@ const formatter = new Intl.DateTimeFormat('en-US', {
|
|
|
22
22
|
*/
|
|
23
23
|
function formatMsToSec(format, ms) {
|
|
24
24
|
const seconds = ms / 1000;
|
|
25
|
-
|
|
25
|
+
// %i truncates floats in util.format, so normalize to %f to preserve precision.
|
|
26
|
+
const normalizedFormat = format.replace(/%i/g, '%f');
|
|
27
|
+
return util_1.default.format(normalizedFormat, seconds);
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* Formats a Date object into a human-readable string.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tywalk/pcf-helper-run",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"description": "Unified CLI interface for Power Platform Component Framework (PCF) development — init, build, import, deploy, and manage PCF controls in Dataverse.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "./types/",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@tywalk/color-logger": "^1.0.3",
|
|
55
|
-
"@tywalk/pcf-helper": "^1.9.
|
|
55
|
+
"@tywalk/pcf-helper": "^1.9.2"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@semantic-release/git": "^10.0.1",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|