Skip to content

Commit 4546814

Browse files
committed
feat: Implement locals merging and overiding
1 parent 992317a commit 4546814

File tree

4 files changed

+208
-87
lines changed

4 files changed

+208
-87
lines changed

src/index.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import tasker from './tasker';
1+
import { initializeTaskerJs } from './tasker';
22
import Router from './router';
33

4+
window.tasker = initializeTaskerJs(window);
5+
46
const CONFIG = {
57
Environment: tasker.global('TJS_ENV'),
68
RemoteUrl: tasker.global('TJS_DEV_REMOTE'),
@@ -22,9 +24,10 @@ const hotReload = () => {
2224
tasker.writeFile(CONFIG.LocalPath, result);
2325
tasker.flash('script updated');
2426
tasker.performTask(
25-
TASK.RunScript,
26-
tasker.local('priority'),
27-
JSON.stringify(tasker.locals)
27+
/* Task name */ TASK.RunScript,
28+
/* Priority */tasker.local('priority'),
29+
/* par1 */ 'null',
30+
/* par2 */ JSON.stringify(tasker.locals), // Supply par2 to overwrite context
2831
);
2932
tasker.exit();
3033
}

src/tasker.js

Lines changed: 77 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,87 @@
1-
/* global local_keys */
1+
export const taskerUtilities = {
2+
inspect: (target) => {
3+
const cache = [];
4+
return JSON.stringify(target, function(key, value) {
5+
if (typeof value === 'object' && value !== null) {
6+
if (cache.indexOf(value) !== -1) {
7+
// Circular reference found, discard key
8+
return;
9+
}
10+
// Store value in our collection
11+
cache.push(value);
12+
}
13+
return value;
14+
});
15+
},
216

3-
var tasker = window;
4-
window.tasker = tasker;
17+
makeConsole: (context) => ({
18+
log(...params) {
19+
context.flash(
20+
params
21+
.map(param => (typeof param === 'string') ? param : taskerUtilities.inspect(param))
22+
.join(' ')
23+
);
24+
},
25+
}),
526

6-
// Injecting development functions
7-
tasker.inspect = (target) => {
8-
const cache = [];
9-
return JSON.stringify(target, function(key, value) {
10-
if (typeof value === 'object' && value !== null) {
11-
if (cache.indexOf(value) !== -1) {
12-
// Circular reference found, discard key
13-
return;
14-
}
15-
// Store value in our collection
16-
cache.push(value);
17-
}
18-
return value;
19-
});
20-
};
21-
tasker.console = {
22-
log(...params) {
23-
tasker.flash(
24-
params
25-
.map(param => (typeof param === 'string') ? param : tasker.inspect(param))
26-
.join(' ')
27-
);
27+
getParams: (context) => {
28+
return (context.par || [])
29+
.map((rawParam) => {
30+
// Test if param is a json
31+
let parsedParam;
32+
try {
33+
parsedParam = JSON.parse(rawParam); // will fail if param is not a JSON
34+
} catch (err) {
35+
parsedParam = rawParam;
36+
}
37+
return parsedParam === 'undefined' ? undefined : parsedParam;
38+
});
2839
},
29-
};
3040

31-
tasker.getParams = () => {
32-
return [
33-
tasker.local('par1'),
34-
tasker.local('par2'),
35-
]
36-
.map((rawParam) => {
37-
// Test if param is a json
38-
let parsedParam;
39-
try {
40-
parsedParam = JSON.parse(rawParam); // will fail if param is not a JSON
41-
} catch (err) {
42-
parsedParam = rawParam;
43-
}
44-
return parsedParam === 'undefined' ? undefined : parsedParam;
45-
});
46-
};
41+
getLocals: (context) => {
42+
const taskParameters = taskerUtilities.getParams(context);
4743

48-
// Attempt to restore param from upstream
49-
const localsJson = tasker.getParams()[0];
44+
// Handle overriding behaviour
45+
const par2 = taskParameters[1];
46+
const overridingLocals = ((par2 && (typeof par2 === 'object')) ? taskParameters[1] : null);
47+
if (overridingLocals) {
48+
return {
49+
par: (overridingLocals.par || []),
50+
caller: (overridingLocals.caller || []),
51+
...overridingLocals,
52+
};
53+
}
5054

51-
tasker.locals = ({
52-
caller: (typeof caller === 'undefined') ? [] : caller,
53-
...(
54-
((typeof local_keys === 'undefined') ? [] : local_keys)
55+
// Handle merging behaviour
56+
const par1 = taskParameters[0];
57+
const parentLocals = ((par1 && (typeof par1 === 'object')) ? par1 : {}) || {};
58+
const locals = (context.local_keys || [])
5559
.reduce((acc, key) => {
5660
const keyName = key.slice(1);
57-
acc[keyName] = tasker.local(keyName);
61+
acc[keyName] = context.local(keyName);
5862
return acc;
59-
}, {})
60-
),
61-
...((typeof localsJson === 'object') ? localsJson : {}),
62-
});
63+
}, {});
64+
65+
66+
return ({
67+
...locals,
68+
...parentLocals,
69+
par: taskParameters,
70+
caller: [
71+
...(context.caller || []),
72+
...(parentLocals.caller || []),
73+
],
74+
})
75+
},
76+
};
77+
78+
export const initializeTaskerJs = (context) => {
79+
// Injecting development functions
80+
context.inspect = taskerUtilities.inspect;
81+
context.console = taskerUtilities.makeConsole(context);
82+
83+
// Attempt to restore param from upstream
84+
context.locals = taskerUtilities.getLocals(context)
6385

64-
export default tasker;
86+
return context;
87+
}

tasker-imports/TJS_RunScript.tsk.xml

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,18 @@
1-
<TaskerData sr="" dvi="1" tv="5.1m">
2-
<Task sr="task58">
1+
<TaskerData sr="" dvi="1" tv="5.7.2">
2+
<Task sr="task29">
33
<cdate>1514855272770</cdate>
4-
<edate>1519573311612</edate>
5-
<id>58</id>
4+
<edate>1558890701302</edate>
5+
<id>29</id>
66
<nme>TJS:RunScript</nme>
7-
<pri>6</pri>
87
<rty>2</rty>
98
<Action sr="act0" ve="7">
10-
<code>547</code>
11-
<label>Allow local_keys to be passed down by other function</label>
12-
<Str sr="arg0" ve="3">%local_keys</Str>
13-
<Str sr="arg1" ve="3">%par1</Str>
14-
<Int sr="arg2" val="0"/>
15-
<Int sr="arg3" val="0"/>
16-
<Int sr="arg4" val="0"/>
17-
<ConditionList sr="if">
18-
<Condition sr="c0" ve="3">
19-
<lhs>%par1</lhs>
20-
<op>12</op>
21-
<rhs></rhs>
22-
</Condition>
23-
</ConditionList>
24-
</Action>
25-
<Action sr="act1" ve="7">
269
<code>347</code>
10+
<label>Allow local_keys to be passed down by other function</label>
2711
<Int sr="arg0" val="4"/>
2812
<Str sr="arg1" ve="3"/>
2913
<Str sr="arg2" ve="3">%local_keys</Str>
30-
<ConditionList sr="if">
31-
<Condition sr="c0" ve="3">
32-
<lhs>%par1</lhs>
33-
<op>13</op>
34-
<rhs></rhs>
35-
</Condition>
36-
</ConditionList>
3714
</Action>
38-
<Action sr="act2" ve="7">
15+
<Action sr="act1" ve="7">
3916
<code>131</code>
4017
<se>false</se>
4118
<Str sr="arg0" ve="3">%TJS_LOCAL_PATH</Str>
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import test from 'ava';
2+
import { taskerUtilities } from '../../../src/tasker';
3+
4+
class Context {
5+
constructor(context) {
6+
Object.keys(context).forEach(key => this[key] = context[key]);
7+
}
8+
9+
local(name) {
10+
return this[name];
11+
}
12+
}
13+
14+
test('should output a minimal locals containing caller and par', t => {
15+
const actual = taskerUtilities.getLocals(
16+
new Context({})
17+
);
18+
19+
t.deepEqual(actual, {
20+
caller: [],
21+
par: [],
22+
})
23+
});
24+
25+
test('should merge own locals with parent\'s locals', t => {
26+
const parentLocal = JSON.stringify({
27+
localA: 'localA',
28+
localB: 'localB',
29+
conflictA: 'parentConflicA',
30+
});
31+
const actual = taskerUtilities.getLocals(
32+
new Context({
33+
caller: ['caller3', 'caller2', 'caller1'],
34+
par: [
35+
{
36+
localA: 'localA',
37+
localB: 'localB',
38+
conflictA: 'parentConflicA',
39+
},
40+
],
41+
conflictA: 'selfConflicA',
42+
})
43+
);
44+
45+
t.deepEqual(actual, {
46+
caller: ['caller3', 'caller2', 'caller1'],
47+
par: [
48+
JSON.parse(parentLocal),
49+
],
50+
localA: 'localA',
51+
localB: 'localB',
52+
conflictA: 'parentConflicA',
53+
})
54+
});
55+
56+
test('should skip parent\'s locals if it is null', t => {
57+
const parentLocal = null;
58+
const actual = taskerUtilities.getLocals(
59+
new Context({
60+
caller: ['caller3', 'caller2', 'caller1'],
61+
par: [
62+
parentLocal,
63+
],
64+
})
65+
);
66+
67+
t.deepEqual(actual, {
68+
caller: ['caller3', 'caller2', 'caller1'],
69+
par: [
70+
null,
71+
],
72+
})
73+
});
74+
75+
test('should skip parent\'s locals if it is not an JSON string', t => {
76+
const parentLocal = "INVALID: PARENT";
77+
const actual = taskerUtilities.getLocals(
78+
new Context({
79+
caller: ['caller3', 'caller2', 'caller1'],
80+
par: [
81+
parentLocal,
82+
],
83+
})
84+
);
85+
86+
t.deepEqual(actual, {
87+
caller: ['caller3', 'caller2', 'caller1'],
88+
par: [
89+
parentLocal,
90+
],
91+
})
92+
});
93+
94+
test('should ignore own locals with par2 is provided', t => {
95+
const overridingLocal = JSON.stringify({
96+
caller: [
97+
'OverridingCaller2',
98+
'OverridingCaller1'
99+
],
100+
});
101+
const actual = taskerUtilities.getLocals(
102+
new Context({
103+
caller: ['caller3', 'caller2', 'caller1'],
104+
par: [
105+
'null',
106+
overridingLocal,
107+
],
108+
})
109+
);
110+
111+
t.deepEqual(actual, {
112+
caller: [
113+
'OverridingCaller2',
114+
'OverridingCaller1'
115+
],
116+
par: [],
117+
})
118+
});

0 commit comments

Comments
 (0)