@hero-design/snowflake-guard 1.4.10 → 1.4.12

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.
Files changed (61) hide show
  1. package/package.json +2 -2
  2. package/lib/src/__tests__/parseMobileSource.spec.d.ts +0 -1
  3. package/lib/src/__tests__/parseMobileSource.spec.js +0 -417
  4. package/lib/src/__tests__/parseSource.spec.d.ts +0 -1
  5. package/lib/src/__tests__/parseSource.spec.js +0 -207
  6. package/lib/src/graphql/__tests__/fetchGrapql.spec.d.ts +0 -1
  7. package/lib/src/graphql/__tests__/fetchGrapql.spec.js +0 -33
  8. package/lib/src/graphql/__tests__/queryGenerators.spec.d.ts +0 -1
  9. package/lib/src/graphql/__tests__/queryGenerators.spec.js +0 -82
  10. package/lib/src/graphql/fetchGraphql.d.ts +0 -2
  11. package/lib/src/graphql/fetchGraphql.js +0 -23
  12. package/lib/src/graphql/queryGenerators.d.ts +0 -18
  13. package/lib/src/graphql/queryGenerators.js +0 -61
  14. package/lib/src/graphql/types.d.ts +0 -18
  15. package/lib/src/graphql/types.js +0 -2
  16. package/lib/src/index.d.ts +0 -3
  17. package/lib/src/index.js +0 -175
  18. package/lib/src/parseMobileSource.d.ts +0 -15
  19. package/lib/src/parseMobileSource.js +0 -135
  20. package/lib/src/parseSource.d.ts +0 -17
  21. package/lib/src/parseSource.js +0 -138
  22. package/lib/src/parsers/flow.d.ts +0 -3
  23. package/lib/src/parsers/flow.js +0 -47
  24. package/lib/src/parsers/typescript.d.ts +0 -3
  25. package/lib/src/parsers/typescript.js +0 -47
  26. package/lib/src/reports/__tests__/reportInlineStyle.spec.d.ts +0 -1
  27. package/lib/src/reports/__tests__/reportInlineStyle.spec.js +0 -143
  28. package/lib/src/reports/constants.d.ts +0 -233
  29. package/lib/src/reports/constants.js +0 -917
  30. package/lib/src/reports/mobile/__tests__/reportCustomStyleProperties.spec.d.ts +0 -1
  31. package/lib/src/reports/mobile/__tests__/reportCustomStyleProperties.spec.js +0 -144
  32. package/lib/src/reports/mobile/__tests__/reportInlineStyle.spec.d.ts +0 -1
  33. package/lib/src/reports/mobile/__tests__/reportInlineStyle.spec.js +0 -113
  34. package/lib/src/reports/mobile/__tests__/reportStyledComponents.spec.d.ts +0 -1
  35. package/lib/src/reports/mobile/__tests__/reportStyledComponents.spec.js +0 -54
  36. package/lib/src/reports/mobile/constants.d.ts +0 -106
  37. package/lib/src/reports/mobile/constants.js +0 -470
  38. package/lib/src/reports/mobile/reportCustomStyleProperties.d.ts +0 -24
  39. package/lib/src/reports/mobile/reportCustomStyleProperties.js +0 -193
  40. package/lib/src/reports/mobile/reportInlineStyle.d.ts +0 -20
  41. package/lib/src/reports/mobile/reportInlineStyle.js +0 -223
  42. package/lib/src/reports/mobile/reportStyledComponents.d.ts +0 -6
  43. package/lib/src/reports/mobile/reportStyledComponents.js +0 -105
  44. package/lib/src/reports/mobile/testUtils.d.ts +0 -1
  45. package/lib/src/reports/mobile/testUtils.js +0 -42
  46. package/lib/src/reports/mobile/types.d.ts +0 -3
  47. package/lib/src/reports/mobile/types.js +0 -2
  48. package/lib/src/reports/reportClassName.d.ts +0 -3
  49. package/lib/src/reports/reportClassName.js +0 -12
  50. package/lib/src/reports/reportCustomStyleProperties.d.ts +0 -25
  51. package/lib/src/reports/reportCustomStyleProperties.js +0 -185
  52. package/lib/src/reports/reportInlineStyle.d.ts +0 -23
  53. package/lib/src/reports/reportInlineStyle.js +0 -238
  54. package/lib/src/reports/reportStyledComponents.d.ts +0 -6
  55. package/lib/src/reports/reportStyledComponents.js +0 -105
  56. package/lib/src/reports/types.d.ts +0 -3
  57. package/lib/src/reports/types.js +0 -2
  58. package/lib/src/utils/__tests__/getDiffLocs.spec.d.ts +0 -1
  59. package/lib/src/utils/__tests__/getDiffLocs.spec.js +0 -43
  60. package/lib/src/utils/getDiffLocs.d.ts +0 -3
  61. package/lib/src/utils/getDiffLocs.js +0 -40
@@ -1,238 +0,0 @@
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
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- const recast = __importStar(require("recast"));
37
- const constants_1 = require("./constants");
38
- const BLACKLIST_PROPERTIES = {
39
- style: constants_1.RULESET_MAP,
40
- sx: constants_1.SX_RULESET_MAP,
41
- };
42
- const INLINE_STYLE_PROPERTIES = ['style', 'sx'];
43
- const ADDITIONAL_PROPERTIES = ['variant']; // Add any additional props you want to track
44
- const addViolatingAttribute = (prop, styleObjName, componentName, loc, violatingAttributes) => {
45
- if (prop.key.type !== 'Identifier') {
46
- return;
47
- }
48
- violatingAttributes.push({
49
- attributeName: prop.key.name,
50
- attributeValue: recast.print(prop.value).code,
51
- inlineStyleProps: styleObjName,
52
- componentName,
53
- loc,
54
- });
55
- };
56
- const getPropValue = (attr) => {
57
- var _a;
58
- if (!attr.value) {
59
- return ''; // Handle case where value is missing
60
- }
61
- if (typeof attr.value === 'string') {
62
- return attr.value; // Directly return string value
63
- }
64
- if (((_a = attr.value) === null || _a === void 0 ? void 0 : _a.type) === 'JSXExpressionContainer') {
65
- return recast.print(attr.value.expression).code;
66
- }
67
- // Use recast to print the expression if it's not a simple string
68
- return recast.print(attr.value).code;
69
- };
70
- const reportInlineStyle = (ast, attributes, componentName) => {
71
- const locs = {};
72
- const violatingAttributes = [];
73
- const additionalProps = [];
74
- let hasCustomStyle = false;
75
- let styleObjName;
76
- attributes.forEach((attr) => {
77
- var _a;
78
- if (attr.type !== 'JSXAttribute') {
79
- return;
80
- }
81
- if (typeof attr.name.name !== 'string') {
82
- return;
83
- }
84
- if (ADDITIONAL_PROPERTIES.includes(attr.name.name)) {
85
- // Handle expression container like `style={{ ... }}`
86
- additionalProps.push({
87
- propName: attr.name.name,
88
- propValue: getPropValue(attr), // Print expression as string
89
- });
90
- }
91
- if (((_a = attr.value) === null || _a === void 0 ? void 0 : _a.type) !== 'JSXExpressionContainer') {
92
- return;
93
- }
94
- if (INLINE_STYLE_PROPERTIES.includes(attr.name.name)) {
95
- styleObjName = attr.name.name;
96
- const { expression } = attr.value;
97
- if (expression.type === 'ObjectExpression') {
98
- expression.properties.forEach((prop) => {
99
- var _a;
100
- // Case 1: Use direct object, e.g. <Card style={{ color: 'red' }} />
101
- if (prop.type === 'ObjectProperty' &&
102
- prop.key.type === 'Identifier' &&
103
- BLACKLIST_PROPERTIES[styleObjName][componentName].includes(prop.key.name)) {
104
- hasCustomStyle = true;
105
- addViolatingAttribute(prop, styleObjName, componentName, (_a = attr.loc) === null || _a === void 0 ? void 0 : _a.start.line, violatingAttributes);
106
- }
107
- // Case 2: Use spread operator, e.g. <Card style={{ ...customStyle }} />
108
- if (prop.type === 'SpreadElement' &&
109
- prop.argument.type === 'Identifier') {
110
- const variableName = prop.argument.name;
111
- recast.visit(ast, {
112
- visitVariableDeclaration(path) {
113
- var _a;
114
- this.traverse(path);
115
- const declaration = path.value
116
- .declarations[0];
117
- if (declaration.id.type === 'Identifier' &&
118
- declaration.id.name === variableName &&
119
- ((_a = declaration.init) === null || _a === void 0 ? void 0 : _a.type) === 'ObjectExpression') {
120
- declaration.init.properties.forEach((deProp) => {
121
- var _a;
122
- if (deProp.type === 'ObjectProperty' &&
123
- deProp.key.type === 'Identifier' &&
124
- BLACKLIST_PROPERTIES[styleObjName][componentName].includes(deProp.key.name)) {
125
- hasCustomStyle = true;
126
- addViolatingAttribute(deProp, styleObjName, componentName, (_a = attr.loc) === null || _a === void 0 ? void 0 : _a.start.line, violatingAttributes);
127
- }
128
- });
129
- }
130
- },
131
- });
132
- }
133
- // Case 3: Use spread operator with variable's property, e.g. <Card style={{ ...customStyle.tileCard }} />
134
- if (prop.type === 'SpreadElement' &&
135
- prop.argument.type === 'MemberExpression' &&
136
- prop.argument.object.type === 'Identifier' &&
137
- prop.argument.property.type === 'Identifier') {
138
- const variableName = prop.argument.object.name;
139
- const propName = prop.argument.property.name;
140
- recast.visit(ast, {
141
- visitVariableDeclaration(path) {
142
- var _a;
143
- this.traverse(path);
144
- const declaration = path.value
145
- .declarations[0];
146
- if (declaration.id.type === 'Identifier' &&
147
- declaration.id.name === variableName &&
148
- ((_a = declaration.init) === null || _a === void 0 ? void 0 : _a.type) === 'ObjectExpression') {
149
- declaration.init.properties.forEach((deProp) => {
150
- if (deProp.type === 'ObjectProperty' &&
151
- deProp.key.type === 'Identifier' &&
152
- deProp.key.name === propName &&
153
- deProp.value.type === 'ObjectExpression') {
154
- deProp.value.properties.forEach((p) => {
155
- var _a;
156
- if (p.type === 'ObjectProperty' &&
157
- p.key.type === 'Identifier' &&
158
- BLACKLIST_PROPERTIES[styleObjName][componentName].includes(p.key.name)) {
159
- hasCustomStyle = true;
160
- addViolatingAttribute(p, styleObjName, componentName, (_a = attr.loc) === null || _a === void 0 ? void 0 : _a.start.line, violatingAttributes);
161
- }
162
- });
163
- }
164
- });
165
- }
166
- },
167
- });
168
- }
169
- });
170
- }
171
- // Case 4: Use variable, e.g. <Card style={customStyle} />
172
- if (expression.type === 'Identifier') {
173
- const variableName = expression.name;
174
- recast.visit(ast, {
175
- visitVariableDeclaration(path) {
176
- var _a;
177
- this.traverse(path);
178
- const declaration = path.value
179
- .declarations[0];
180
- if (declaration.id.type === 'Identifier' &&
181
- declaration.id.name === variableName &&
182
- ((_a = declaration.init) === null || _a === void 0 ? void 0 : _a.type) === 'ObjectExpression') {
183
- declaration.init.properties.forEach((prop) => {
184
- var _a;
185
- if (prop.type === 'ObjectProperty' &&
186
- prop.key.type === 'Identifier' &&
187
- BLACKLIST_PROPERTIES[styleObjName][componentName].includes(prop.key.name)) {
188
- hasCustomStyle = true;
189
- addViolatingAttribute(prop, styleObjName, componentName, (_a = attr.loc) === null || _a === void 0 ? void 0 : _a.start.line, violatingAttributes);
190
- }
191
- });
192
- }
193
- },
194
- });
195
- }
196
- // Case 5: Use variable's property, e.g. <Card style={customStyle.tileCard} />
197
- if (expression.type === 'MemberExpression' &&
198
- expression.object.type === 'Identifier' &&
199
- expression.property.type === 'Identifier') {
200
- const objectName = expression.object.name;
201
- const propName = expression.property.name;
202
- recast.visit(ast, {
203
- visitVariableDeclaration(path) {
204
- var _a;
205
- this.traverse(path);
206
- const declaration = path.value
207
- .declarations[0];
208
- if (declaration.id.type === 'Identifier' &&
209
- declaration.id.name === objectName &&
210
- ((_a = declaration.init) === null || _a === void 0 ? void 0 : _a.type) === 'ObjectExpression') {
211
- declaration.init.properties.forEach((prop) => {
212
- if (prop.type === 'ObjectProperty' &&
213
- prop.key.type === 'Identifier' &&
214
- prop.key.name === propName &&
215
- prop.value.type === 'ObjectExpression') {
216
- prop.value.properties.forEach((p) => {
217
- var _a;
218
- if (p.type === 'ObjectProperty' &&
219
- p.key.type === 'Identifier' &&
220
- BLACKLIST_PROPERTIES[styleObjName][componentName].includes(p.key.name)) {
221
- hasCustomStyle = true;
222
- addViolatingAttribute(p, styleObjName, componentName, (_a = attr.loc) === null || _a === void 0 ? void 0 : _a.start.line, violatingAttributes);
223
- }
224
- });
225
- }
226
- });
227
- }
228
- },
229
- });
230
- }
231
- if (hasCustomStyle && attr.loc) {
232
- locs[styleObjName] = attr.loc.start.line;
233
- }
234
- }
235
- });
236
- return { locs, violatingAttributes, additionalProps };
237
- };
238
- exports.default = reportInlineStyle;
@@ -1,6 +0,0 @@
1
- import * as recast from 'recast';
2
- import type { ComponentName } from './types';
3
- declare const reportStyledComponents: (ast: recast.types.ASTNode, componentList: {
4
- [k: string]: ComponentName;
5
- }, styledAliasName: string) => number[];
6
- export default reportStyledComponents;
@@ -1,105 +0,0 @@
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
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- const recast = __importStar(require("recast"));
37
- const reportStyledComponents = (ast, componentList, styledAliasName) => {
38
- const locs = [];
39
- const localComponentList = Object.keys(componentList);
40
- recast.visit(ast, {
41
- visitVariableDeclaration(path) {
42
- this.traverse(path);
43
- const declaration = path.value
44
- .declarations[0];
45
- if (declaration.init &&
46
- declaration.init.type === 'TaggedTemplateExpression') {
47
- const { tag } = declaration.init;
48
- if (tag.type === 'CallExpression' &&
49
- tag.callee.type === 'Identifier' &&
50
- tag.callee.name === styledAliasName) {
51
- const arg = tag.arguments[0];
52
- // Case 1: Custom default component, e.g. styled(Card)
53
- if (arg.type === 'Identifier' &&
54
- localComponentList.includes(arg.name) &&
55
- tag.loc) {
56
- locs.push(tag.loc.start.line);
57
- }
58
- // Case 2: Custom compound component, e.g. styled(Card.Header)
59
- if (arg.type === 'MemberExpression' &&
60
- arg.object.type === 'Identifier' &&
61
- localComponentList.includes(arg.object.name) &&
62
- tag.loc) {
63
- locs.push(tag.loc.start.line);
64
- }
65
- }
66
- }
67
- // Case 3: Custom compound component with spead operator. e.g. const { Header } = Card, then styled(Header)
68
- if (declaration.init &&
69
- declaration.init.type === 'Identifier' &&
70
- localComponentList.includes(declaration.init.name)) {
71
- const { id } = declaration;
72
- if (id.type === 'ObjectPattern') {
73
- const compoundComponentNames = id.properties
74
- .map((prop) => prop.type === 'ObjectProperty' && prop.key.type === 'Identifier'
75
- ? prop.key.name
76
- : null)
77
- .filter((name) => name !== null);
78
- recast.visit(ast, {
79
- visitVariableDeclaration(spreadPath) {
80
- this.traverse(spreadPath);
81
- const spreadDeclaration = spreadPath.value
82
- .declarations[0];
83
- if (spreadDeclaration.init &&
84
- spreadDeclaration.init.type === 'TaggedTemplateExpression') {
85
- const { tag } = spreadDeclaration.init;
86
- if (tag.type === 'CallExpression' &&
87
- tag.callee.type === 'Identifier' &&
88
- tag.callee.name === styledAliasName) {
89
- const arg = tag.arguments[0];
90
- if (arg.type === 'Identifier' &&
91
- compoundComponentNames.includes(arg.name) &&
92
- tag.loc) {
93
- locs.push(tag.loc.start.line);
94
- }
95
- }
96
- }
97
- },
98
- });
99
- }
100
- }
101
- },
102
- });
103
- return locs;
104
- };
105
- exports.default = reportStyledComponents;
@@ -1,3 +0,0 @@
1
- import type { HD_COMPONENTS, RULESET_MAP } from './constants';
2
- export type ComponentName = typeof HD_COMPONENTS[number];
3
- export type CompoundComponentName = keyof typeof RULESET_MAP;
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1 +0,0 @@
1
- export {};
@@ -1,43 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const getDiffLocs_1 = require("../getDiffLocs");
4
- describe('getDiffLocs', () => {
5
- it('returns diff locations from patches', () => {
6
- const filePatch = "@@ -4,8 +4,6 @@ import { Button, Typography, Box, ButtonProps } from '@hero-design/react';\n" +
7
- ' \n' +
8
- " import emptyBanner from './assets/empty-banner.png';\n" +
9
- ' \n' +
10
- "-console.log('test');\n" +
11
- '-\n' +
12
- ' const EmptyImg = styled.img`\n' +
13
- ' height: 172px;\n' +
14
- ` margin-bottom: \${({ theme }) => theme.space.small}px;\n` +
15
- '@@ -28,7 +26,8 @@ const EmptyTableView = ({\n' +
16
- ' <EmptyImg src={emptyBanner} alt="Empty" />\n' +
17
- ' <Typography.Text\n' +
18
- ' fontSize={14}\n' +
19
- "- sx={{ color: 'bodyText', mb: 'xxlarge', whiteSpace: 'pre-wrap' }} // @snowflake-guard/snowflake-approved-by-andromeda\n" +
20
- "+ sx={{ color: 'bodyText', mb: 'xxlarge', whiteSpace: 'pre-wrap', backgroundColour: 'lightPrimary' }} // @snowflake-guard/snowflake-approved-by-andromeda\n" +
21
- '+ aria-label="Empty table message"\n' +
22
- ' >\n' +
23
- ' {message}\n' +
24
- ' </Typography.Text>\n' +
25
- '@@ -39,6 +38,7 @@ const EmptyTableView = ({\n' +
26
- ' text={buttonText}\n' +
27
- ' />\n' +
28
- ' </Box>\n' +
29
- '+\n' +
30
- ' );\n' +
31
- ' \n' +
32
- ' export default EmptyTableView;';
33
- expect((0, getDiffLocs_1.getDiffLocs)(filePatch)).toEqual([
34
- [7, 6],
35
- [29, 30],
36
- [41, 41],
37
- ]);
38
- });
39
- it('returns empty for empty patches', () => {
40
- const filePatch = '';
41
- expect((0, getDiffLocs_1.getDiffLocs)(filePatch)).toEqual([]);
42
- });
43
- });
@@ -1,3 +0,0 @@
1
- export type DiffLocs = [number, number][];
2
- declare const getDiffLocs: (filePatch: string) => DiffLocs;
3
- export { getDiffLocs };
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getDiffLocs = void 0;
4
- const DIFF_LOCS_REGEX = /@@(.*)@@/g;
5
- const getDiffLocs = (filePatch) => {
6
- const locs = [];
7
- const patches = {};
8
- if (!filePatch) {
9
- return locs;
10
- }
11
- // Split file patch into lines
12
- const splitPatch = filePatch.split('\n');
13
- // Get patches
14
- // Example: @@ -1,2 +1,3 @@
15
- let tempPatch = '';
16
- splitPatch.forEach((linePatch) => {
17
- const matchPatch = linePatch.match(DIFF_LOCS_REGEX);
18
- if (matchPatch) {
19
- [tempPatch] = matchPatch[0].split('+')[1].split(' ');
20
- patches[tempPatch] = [];
21
- }
22
- else {
23
- patches[tempPatch].push(linePatch);
24
- }
25
- });
26
- // Get diff locations from patches
27
- Object.entries(patches).forEach(([loc, lines]) => {
28
- const [startLoc, numberOfLines] = loc
29
- .split(',')
30
- .map((l) => parseInt(l, 10));
31
- const endLoc = startLoc + numberOfLines - 1;
32
- const firstDiffLineIdx = lines.findIndex((l) => l.startsWith('+') || l.startsWith('-'));
33
- const lastDiffLineIdx = lines
34
- .reverse()
35
- .findIndex((l) => l.startsWith('+') || l.startsWith('-'));
36
- locs.push([startLoc + firstDiffLineIdx, endLoc - lastDiffLineIdx]);
37
- });
38
- return locs;
39
- };
40
- exports.getDiffLocs = getDiffLocs;