@hero-design/snowflake-guard 1.0.11 → 1.0.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.
- package/package.json +6 -1
- package/.dockerignore +0 -12
- package/.env.example +0 -9
- package/.eslintrc.js +0 -8
- package/.turbo/turbo-build.log +0 -0
- package/CHANGELOG.md +0 -71
- package/Dockerfile +0 -8
- package/app.yml +0 -137
- package/jest.config.js +0 -9
- package/lib/netlify/functions/snowflake.d.ts +0 -2
- package/lib/netlify/functions/snowflake.js +0 -10
- package/lib/tsconfig.tsbuildinfo +0 -1
- package/netlify/functions/snowflake.ts +0 -9
- package/netlify.toml +0 -21
- package/src/__mocks__/sourceSample.tsx +0 -69
- package/src/__tests__/parseSource.spec.ts +0 -16
- package/src/graphql/__tests__/fetchGrapql.spec.ts +0 -26
- package/src/graphql/__tests__/queryGenerators.spec.ts +0 -97
- package/src/graphql/fetchGraphql.ts +0 -13
- package/src/graphql/queryGenerators.ts +0 -91
- package/src/graphql/types.ts +0 -19
- package/src/index.ts +0 -208
- package/src/parseSource.ts +0 -115
- package/src/parsers/typescript.ts +0 -8
- package/src/reports/constants.ts +0 -972
- package/src/reports/reportClassName.ts +0 -20
- package/src/reports/reportCustomStyleProperties.ts +0 -125
- package/src/reports/reportInlineStyle.ts +0 -221
- package/src/reports/reportStyledComponents.ts +0 -109
- package/src/reports/types.ts +0 -5
- package/src/utils/__tests__/getDiffLocs.spec.ts +0 -40
- package/src/utils/getDiffLocs.ts +0 -44
- package/tsconfig.json +0 -14
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
generateFetchReportQuery,
|
|
3
|
-
generateCreateReportQuery,
|
|
4
|
-
generateUpdateReportQuery,
|
|
5
|
-
} from '../queryGenerators';
|
|
6
|
-
|
|
7
|
-
const replaceWhiteSpace = (str: string) => str.replace(/\s/g, '');
|
|
8
|
-
|
|
9
|
-
describe('generateFetchReportQuery', () => {
|
|
10
|
-
it('returns correct query', () => {
|
|
11
|
-
const query = generateFetchReportQuery({
|
|
12
|
-
repoName: 'repoName',
|
|
13
|
-
prNumber: 123,
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
expect(replaceWhiteSpace(query)).toBe(
|
|
17
|
-
replaceWhiteSpace(`
|
|
18
|
-
query {
|
|
19
|
-
fetchHdSnowflakeGuardReport(repoName: "repoName", prNumber: 123) {
|
|
20
|
-
id
|
|
21
|
-
originalCount
|
|
22
|
-
latestCount
|
|
23
|
-
approvedCount
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
`)
|
|
27
|
-
);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe('generateCreateReportQuery', () => {
|
|
32
|
-
it('returns correct query', () => {
|
|
33
|
-
const query = generateCreateReportQuery({
|
|
34
|
-
repoName: 'repoName',
|
|
35
|
-
prNumber: 123,
|
|
36
|
-
owner: 'owner',
|
|
37
|
-
originalCount: 3,
|
|
38
|
-
latestCount: 1,
|
|
39
|
-
approvedCount: 2,
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
expect(replaceWhiteSpace(query)).toBe(
|
|
43
|
-
replaceWhiteSpace(`
|
|
44
|
-
mutation {
|
|
45
|
-
createHdSnowflakeGuardReport(
|
|
46
|
-
input: {
|
|
47
|
-
params: {
|
|
48
|
-
repoName: "repoName"
|
|
49
|
-
prNumber: 123
|
|
50
|
-
owner: "owner"
|
|
51
|
-
originalCount: 3
|
|
52
|
-
latestCount: 1
|
|
53
|
-
approvedCount: 2
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
) {
|
|
57
|
-
hdSnowflakeGuardReport {
|
|
58
|
-
id
|
|
59
|
-
repoName
|
|
60
|
-
prNumber
|
|
61
|
-
originalCount
|
|
62
|
-
latestCount
|
|
63
|
-
approvedCount
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
`)
|
|
68
|
-
);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
describe('generateUpdateReportQuery', () => {
|
|
73
|
-
it('returns correct query', () => {
|
|
74
|
-
const query = generateUpdateReportQuery({
|
|
75
|
-
id: 'id',
|
|
76
|
-
latestCount: 1,
|
|
77
|
-
approvedCount: 2,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
expect(replaceWhiteSpace(query)).toBe(
|
|
81
|
-
replaceWhiteSpace(`
|
|
82
|
-
mutation {
|
|
83
|
-
updateHdSnowflakeGuardReport(
|
|
84
|
-
input: { id: "id", latestCount: 1, approvedCount: 2 }
|
|
85
|
-
) {
|
|
86
|
-
hdSnowflakeGuardReport {
|
|
87
|
-
id
|
|
88
|
-
latestCount
|
|
89
|
-
originalCount
|
|
90
|
-
approvedCount
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
`)
|
|
95
|
-
);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
const fetchGraphql = async (query: string) => {
|
|
2
|
-
const host = process.env.DB_HOST || 'http://localhost:3000';
|
|
3
|
-
return fetch(`${host}/graphql`, {
|
|
4
|
-
method: 'POST',
|
|
5
|
-
headers: {
|
|
6
|
-
'Content-Type': 'application/json',
|
|
7
|
-
'Snowflake-Guard-Auth': process.env.SNOWFLAKE_GUARD_SECRET || '',
|
|
8
|
-
},
|
|
9
|
-
body: JSON.stringify({ query }),
|
|
10
|
-
}).then((response) => response.json());
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export default fetchGraphql;
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
const generateFetchReportQuery = ({
|
|
2
|
-
repoName,
|
|
3
|
-
prNumber,
|
|
4
|
-
}: {
|
|
5
|
-
repoName: string;
|
|
6
|
-
prNumber: number;
|
|
7
|
-
}) => {
|
|
8
|
-
return `
|
|
9
|
-
query {
|
|
10
|
-
fetchHdSnowflakeGuardReport(repoName: "${repoName}", prNumber: ${prNumber}) {
|
|
11
|
-
id
|
|
12
|
-
originalCount
|
|
13
|
-
latestCount
|
|
14
|
-
approvedCount
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
`;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const generateCreateReportQuery = ({
|
|
21
|
-
repoName,
|
|
22
|
-
prNumber,
|
|
23
|
-
owner,
|
|
24
|
-
originalCount,
|
|
25
|
-
latestCount,
|
|
26
|
-
approvedCount,
|
|
27
|
-
}: {
|
|
28
|
-
repoName: string;
|
|
29
|
-
prNumber: number;
|
|
30
|
-
owner: string;
|
|
31
|
-
originalCount: number;
|
|
32
|
-
latestCount: number;
|
|
33
|
-
approvedCount: number;
|
|
34
|
-
}) => {
|
|
35
|
-
return `
|
|
36
|
-
mutation {
|
|
37
|
-
createHdSnowflakeGuardReport(
|
|
38
|
-
input: {
|
|
39
|
-
params: {
|
|
40
|
-
repoName: "${repoName}"
|
|
41
|
-
prNumber: ${prNumber}
|
|
42
|
-
owner: "${owner}"
|
|
43
|
-
originalCount: ${originalCount}
|
|
44
|
-
latestCount: ${latestCount}
|
|
45
|
-
approvedCount: ${approvedCount}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
) {
|
|
49
|
-
hdSnowflakeGuardReport {
|
|
50
|
-
id
|
|
51
|
-
repoName
|
|
52
|
-
prNumber
|
|
53
|
-
originalCount
|
|
54
|
-
latestCount
|
|
55
|
-
approvedCount
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
`;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const generateUpdateReportQuery = ({
|
|
63
|
-
id,
|
|
64
|
-
latestCount,
|
|
65
|
-
approvedCount,
|
|
66
|
-
}: {
|
|
67
|
-
id: string;
|
|
68
|
-
latestCount: number;
|
|
69
|
-
approvedCount: number;
|
|
70
|
-
}) => {
|
|
71
|
-
return `
|
|
72
|
-
mutation {
|
|
73
|
-
updateHdSnowflakeGuardReport(
|
|
74
|
-
input: { id: "${id}", latestCount: ${latestCount}, approvedCount: ${approvedCount} }
|
|
75
|
-
) {
|
|
76
|
-
hdSnowflakeGuardReport {
|
|
77
|
-
id
|
|
78
|
-
latestCount
|
|
79
|
-
originalCount
|
|
80
|
-
approvedCount
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
`;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export {
|
|
88
|
-
generateFetchReportQuery,
|
|
89
|
-
generateCreateReportQuery,
|
|
90
|
-
generateUpdateReportQuery,
|
|
91
|
-
};
|
package/src/graphql/types.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export type Report = {
|
|
2
|
-
id: string;
|
|
3
|
-
repoName: string;
|
|
4
|
-
prNumber: number;
|
|
5
|
-
owner: string;
|
|
6
|
-
originalCount: number;
|
|
7
|
-
latestCount: number;
|
|
8
|
-
approvedCount: number;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export type FetchReportResponse = {
|
|
12
|
-
errors: { message: string }[];
|
|
13
|
-
data: null | {
|
|
14
|
-
fetchHdSnowflakeGuardReport: Pick<
|
|
15
|
-
Report,
|
|
16
|
-
'id' | 'originalCount' | 'latestCount' | 'approvedCount'
|
|
17
|
-
>;
|
|
18
|
-
};
|
|
19
|
-
};
|
package/src/index.ts
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { Probot } from 'probot';
|
|
2
|
-
import parseSource from './parseSource';
|
|
3
|
-
import { APPROVED_CLASSNAME_COMMENT } from './reports/constants';
|
|
4
|
-
import fetchGraphql from './graphql/fetchGraphql';
|
|
5
|
-
import {
|
|
6
|
-
generateFetchReportQuery,
|
|
7
|
-
generateUpdateReportQuery,
|
|
8
|
-
generateCreateReportQuery,
|
|
9
|
-
} from './graphql/queryGenerators';
|
|
10
|
-
import type { FetchReportResponse } from './graphql/types';
|
|
11
|
-
import { getDiffLocs } from './utils/getDiffLocs';
|
|
12
|
-
import type { DiffLocs } from './utils/getDiffLocs';
|
|
13
|
-
|
|
14
|
-
type Comment = {
|
|
15
|
-
path: string;
|
|
16
|
-
body: string;
|
|
17
|
-
line: number;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const TSX_REGEX = /\.tsx$/;
|
|
21
|
-
const TEST_REGEX = /__tests__/;
|
|
22
|
-
|
|
23
|
-
const SNOWFLAKE_COMMENTS = {
|
|
24
|
-
style:
|
|
25
|
-
'Snowflake detected! A component is customized using inline styles. Make sure to not use [prohibited CSS properties](https://docs.google.com/spreadsheets/d/1Dj8vqLdFaf-CSaSVoYqyYZIkGqF6OoyP7K4G1_9L62U/edit?usp=sharing).',
|
|
26
|
-
sx: 'Snowflake detected! A component is customized via sx prop. Make sure to not use [prohibited CSS properties](https://docs.google.com/spreadsheets/d/1Dj8vqLdFaf-CSaSVoYqyYZIkGqF6OoyP7K4G1_9L62U/edit?usp=sharing).',
|
|
27
|
-
'styled-component':
|
|
28
|
-
'Please do not use styled-component to customize this component, use sx prop or inline style instead.',
|
|
29
|
-
className: `Please make sure that this className is not used as a CSS classname for component customization purposes, use sx prop or inline style instead. In case this is none-css classname, please flag it with this comment \`${APPROVED_CLASSNAME_COMMENT}\`.`,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const checkIfDetectedSnowflakesInDiff = (
|
|
33
|
-
diffLocs: DiffLocs,
|
|
34
|
-
locToComment: number
|
|
35
|
-
) => {
|
|
36
|
-
const locIdx = diffLocs.findIndex(([start, end]) => {
|
|
37
|
-
return locToComment >= start && locToComment <= end;
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return locIdx !== -1;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export = (app: Probot) => {
|
|
44
|
-
app.on(
|
|
45
|
-
['pull_request.opened', 'pull_request.synchronize'],
|
|
46
|
-
async (context) => {
|
|
47
|
-
// Get PR info
|
|
48
|
-
const prNumber = context.payload.number;
|
|
49
|
-
const repoInfo = {
|
|
50
|
-
repo: context.payload.repository.name,
|
|
51
|
-
owner: context.payload.repository.owner.login,
|
|
52
|
-
};
|
|
53
|
-
const prBranch = context.payload.pull_request.head.ref;
|
|
54
|
-
|
|
55
|
-
// List all changed files
|
|
56
|
-
const prFiles = await context.octokit.pulls.listFiles({
|
|
57
|
-
...repoInfo,
|
|
58
|
-
pull_number: prNumber,
|
|
59
|
-
});
|
|
60
|
-
const tsxFiles = prFiles.data.filter(
|
|
61
|
-
(file) =>
|
|
62
|
-
TSX_REGEX.test(file.filename) &&
|
|
63
|
-
!TEST_REGEX.test(file.filename) &&
|
|
64
|
-
file.status !== 'removed'
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
// Saving file patches to get diff locations
|
|
68
|
-
const prFilePatches = tsxFiles.reduce((acc, file) => {
|
|
69
|
-
acc[file.filename] = file.patch || '';
|
|
70
|
-
return acc;
|
|
71
|
-
}, {} as { [key: string]: string });
|
|
72
|
-
|
|
73
|
-
// Get file contents
|
|
74
|
-
const prFileContentPromises = tsxFiles.map((file) =>
|
|
75
|
-
context.octokit.repos.getContent({
|
|
76
|
-
...repoInfo,
|
|
77
|
-
path: file.filename,
|
|
78
|
-
ref: prBranch,
|
|
79
|
-
})
|
|
80
|
-
);
|
|
81
|
-
const prFileContents = await Promise.all(prFileContentPromises);
|
|
82
|
-
|
|
83
|
-
const snowflakeComments: Comment[] = [];
|
|
84
|
-
const approvedSnowflakeLocs: number[] = [];
|
|
85
|
-
|
|
86
|
-
prFileContents.forEach(async (file) => {
|
|
87
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
88
|
-
// @ts-ignore
|
|
89
|
-
const filePath = file.data.path;
|
|
90
|
-
const diffLocs = getDiffLocs(prFilePatches[filePath]);
|
|
91
|
-
|
|
92
|
-
const stringContent = Buffer.from(
|
|
93
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
94
|
-
// @ts-ignore
|
|
95
|
-
file.data.content,
|
|
96
|
-
'base64'
|
|
97
|
-
).toString();
|
|
98
|
-
|
|
99
|
-
// Parse file content to check for snowflakes
|
|
100
|
-
const snowflakeReport = parseSource(stringContent);
|
|
101
|
-
|
|
102
|
-
snowflakeReport.styleLocs.forEach((loc) => {
|
|
103
|
-
if (checkIfDetectedSnowflakesInDiff(diffLocs, loc)) {
|
|
104
|
-
snowflakeComments.push({
|
|
105
|
-
path: filePath,
|
|
106
|
-
body: SNOWFLAKE_COMMENTS['style'],
|
|
107
|
-
line: loc,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
snowflakeReport.sxLocs.forEach((loc) => {
|
|
113
|
-
if (checkIfDetectedSnowflakesInDiff(diffLocs, loc)) {
|
|
114
|
-
snowflakeComments.push({
|
|
115
|
-
path: filePath,
|
|
116
|
-
body: SNOWFLAKE_COMMENTS['sx'],
|
|
117
|
-
line: loc,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
snowflakeReport.styledComponentLocs.forEach((loc) => {
|
|
123
|
-
if (checkIfDetectedSnowflakesInDiff(diffLocs, loc)) {
|
|
124
|
-
snowflakeComments.push({
|
|
125
|
-
path: filePath,
|
|
126
|
-
body: SNOWFLAKE_COMMENTS['styled-component'],
|
|
127
|
-
line: loc,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
snowflakeReport.classNameLocs.forEach((loc) => {
|
|
133
|
-
if (checkIfDetectedSnowflakesInDiff(diffLocs, loc)) {
|
|
134
|
-
snowflakeComments.push({
|
|
135
|
-
path: filePath,
|
|
136
|
-
body: SNOWFLAKE_COMMENTS['className'],
|
|
137
|
-
line: loc,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
snowflakeReport.approvedLocs.forEach((loc) => {
|
|
143
|
-
if (checkIfDetectedSnowflakesInDiff(diffLocs, loc)) {
|
|
144
|
-
approvedSnowflakeLocs.push(loc);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// Saving report
|
|
150
|
-
const snowflakeCount = snowflakeComments.length;
|
|
151
|
-
const report = (await fetchGraphql(
|
|
152
|
-
generateFetchReportQuery({ repoName: repoInfo.repo, prNumber })
|
|
153
|
-
)) as FetchReportResponse;
|
|
154
|
-
const reportData = report.data?.fetchHdSnowflakeGuardReport;
|
|
155
|
-
if (reportData) {
|
|
156
|
-
await fetchGraphql(
|
|
157
|
-
generateUpdateReportQuery({
|
|
158
|
-
id: reportData.id,
|
|
159
|
-
latestCount: snowflakeCount,
|
|
160
|
-
approvedCount: approvedSnowflakeLocs.length,
|
|
161
|
-
})
|
|
162
|
-
);
|
|
163
|
-
} else {
|
|
164
|
-
await fetchGraphql(
|
|
165
|
-
generateCreateReportQuery({
|
|
166
|
-
repoName: repoInfo.repo,
|
|
167
|
-
prNumber,
|
|
168
|
-
owner: repoInfo.owner,
|
|
169
|
-
originalCount: snowflakeCount,
|
|
170
|
-
latestCount: snowflakeCount,
|
|
171
|
-
approvedCount: approvedSnowflakeLocs.length,
|
|
172
|
-
})
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// No snowflakes detected
|
|
177
|
-
// Create success check-run
|
|
178
|
-
if (snowflakeCount === 0) {
|
|
179
|
-
return context.octokit.checks.create({
|
|
180
|
-
...repoInfo,
|
|
181
|
-
name: 'SnowflakeGuard/Check',
|
|
182
|
-
head_sha: context.payload.pull_request.head.sha,
|
|
183
|
-
status: 'completed',
|
|
184
|
-
conclusion: 'success',
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Snowflakes detected
|
|
189
|
-
// Create failed check-run & comment
|
|
190
|
-
await context.octokit.checks.create({
|
|
191
|
-
...repoInfo,
|
|
192
|
-
name: 'SnowflakeGuard/Check',
|
|
193
|
-
head_sha: context.payload.pull_request.head.sha,
|
|
194
|
-
status: 'completed',
|
|
195
|
-
conclusion: 'failure',
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
return context.octokit.pulls.createReview({
|
|
199
|
-
...repoInfo,
|
|
200
|
-
pull_number: prNumber,
|
|
201
|
-
commit_id: context.payload.pull_request.head.sha,
|
|
202
|
-
event: 'COMMENT',
|
|
203
|
-
body: 'Snowflake Guard Bot has detected some snowflakes in this PR. Please review the following comments.',
|
|
204
|
-
comments: snowflakeComments,
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
);
|
|
208
|
-
};
|
package/src/parseSource.ts
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import * as recast from 'recast';
|
|
2
|
-
import * as tsParser from './parsers/typescript';
|
|
3
|
-
import reportCustomProperties from './reports/reportCustomStyleProperties';
|
|
4
|
-
import reportStyledComponents from './reports/reportStyledComponents';
|
|
5
|
-
import {
|
|
6
|
-
HD_COMPONENTS,
|
|
7
|
-
APPROVED_COMMENT,
|
|
8
|
-
APPROVED_CLASSNAME_COMMENT,
|
|
9
|
-
} from './reports/constants';
|
|
10
|
-
import type { ComponentName } from './reports/types';
|
|
11
|
-
|
|
12
|
-
const parseSource = (source: string) => {
|
|
13
|
-
let hasHeroDesignImport = false;
|
|
14
|
-
let hasStyledComponentsImport = false;
|
|
15
|
-
|
|
16
|
-
const componentList: { [k: string]: ComponentName } = {};
|
|
17
|
-
let styledAliasName = 'styled';
|
|
18
|
-
|
|
19
|
-
let styledComponentLocs: number[] = [];
|
|
20
|
-
let classNameLocs: number[] = [];
|
|
21
|
-
let styleLocs: number[] = [];
|
|
22
|
-
let sxLocs: number[] = [];
|
|
23
|
-
const approvedCmtLocs: number[] = [];
|
|
24
|
-
const approvedClassnameLocs: number[] = [];
|
|
25
|
-
|
|
26
|
-
const ast = recast.parse(source, { parser: tsParser });
|
|
27
|
-
|
|
28
|
-
recast.visit(ast, {
|
|
29
|
-
visitImportDeclaration(path) {
|
|
30
|
-
this.traverse(path);
|
|
31
|
-
|
|
32
|
-
const importedFrom = path.value.source.value as string;
|
|
33
|
-
|
|
34
|
-
// Check if file imports components from '@hero-design/react'
|
|
35
|
-
if (importedFrom === '@hero-design/react') {
|
|
36
|
-
recast.visit(path.node, {
|
|
37
|
-
visitImportSpecifier(importPath) {
|
|
38
|
-
this.traverse(importPath);
|
|
39
|
-
|
|
40
|
-
if (HD_COMPONENTS.includes(importPath.value.imported.name)) {
|
|
41
|
-
componentList[importPath.value.local.name] =
|
|
42
|
-
importPath.value.imported.name;
|
|
43
|
-
hasHeroDesignImport = true;
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Check if file imports from 'styled-components'
|
|
50
|
-
if (importedFrom === 'styled-components') {
|
|
51
|
-
recast.visit(path.node, {
|
|
52
|
-
visitImportDefaultSpecifier(importPath) {
|
|
53
|
-
this.traverse(importPath);
|
|
54
|
-
|
|
55
|
-
styledAliasName = importPath.value.local.name;
|
|
56
|
-
hasStyledComponentsImport = true;
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
visitComment(path) {
|
|
63
|
-
this.traverse(path);
|
|
64
|
-
|
|
65
|
-
const comment = path.value.value as string;
|
|
66
|
-
if (comment.toLowerCase().includes(APPROVED_COMMENT.toLowerCase())) {
|
|
67
|
-
approvedCmtLocs.push(path.value.loc.start.line);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (
|
|
71
|
-
comment.toLowerCase().includes(APPROVED_CLASSNAME_COMMENT.toLowerCase())
|
|
72
|
-
) {
|
|
73
|
-
approvedClassnameLocs.push(path.value.loc.start.line);
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const isNotApprovedSnowflakes = (loc: number) =>
|
|
79
|
-
!approvedCmtLocs.includes(loc);
|
|
80
|
-
|
|
81
|
-
const isNotApprovedClassnameSnowflakes = (loc: number) =>
|
|
82
|
-
!approvedClassnameLocs.includes(loc);
|
|
83
|
-
|
|
84
|
-
if (hasHeroDesignImport) {
|
|
85
|
-
// Case 1: Using className to customise components
|
|
86
|
-
// Case 2: Using style object to customise components
|
|
87
|
-
// Case 3: Using sx object to customise components
|
|
88
|
-
const customPropLocs = reportCustomProperties(ast, componentList);
|
|
89
|
-
classNameLocs = customPropLocs.className.filter(
|
|
90
|
-
(loc) =>
|
|
91
|
-
isNotApprovedSnowflakes(loc) && isNotApprovedClassnameSnowflakes(loc)
|
|
92
|
-
);
|
|
93
|
-
styleLocs = customPropLocs.style.filter(isNotApprovedSnowflakes);
|
|
94
|
-
sxLocs = customPropLocs.sx.filter(isNotApprovedSnowflakes);
|
|
95
|
-
|
|
96
|
-
// Case 4: Using styled-components to customise components
|
|
97
|
-
if (hasStyledComponentsImport) {
|
|
98
|
-
styledComponentLocs = reportStyledComponents(
|
|
99
|
-
ast,
|
|
100
|
-
componentList,
|
|
101
|
-
styledAliasName
|
|
102
|
-
).filter(isNotApprovedSnowflakes);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
classNameLocs,
|
|
108
|
-
styleLocs,
|
|
109
|
-
sxLocs,
|
|
110
|
-
styledComponentLocs,
|
|
111
|
-
approvedLocs: [...approvedCmtLocs, ...approvedClassnameLocs],
|
|
112
|
-
};
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
export default parseSource;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import * as babelParser from '@babel/parser';
|
|
2
|
-
import getBabelOptions, { Overrides } from 'recast/parsers/_babel_options';
|
|
3
|
-
|
|
4
|
-
export const parse = (source: string, options?: Overrides) => {
|
|
5
|
-
const babelOptions = getBabelOptions(options);
|
|
6
|
-
babelOptions.plugins.push('jsx', 'typescript');
|
|
7
|
-
return babelParser.parse(source, babelOptions);
|
|
8
|
-
};
|