@hero-design/snowflake-guard 1.0.7-alpha0
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/.dockerignore +12 -0
- package/.env.example +9 -0
- package/.eslintrc.js +8 -0
- package/CHANGELOG.md +47 -0
- package/Dockerfile +8 -0
- package/LICENSE +15 -0
- package/README.md +33 -0
- package/app.yml +137 -0
- package/jest.config.js +9 -0
- package/lib/netlify/functions/snowflake.d.ts +2 -0
- package/lib/netlify/functions/snowflake.js +10 -0
- package/lib/src/__mocks__/sourceSample.d.ts +2 -0
- package/lib/src/__mocks__/sourceSample.js +27 -0
- package/lib/src/__tests__/parseSource.spec.d.ts +1 -0
- package/lib/src/__tests__/parseSource.spec.js +41 -0
- package/lib/src/index.d.ts +3 -0
- package/lib/src/index.js +142 -0
- package/lib/src/parseSource.d.ts +7 -0
- package/lib/src/parseSource.js +102 -0
- package/lib/src/parsers/typescript.d.ts +3 -0
- package/lib/src/parsers/typescript.js +37 -0
- package/lib/src/reports/constants.d.ts +215 -0
- package/lib/src/reports/constants.js +848 -0
- package/lib/src/reports/reportClassName.d.ts +3 -0
- package/lib/src/reports/reportClassName.js +15 -0
- package/lib/src/reports/reportCustomStyleProperties.d.ts +10 -0
- package/lib/src/reports/reportCustomStyleProperties.js +109 -0
- package/lib/src/reports/reportInlineStyle.d.ts +7 -0
- package/lib/src/reports/reportInlineStyle.js +179 -0
- package/lib/src/reports/reportStyledComponents.d.ts +6 -0
- package/lib/src/reports/reportStyledComponents.js +95 -0
- package/lib/src/reports/types.d.ts +3 -0
- package/lib/src/reports/types.js +2 -0
- package/lib/src/test.tsx +123 -0
- package/netlify/functions/snowflake.ts +9 -0
- package/netlify.toml +21 -0
- package/package.json +44 -0
- package/src/__mocks__/sourceSample.tsx +67 -0
- package/src/__tests__/parseSource.spec.ts +15 -0
- package/src/index.ts +201 -0
- package/src/parseSource.ts +97 -0
- package/src/parsers/typescript.ts +8 -0
- package/src/reports/constants.ts +965 -0
- package/src/reports/reportClassName.ts +20 -0
- package/src/reports/reportCustomStyleProperties.ts +125 -0
- package/src/reports/reportInlineStyle.ts +221 -0
- package/src/reports/reportStyledComponents.ts +109 -0
- package/src/reports/types.ts +5 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const reportClassName = (attributes) => {
|
|
4
|
+
const locs = [];
|
|
5
|
+
attributes.forEach((attr) => {
|
|
6
|
+
if (attr.type === 'JSXAttribute' &&
|
|
7
|
+
attr.name.type === 'JSXIdentifier' &&
|
|
8
|
+
attr.name.name === 'className' &&
|
|
9
|
+
attr.loc) {
|
|
10
|
+
locs.push(attr.loc.start.line);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
return locs;
|
|
14
|
+
};
|
|
15
|
+
exports.default = reportClassName;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as recast from 'recast';
|
|
2
|
+
import type { ComponentName } from './types';
|
|
3
|
+
declare const reportCustomProperties: (ast: recast.types.ASTNode, componentList: {
|
|
4
|
+
[k: string]: "Alert" | "Badge" | "Banner" | "Breadcrumb" | "Button" | "Card" | "Carousel" | "Chart" | "Checkbox" | "Collapse" | "Comment" | "ContextPanel" | "DatePicker" | "Divider" | "Dropdown" | "Empty" | "File" | "Filters" | "Form" | "Grid" | "Icon" | "InPageNavigation" | "Input" | "MediaQuery" | "Menu" | "Modal" | "Notification" | "PageHeader" | "Pagination" | "Portal" | "Portlet" | "Progress" | "Radio" | "Rate" | "Result" | "Select" | "SelectButton" | "SideBar" | "Slider" | "Spinner" | "Statistic" | "Steps" | "Switch" | "Table" | "Tabs" | "Tag" | "TagInput" | "TimePicker" | "Timeline" | "Tooltip" | "Typography" | "Widget";
|
|
5
|
+
}) => {
|
|
6
|
+
className: number[];
|
|
7
|
+
style: number[];
|
|
8
|
+
sx: number[];
|
|
9
|
+
};
|
|
10
|
+
export default reportCustomProperties;
|
|
@@ -0,0 +1,109 @@
|
|
|
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 (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
const recast = __importStar(require("recast"));
|
|
30
|
+
const reportClassName_1 = __importDefault(require("./reportClassName"));
|
|
31
|
+
const reportInlineStyle_1 = __importDefault(require("./reportInlineStyle"));
|
|
32
|
+
const reportCustomProperties = (ast, componentList) => {
|
|
33
|
+
const locs = {
|
|
34
|
+
className: [],
|
|
35
|
+
style: [],
|
|
36
|
+
sx: [],
|
|
37
|
+
};
|
|
38
|
+
const localComponentList = Object.keys(componentList);
|
|
39
|
+
recast.visit(ast, {
|
|
40
|
+
visitJSXOpeningElement(path) {
|
|
41
|
+
this.traverse(path);
|
|
42
|
+
// Case 1: Custom default component, e.g. <Card />
|
|
43
|
+
if (path.value.name.type === 'JSXIdentifier' &&
|
|
44
|
+
localComponentList.includes(path.value.name.name)) {
|
|
45
|
+
const attributes = path.value
|
|
46
|
+
.attributes;
|
|
47
|
+
const styleObjectLocs = (0, reportInlineStyle_1.default)(ast, attributes, componentList[path.value.name.name]);
|
|
48
|
+
locs.className = [...locs.className, ...(0, reportClassName_1.default)(attributes)];
|
|
49
|
+
locs.style = [...locs.style, ...styleObjectLocs.style];
|
|
50
|
+
locs.sx = [...locs.sx, ...styleObjectLocs.sx];
|
|
51
|
+
}
|
|
52
|
+
// Case 2: Custom compound component, e.g. <Card.Header />
|
|
53
|
+
if (path.value.name.type === 'JSXMemberExpression' &&
|
|
54
|
+
localComponentList.includes(path.value.name.object.name)) {
|
|
55
|
+
const compoundComponentName = [
|
|
56
|
+
componentList[path.value.name.object.name],
|
|
57
|
+
path.value.name.property.name,
|
|
58
|
+
].join('.');
|
|
59
|
+
const attributes = path.value
|
|
60
|
+
.attributes;
|
|
61
|
+
const styleObjectLocs = (0, reportInlineStyle_1.default)(ast, attributes, compoundComponentName);
|
|
62
|
+
locs.className = [...locs.className, ...(0, reportClassName_1.default)(attributes)];
|
|
63
|
+
locs.style = [...locs.style, ...styleObjectLocs.style];
|
|
64
|
+
locs.sx = [...locs.sx, ...styleObjectLocs.sx];
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
// Case 3: Custom compound component with spead operator. e.g. const { Header } = Card, then <Header />
|
|
68
|
+
visitVariableDeclaration(path) {
|
|
69
|
+
this.traverse(path);
|
|
70
|
+
const declaration = path.value
|
|
71
|
+
.declarations[0];
|
|
72
|
+
if (declaration.init &&
|
|
73
|
+
declaration.init.type === 'Identifier' &&
|
|
74
|
+
localComponentList.includes(declaration.init.name)) {
|
|
75
|
+
const componentName = declaration.init.name;
|
|
76
|
+
const { id } = declaration;
|
|
77
|
+
if (id.type === 'ObjectPattern') {
|
|
78
|
+
const compoundComponentNames = id.properties
|
|
79
|
+
.map((prop) => prop.type === 'ObjectProperty' && prop.key.type === 'Identifier'
|
|
80
|
+
? prop.key.name
|
|
81
|
+
: null)
|
|
82
|
+
.filter((name) => name !== null);
|
|
83
|
+
recast.visit(ast, {
|
|
84
|
+
visitJSXOpeningElement(openPath) {
|
|
85
|
+
this.traverse(openPath);
|
|
86
|
+
if (openPath.value.name.type === 'JSXIdentifier' &&
|
|
87
|
+
compoundComponentNames.includes(openPath.value.name.name)) {
|
|
88
|
+
const compoundComponentName = [
|
|
89
|
+
componentList[componentName],
|
|
90
|
+
openPath.value.name.name,
|
|
91
|
+
].join('.');
|
|
92
|
+
const { attributes } = openPath.value;
|
|
93
|
+
const styleObjectLocs = (0, reportInlineStyle_1.default)(ast, attributes, compoundComponentName);
|
|
94
|
+
locs.className = [
|
|
95
|
+
...locs.className,
|
|
96
|
+
...(0, reportClassName_1.default)(attributes),
|
|
97
|
+
];
|
|
98
|
+
locs.style = [...locs.style, ...styleObjectLocs.style];
|
|
99
|
+
locs.sx = [...locs.sx, ...styleObjectLocs.sx];
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
return locs;
|
|
108
|
+
};
|
|
109
|
+
exports.default = reportCustomProperties;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as recast from 'recast';
|
|
2
|
+
import type { CompoundComponentName } from './types';
|
|
3
|
+
declare const reportInlineStyle: (ast: recast.types.ASTNode, attributes: recast.types.namedTypes.JSXAttribute[], componentName: CompoundComponentName) => {
|
|
4
|
+
style: number[];
|
|
5
|
+
sx: number[];
|
|
6
|
+
};
|
|
7
|
+
export default reportInlineStyle;
|
|
@@ -0,0 +1,179 @@
|
|
|
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 (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
const recast = __importStar(require("recast"));
|
|
27
|
+
const constants_1 = require("./constants");
|
|
28
|
+
const BLACKLIST_PROPERTIES = {
|
|
29
|
+
style: constants_1.RULESET_MAP,
|
|
30
|
+
sx: constants_1.SX_RULESET_MAP,
|
|
31
|
+
};
|
|
32
|
+
const INLINE_STYLE_PROPERTIES = ['style', 'sx'];
|
|
33
|
+
const reportInlineStyle = (ast, attributes, componentName) => {
|
|
34
|
+
const locs = {
|
|
35
|
+
style: [],
|
|
36
|
+
sx: [],
|
|
37
|
+
};
|
|
38
|
+
let hasCustomStyle = false;
|
|
39
|
+
let styleObjName;
|
|
40
|
+
attributes.forEach((attr) => {
|
|
41
|
+
var _a;
|
|
42
|
+
if (attr.type === 'JSXAttribute' &&
|
|
43
|
+
typeof attr.name.name === 'string' &&
|
|
44
|
+
INLINE_STYLE_PROPERTIES.includes(attr.name.name) &&
|
|
45
|
+
((_a = attr.value) === null || _a === void 0 ? void 0 : _a.type) === 'JSXExpressionContainer') {
|
|
46
|
+
styleObjName = attr.name.name;
|
|
47
|
+
const { expression } = attr.value;
|
|
48
|
+
if (expression.type === 'ObjectExpression') {
|
|
49
|
+
expression.properties.forEach((prop) => {
|
|
50
|
+
// Case 1: Use direct object, e.g. <Card style={{ color: 'red' }} />
|
|
51
|
+
if (prop.type === 'ObjectProperty' &&
|
|
52
|
+
prop.key.type === 'Identifier' &&
|
|
53
|
+
BLACKLIST_PROPERTIES[styleObjName][componentName].includes(prop.key.name)) {
|
|
54
|
+
hasCustomStyle = true;
|
|
55
|
+
}
|
|
56
|
+
// Case 2: Use spread operator, e.g. <Card style={{ ...customStyle }} />
|
|
57
|
+
if (prop.type === 'SpreadElement' &&
|
|
58
|
+
prop.argument.type === 'Identifier') {
|
|
59
|
+
const variableName = prop.argument.name;
|
|
60
|
+
recast.visit(ast, {
|
|
61
|
+
visitVariableDeclaration(path) {
|
|
62
|
+
var _a;
|
|
63
|
+
this.traverse(path);
|
|
64
|
+
const declaration = path.value
|
|
65
|
+
.declarations[0];
|
|
66
|
+
if (declaration.id.type === 'Identifier' &&
|
|
67
|
+
declaration.id.name === variableName &&
|
|
68
|
+
((_a = declaration.init) === null || _a === void 0 ? void 0 : _a.type) === 'ObjectExpression') {
|
|
69
|
+
declaration.init.properties.forEach((deProp) => {
|
|
70
|
+
if (deProp.type === 'ObjectProperty' &&
|
|
71
|
+
deProp.key.type === 'Identifier' &&
|
|
72
|
+
BLACKLIST_PROPERTIES[styleObjName][componentName].includes(deProp.key.name)) {
|
|
73
|
+
hasCustomStyle = true;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// Case 3: Use spread operator with variable's property, e.g. <Card style={{ ...customStyle.tileCard }} />
|
|
81
|
+
if (prop.type === 'SpreadElement' &&
|
|
82
|
+
prop.argument.type === 'MemberExpression' &&
|
|
83
|
+
prop.argument.object.type === 'Identifier' &&
|
|
84
|
+
prop.argument.property.type === 'Identifier') {
|
|
85
|
+
const variableName = prop.argument.object.name;
|
|
86
|
+
const propName = prop.argument.property.name;
|
|
87
|
+
recast.visit(ast, {
|
|
88
|
+
visitVariableDeclaration(path) {
|
|
89
|
+
var _a;
|
|
90
|
+
this.traverse(path);
|
|
91
|
+
const declaration = path.value
|
|
92
|
+
.declarations[0];
|
|
93
|
+
if (declaration.id.type === 'Identifier' &&
|
|
94
|
+
declaration.id.name === variableName &&
|
|
95
|
+
((_a = declaration.init) === null || _a === void 0 ? void 0 : _a.type) === 'ObjectExpression') {
|
|
96
|
+
declaration.init.properties.forEach((deProp) => {
|
|
97
|
+
if (deProp.type === 'ObjectProperty' &&
|
|
98
|
+
deProp.key.type === 'Identifier' &&
|
|
99
|
+
deProp.key.name === propName &&
|
|
100
|
+
deProp.value.type === 'ObjectExpression') {
|
|
101
|
+
deProp.value.properties.forEach((p) => {
|
|
102
|
+
if (p.type === 'ObjectProperty' &&
|
|
103
|
+
p.key.type === 'Identifier' &&
|
|
104
|
+
BLACKLIST_PROPERTIES[styleObjName][componentName].includes(p.key.name)) {
|
|
105
|
+
hasCustomStyle = true;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// Case 4: Use variable, e.g. <Card style={customStyle} />
|
|
117
|
+
if (expression.type === 'Identifier') {
|
|
118
|
+
const variableName = expression.name;
|
|
119
|
+
recast.visit(ast, {
|
|
120
|
+
visitVariableDeclaration(path) {
|
|
121
|
+
var _a;
|
|
122
|
+
this.traverse(path);
|
|
123
|
+
const declaration = path.value
|
|
124
|
+
.declarations[0];
|
|
125
|
+
if (declaration.id.type === 'Identifier' &&
|
|
126
|
+
declaration.id.name === variableName &&
|
|
127
|
+
((_a = declaration.init) === null || _a === void 0 ? void 0 : _a.type) === 'ObjectExpression') {
|
|
128
|
+
declaration.init.properties.forEach((prop) => {
|
|
129
|
+
if (prop.type === 'ObjectProperty' &&
|
|
130
|
+
prop.key.type === 'Identifier' &&
|
|
131
|
+
BLACKLIST_PROPERTIES[styleObjName][componentName].includes(prop.key.name)) {
|
|
132
|
+
hasCustomStyle = true;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// Case 5: Use variable's property, e.g. <Card style={customStyle.tileCard} />
|
|
140
|
+
if (expression.type === 'MemberExpression' &&
|
|
141
|
+
expression.object.type === 'Identifier' &&
|
|
142
|
+
expression.property.type === 'Identifier') {
|
|
143
|
+
const objectName = expression.object.name;
|
|
144
|
+
const propName = expression.property.name;
|
|
145
|
+
recast.visit(ast, {
|
|
146
|
+
visitVariableDeclaration(path) {
|
|
147
|
+
var _a;
|
|
148
|
+
this.traverse(path);
|
|
149
|
+
const declaration = path.value
|
|
150
|
+
.declarations[0];
|
|
151
|
+
if (declaration.id.type === 'Identifier' &&
|
|
152
|
+
declaration.id.name === objectName &&
|
|
153
|
+
((_a = declaration.init) === null || _a === void 0 ? void 0 : _a.type) === 'ObjectExpression') {
|
|
154
|
+
declaration.init.properties.forEach((prop) => {
|
|
155
|
+
if (prop.type === 'ObjectProperty' &&
|
|
156
|
+
prop.key.type === 'Identifier' &&
|
|
157
|
+
prop.key.name === propName &&
|
|
158
|
+
prop.value.type === 'ObjectExpression') {
|
|
159
|
+
prop.value.properties.forEach((p) => {
|
|
160
|
+
if (p.type === 'ObjectProperty' &&
|
|
161
|
+
p.key.type === 'Identifier' &&
|
|
162
|
+
BLACKLIST_PROPERTIES[styleObjName][componentName].includes(p.key.name)) {
|
|
163
|
+
hasCustomStyle = true;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
if (hasCustomStyle && attr.loc) {
|
|
173
|
+
locs[styleObjName].push(attr.loc.start.line);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
return locs;
|
|
178
|
+
};
|
|
179
|
+
exports.default = reportInlineStyle;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as recast from 'recast';
|
|
2
|
+
import type { ComponentName } from './types';
|
|
3
|
+
declare const reportStyledComponents: (ast: recast.types.ASTNode, componentList: {
|
|
4
|
+
[k: string]: "Alert" | "Badge" | "Banner" | "Breadcrumb" | "Button" | "Card" | "Carousel" | "Chart" | "Checkbox" | "Collapse" | "Comment" | "ContextPanel" | "DatePicker" | "Divider" | "Dropdown" | "Empty" | "File" | "Filters" | "Form" | "Grid" | "Icon" | "InPageNavigation" | "Input" | "MediaQuery" | "Menu" | "Modal" | "Notification" | "PageHeader" | "Pagination" | "Portal" | "Portlet" | "Progress" | "Radio" | "Rate" | "Result" | "Select" | "SelectButton" | "SideBar" | "Slider" | "Spinner" | "Statistic" | "Steps" | "Switch" | "Table" | "Tabs" | "Tag" | "TagInput" | "TimePicker" | "Timeline" | "Tooltip" | "Typography" | "Widget";
|
|
5
|
+
}, styledAliasName: string) => number[];
|
|
6
|
+
export default reportStyledComponents;
|
|
@@ -0,0 +1,95 @@
|
|
|
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 (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
const recast = __importStar(require("recast"));
|
|
27
|
+
const reportStyledComponents = (ast, componentList, styledAliasName) => {
|
|
28
|
+
const locs = [];
|
|
29
|
+
const localComponentList = Object.keys(componentList);
|
|
30
|
+
recast.visit(ast, {
|
|
31
|
+
visitVariableDeclaration(path) {
|
|
32
|
+
this.traverse(path);
|
|
33
|
+
const declaration = path.value
|
|
34
|
+
.declarations[0];
|
|
35
|
+
if (declaration.init &&
|
|
36
|
+
declaration.init.type === 'TaggedTemplateExpression') {
|
|
37
|
+
const { tag } = declaration.init;
|
|
38
|
+
if (tag.type === 'CallExpression' &&
|
|
39
|
+
tag.callee.type === 'Identifier' &&
|
|
40
|
+
tag.callee.name === styledAliasName) {
|
|
41
|
+
const arg = tag.arguments[0];
|
|
42
|
+
// Case 1: Custom default component, e.g. styled(Card)
|
|
43
|
+
if (arg.type === 'Identifier' &&
|
|
44
|
+
localComponentList.includes(arg.name) &&
|
|
45
|
+
tag.loc) {
|
|
46
|
+
locs.push(tag.loc.start.line);
|
|
47
|
+
}
|
|
48
|
+
// Case 2: Custom compound component, e.g. styled(Card.Header)
|
|
49
|
+
if (arg.type === 'MemberExpression' &&
|
|
50
|
+
arg.object.type === 'Identifier' &&
|
|
51
|
+
localComponentList.includes(arg.object.name) &&
|
|
52
|
+
tag.loc) {
|
|
53
|
+
locs.push(tag.loc.start.line);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Case 3: Custom compound component with spead operator. e.g. const { Header } = Card, then styled(Header)
|
|
58
|
+
if (declaration.init &&
|
|
59
|
+
declaration.init.type === 'Identifier' &&
|
|
60
|
+
localComponentList.includes(declaration.init.name)) {
|
|
61
|
+
const { id } = declaration;
|
|
62
|
+
if (id.type === 'ObjectPattern') {
|
|
63
|
+
const compoundComponentNames = id.properties
|
|
64
|
+
.map((prop) => prop.type === 'ObjectProperty' && prop.key.type === 'Identifier'
|
|
65
|
+
? prop.key.name
|
|
66
|
+
: null)
|
|
67
|
+
.filter((name) => name !== null);
|
|
68
|
+
recast.visit(ast, {
|
|
69
|
+
visitVariableDeclaration(spreadPath) {
|
|
70
|
+
this.traverse(spreadPath);
|
|
71
|
+
const spreadDeclaration = spreadPath.value
|
|
72
|
+
.declarations[0];
|
|
73
|
+
if (spreadDeclaration.init &&
|
|
74
|
+
spreadDeclaration.init.type === 'TaggedTemplateExpression') {
|
|
75
|
+
const { tag } = spreadDeclaration.init;
|
|
76
|
+
if (tag.type === 'CallExpression' &&
|
|
77
|
+
tag.callee.type === 'Identifier' &&
|
|
78
|
+
tag.callee.name === styledAliasName) {
|
|
79
|
+
const arg = tag.arguments[0];
|
|
80
|
+
if (arg.type === 'Identifier' &&
|
|
81
|
+
compoundComponentNames.includes(arg.name) &&
|
|
82
|
+
tag.loc) {
|
|
83
|
+
locs.push(tag.loc.start.line);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
return locs;
|
|
94
|
+
};
|
|
95
|
+
exports.default = reportStyledComponents;
|
package/lib/src/test.tsx
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Intl } from 'redux-intl';
|
|
3
|
+
import { Button, Dropdown, Menu } from '@hero-design/react';
|
|
4
|
+
|
|
5
|
+
import { MODAL_NAMES } from './constants';
|
|
6
|
+
import { TRACK_PREVIEW_DOCUMENT } from '../../HrDocumentsTab/tracks';
|
|
7
|
+
|
|
8
|
+
const ActionDropdown = ({
|
|
9
|
+
additionalPropsForCustomComponents: {
|
|
10
|
+
updatingSelectContract,
|
|
11
|
+
selectContract,
|
|
12
|
+
selectedContractId,
|
|
13
|
+
track,
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
openModal,
|
|
17
|
+
rowData,
|
|
18
|
+
setCustomData,
|
|
19
|
+
value,
|
|
20
|
+
}: any) => {
|
|
21
|
+
const [open, setOpen] = React.useState(false);
|
|
22
|
+
const toggleDropdown = () => setOpen(!open);
|
|
23
|
+
const closeDropdown = () => setOpen(false);
|
|
24
|
+
const dropdownTarget = (
|
|
25
|
+
<Button
|
|
26
|
+
variant="text"
|
|
27
|
+
rightIcon="carat-down-small"
|
|
28
|
+
text={Intl.formatMessage({ id: 'actions' })}
|
|
29
|
+
onClick={toggleDropdown}
|
|
30
|
+
style={{ padding: 0, width: 110}}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
const dropdownContent = (
|
|
34
|
+
<Menu>
|
|
35
|
+
<Menu.Item
|
|
36
|
+
className="dropdown-item"
|
|
37
|
+
icon="eye-outlined"
|
|
38
|
+
text={Intl.formatMessage({ id: 'preview' })}
|
|
39
|
+
onClick={() => {
|
|
40
|
+
openModal(MODAL_NAMES.PREVIEW_TEMPLATE);
|
|
41
|
+
setCustomData(rowData);
|
|
42
|
+
closeDropdown();
|
|
43
|
+
track(TRACK_PREVIEW_DOCUMENT);
|
|
44
|
+
}}
|
|
45
|
+
/>
|
|
46
|
+
<Menu.Item
|
|
47
|
+
icon="enter-arrow"
|
|
48
|
+
text={Intl.formatMessage({ id: 'select' })}
|
|
49
|
+
disabled={updatingSelectContract || !!selectedContractId}
|
|
50
|
+
onClick={() => {
|
|
51
|
+
selectContract(value);
|
|
52
|
+
closeDropdown();
|
|
53
|
+
}}
|
|
54
|
+
sx={{ padding: 0, width: 100}}
|
|
55
|
+
/>
|
|
56
|
+
</Menu>
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Dropdown
|
|
61
|
+
open={open}
|
|
62
|
+
target={dropdownTarget}
|
|
63
|
+
content={dropdownContent}
|
|
64
|
+
onClose={closeDropdown}
|
|
65
|
+
/>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
import styled from 'styled-components';
|
|
70
|
+
import { Select } from '@hero-design/react';
|
|
71
|
+
|
|
72
|
+
import { mediaQueries } from '@ehrocks/hero-theme';
|
|
73
|
+
|
|
74
|
+
export const Body = styled.div`
|
|
75
|
+
text-align: left;
|
|
76
|
+
padding: ${({ theme }) => theme.space.xxlarge}px
|
|
77
|
+
${({ theme }) => theme.space.xxlarge}px 0
|
|
78
|
+
${({ theme }) => theme.space.xxlarge}px;
|
|
79
|
+
table tr td {
|
|
80
|
+
vertical-align: middle;
|
|
81
|
+
}
|
|
82
|
+
.search-select {
|
|
83
|
+
margin-bottom: ${({ theme }) => theme.space.medium}px;
|
|
84
|
+
div[data-popper-reference-hidden] {
|
|
85
|
+
${mediaQueries.sm} {
|
|
86
|
+
transform: translate(
|
|
87
|
+
${({ theme }) => theme.space.xxlarge}px,
|
|
88
|
+
241px
|
|
89
|
+
) !important;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
${mediaQueries.md} {
|
|
93
|
+
transform: translate(
|
|
94
|
+
${({ theme }) => theme.space.xxlarge}px,
|
|
95
|
+
219px
|
|
96
|
+
) !important;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
`;
|
|
101
|
+
|
|
102
|
+
export const StyledSelectField = styled(Select)`
|
|
103
|
+
width: calc(100% - 30px);
|
|
104
|
+
display: inline-block;
|
|
105
|
+
padding: 50px;
|
|
106
|
+
`;
|
|
107
|
+
|
|
108
|
+
export const StyledRemove = styled.a`
|
|
109
|
+
display: inline-block;
|
|
110
|
+
width: 30px;
|
|
111
|
+
text-align: right;
|
|
112
|
+
vertical-align: top;
|
|
113
|
+
height: 36px;
|
|
114
|
+
line-height: 36px;
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
export const ROLE_OPTIONS = [
|
|
118
|
+
{ value: 'employee', text: 'Employee' },
|
|
119
|
+
{ value: 'employer', text: 'Admin' },
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
export default ActionDropdown;
|
package/netlify.toml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# example netlify.toml
|
|
2
|
+
[build]
|
|
3
|
+
command = "# no build command"
|
|
4
|
+
functions = "packages/snowflake-guard/netlify/functions"
|
|
5
|
+
publish = "packages/snowflake-guard/lib"
|
|
6
|
+
|
|
7
|
+
## Uncomment to use this redirect for Single Page Applications like create-react-app.
|
|
8
|
+
## Not needed for static site generators.
|
|
9
|
+
#[[redirects]]
|
|
10
|
+
# from = "/*"
|
|
11
|
+
# to = "/index.html"
|
|
12
|
+
# status = 200
|
|
13
|
+
|
|
14
|
+
## (optional) Settings for Netlify Dev
|
|
15
|
+
## https://github.com/netlify/cli/blob/main/docs/netlify-dev.md#project-detection
|
|
16
|
+
#[dev]
|
|
17
|
+
# command = "yarn start" # Command to start your dev server
|
|
18
|
+
# port = 3000 # Port that the dev server will be listening on
|
|
19
|
+
# publish = "dist" # Folder with the static content for _redirect file
|
|
20
|
+
|
|
21
|
+
## more info on configuring this file: https://ntl.fyi/file-based-build-config
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hero-design/snowflake-guard",
|
|
3
|
+
"version": "1.0.7-alpha0",
|
|
4
|
+
"description": "A hero-design bot detecting snowflake usage",
|
|
5
|
+
"author": "Hau Dao",
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"main": "lib/src/parseSource.js",
|
|
8
|
+
"types": "lib/src/parseSource.d.ts",
|
|
9
|
+
"homepage": "https://github.com//",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"probot",
|
|
12
|
+
"github",
|
|
13
|
+
"probot-app"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"start": "probot run ./lib/src/index.js",
|
|
18
|
+
"test": "jest --passWithNoTests",
|
|
19
|
+
"deploy": "netlify deploy --site snowflake-guard.netlify.app --prod --auth $NETLIFY_AUTH_TOKEN",
|
|
20
|
+
"publish:npm": "yarn publish --access public"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@babel/parser": "^7.24.7",
|
|
24
|
+
"@probot/adapter-aws-lambda-serverless": "^3.0.4",
|
|
25
|
+
"probot": "^12.2.4",
|
|
26
|
+
"recast": "^0.23.9"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/jest": "^29.0.0",
|
|
30
|
+
"@types/node": "^18.0.0",
|
|
31
|
+
"config-tsconfig": "8.42.4",
|
|
32
|
+
"eslint-config-hd": "8.42.4",
|
|
33
|
+
"jest": "^29.0.0",
|
|
34
|
+
"nock": "^13.0.5",
|
|
35
|
+
"prettier-config-hd": "8.42.4",
|
|
36
|
+
"smee-client": "^1.2.2",
|
|
37
|
+
"ts-jest": "^29.0.0",
|
|
38
|
+
"typescript": "^4.1.3"
|
|
39
|
+
},
|
|
40
|
+
"prettier": "prettier-config-hd",
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">= 10.13.0"
|
|
43
|
+
}
|
|
44
|
+
}
|