@upleveled/preflight 2.0.0 → 2.1.0-0
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/checks/stylelint.d.ts +3 -0
- package/dist/checks/stylelintConfigIsValid.d.ts +2 -0
- package/dist/preflight.esm.js +187 -113
- package/dist/preflight.esm.js.map +1 -1
- package/package.json +11 -9
- package/src/checks/eslint.ts +16 -17
- package/src/checks/eslintConfigIsValid.ts +2 -2
- package/src/checks/noDependencyProblems/noDependenciesWithoutTypes.ts +7 -0
- package/src/checks/prettier.ts +13 -7
- package/src/checks/stylelint.ts +48 -0
- package/src/checks/stylelintConfigIsValid.ts +92 -0
- package/src/index.ts +17 -2
package/dist/preflight.esm.js
CHANGED
|
@@ -2,6 +2,7 @@ import { Listr } from 'listr2';
|
|
|
2
2
|
import { promises, existsSync } from 'node:fs';
|
|
3
3
|
import { execaCommand } from 'execa';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
+
import path, { sep, dirname, relative } from 'node:path';
|
|
5
6
|
import { createRequire } from 'node:module';
|
|
6
7
|
import readdirp from 'readdirp';
|
|
7
8
|
import semver from 'semver';
|
|
@@ -11,11 +12,10 @@ import userAgents from 'top-user-agents';
|
|
|
11
12
|
import { URL, fileURLToPath } from 'node:url';
|
|
12
13
|
import algoliasearch from 'algoliasearch';
|
|
13
14
|
import pReduce from 'p-reduce';
|
|
14
|
-
import path, { dirname } from 'node:path';
|
|
15
15
|
import os from 'node:os';
|
|
16
16
|
|
|
17
|
+
// https://www.compart.com/en/unicode/U+2800
|
|
17
18
|
// eslint-disable-next-line security/detect-bidi-characters -- Intentional use of unusual character for formatting
|
|
18
|
-
|
|
19
19
|
const emptyBrailleCharacter = '';
|
|
20
20
|
function commandExample(command) {
|
|
21
21
|
return `${emptyBrailleCharacter} ${chalk.dim('$')} ${command}`;
|
|
@@ -36,15 +36,12 @@ async function allChangesCommittedToGit() {
|
|
|
36
36
|
stdout: replSlug
|
|
37
37
|
} = await execaCommand('echo $REPL_SLUG');
|
|
38
38
|
const isRunningInReplIt = replSlug !== '';
|
|
39
|
-
|
|
40
39
|
if (isRunningInReplIt) {
|
|
41
40
|
await promises.writeFile('.git/info/exclude', '.replit\n');
|
|
42
41
|
}
|
|
43
|
-
|
|
44
42
|
const {
|
|
45
43
|
stdout
|
|
46
44
|
} = await execaCommand('git status --porcelain');
|
|
47
|
-
|
|
48
45
|
if (stdout !== '') {
|
|
49
46
|
const onlyPnpmLockModifiedOnDrone = stdout.trim() === 'M pnpm-lock.yaml' && (await isDrone());
|
|
50
47
|
throw new Error(`Some changes have not been committed to Git:
|
|
@@ -63,44 +60,28 @@ var allChangesCommittedToGit$1 = {
|
|
|
63
60
|
'default': allChangesCommittedToGit
|
|
64
61
|
};
|
|
65
62
|
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
if (typeof input !== 'string') {
|
|
69
|
-
throw new TypeError(`Expected a \`string\`, got \`${typeof input}\``);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return input.replace(new RegExp(CRLF, 'g'), '\n');
|
|
73
|
-
}
|
|
74
|
-
|
|
63
|
+
const errorKey = 'errorCount';
|
|
64
|
+
const warningKey = 'warningCount';
|
|
75
65
|
const title$1 = 'ESLint';
|
|
76
66
|
async function eslintCheck() {
|
|
77
67
|
try {
|
|
78
|
-
await execaCommand('pnpm eslint . --max-warnings 0 --format
|
|
68
|
+
await execaCommand('pnpm eslint . --max-warnings 0 --format json');
|
|
79
69
|
} catch (error) {
|
|
80
70
|
const {
|
|
81
71
|
stdout
|
|
82
72
|
} = error;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (!/^\d+ problems?$/.test(lines[lines.length - 2])) {
|
|
73
|
+
// If no ESLint problems detected, throw the error
|
|
74
|
+
if (!new RegExp(`"${errorKey}":|"${warningKey}":`).test(stdout)) {
|
|
86
75
|
throw error;
|
|
87
76
|
}
|
|
88
|
-
|
|
89
77
|
throw new Error(`ESLint problems found in the following files:
|
|
90
|
-
${
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
})
|
|
97
|
-
.reduce((linesWithoutDuplicates, line) => {
|
|
98
|
-
if (line && !linesWithoutDuplicates.includes(line)) {
|
|
99
|
-
linesWithoutDuplicates.push(line);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return linesWithoutDuplicates;
|
|
103
|
-
}, []).join('\n')}
|
|
78
|
+
${JSON.parse(stdout).filter(eslintResult => !(eslintResult[errorKey] === 0 && eslintResult[warningKey] === 0))
|
|
79
|
+
// Make paths relative to the project:
|
|
80
|
+
// before: /home/projects/next-student-project/app/api/hello/route.js
|
|
81
|
+
// after: app/api/hello/route.js
|
|
82
|
+
.map(({
|
|
83
|
+
filePath
|
|
84
|
+
}) => filePath.replace(`${process.cwd()}${sep}`, '')).join('\n')}
|
|
104
85
|
|
|
105
86
|
Open these files in your editor - there should be problems to fix
|
|
106
87
|
`);
|
|
@@ -114,32 +95,25 @@ var eslint = {
|
|
|
114
95
|
};
|
|
115
96
|
|
|
116
97
|
const require$1 = /*#__PURE__*/createRequire(`${/*#__PURE__*/process.cwd()}/`);
|
|
117
|
-
|
|
118
98
|
const title$2 = 'ESLint config is latest version';
|
|
119
99
|
async function eslintConfigIsValid() {
|
|
120
100
|
const {
|
|
121
101
|
stdout: remoteVersion
|
|
122
102
|
} = await execaCommand('npm show eslint-config-upleveled version');
|
|
123
103
|
let localVersion;
|
|
124
|
-
|
|
125
104
|
try {
|
|
126
105
|
const eslintConfigPackageJsonPath = require$1.resolve('eslint-config-upleveled/package.json');
|
|
127
|
-
|
|
128
106
|
localVersion = JSON.parse(await promises.readFile(eslintConfigPackageJsonPath, 'utf-8')).version;
|
|
129
107
|
} catch (err) {}
|
|
130
|
-
|
|
131
108
|
if (typeof localVersion === 'undefined') {
|
|
132
109
|
throw new Error(`The UpLeveled ESLint Config has not been installed - please install using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
133
110
|
`);
|
|
134
111
|
}
|
|
135
|
-
|
|
136
112
|
if (semver.gt(remoteVersion, localVersion)) {
|
|
137
113
|
throw new Error(`Your current version of the UpLeveled ESLint Config (${localVersion}) is older than the latest version ${remoteVersion} - upgrade by running all lines of the install instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
138
114
|
`);
|
|
139
115
|
}
|
|
140
|
-
|
|
141
116
|
let eslintConfigMatches;
|
|
142
|
-
|
|
143
117
|
try {
|
|
144
118
|
eslintConfigMatches = (await promises.readFile('./.eslintrc.cjs', 'utf-8')).trim() === `/** @type {import('@typescript-eslint/utils').TSESLint.Linter.Config} */
|
|
145
119
|
const config = {
|
|
@@ -148,17 +122,14 @@ const config = {
|
|
|
148
122
|
|
|
149
123
|
module.exports = config;`;
|
|
150
124
|
} catch (err) {
|
|
151
|
-
throw new Error(`Error reading your .eslintrc.cjs file - please reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
125
|
+
throw new Error(`Error reading your .eslintrc.cjs file - please delete the file if it exists and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
152
126
|
`);
|
|
153
127
|
}
|
|
154
|
-
|
|
155
128
|
if (!eslintConfigMatches) {
|
|
156
|
-
throw new Error(`Your
|
|
129
|
+
throw new Error(`Your .eslintrc.cjs file does not match the configuration file template - please delete the file and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
157
130
|
`);
|
|
158
131
|
}
|
|
159
|
-
|
|
160
132
|
const eslintDisableOccurrences = [];
|
|
161
|
-
|
|
162
133
|
for await (const {
|
|
163
134
|
path
|
|
164
135
|
} of readdirp('.', {
|
|
@@ -166,12 +137,10 @@ module.exports = config;`;
|
|
|
166
137
|
fileFilter: ['*.js', '*.jsx', '*.ts', '*.tsx']
|
|
167
138
|
})) {
|
|
168
139
|
const fileContents = await promises.readFile(path, 'utf-8');
|
|
169
|
-
|
|
170
140
|
if (/eslint-disable|eslint [a-z0-9@/-]+: (0|off)/.test(fileContents)) {
|
|
171
141
|
eslintDisableOccurrences.push(path);
|
|
172
142
|
}
|
|
173
143
|
}
|
|
174
|
-
|
|
175
144
|
if (eslintDisableOccurrences.length > 0) {
|
|
176
145
|
throw new Error(`ESLint has been disabled in the following files:
|
|
177
146
|
${eslintDisableOccurrences.join('\n')}
|
|
@@ -205,18 +174,15 @@ async function linkOnGithubAbout() {
|
|
|
205
174
|
}).nextAll('div').filter(function () {
|
|
206
175
|
return $(this).children('.octicon.octicon-link').length > 0;
|
|
207
176
|
}).children('.octicon.octicon-link').next().children('a[href]').attr('href');
|
|
208
|
-
|
|
209
177
|
if (!urlInAboutSection) {
|
|
210
178
|
throw new Error(`Deployed project link not found in About section on ${repoUrl}. Click on the cog symbol to the right of the About heading and paste the Repl.it / Netlify / Fly.io link in the Website box.`);
|
|
211
179
|
}
|
|
212
|
-
|
|
213
180
|
const response = await fetch(urlInAboutSection, {
|
|
214
181
|
headers: {
|
|
215
182
|
// For repl.it
|
|
216
183
|
'user-agent': randomUserAgent()
|
|
217
184
|
}
|
|
218
185
|
});
|
|
219
|
-
|
|
220
186
|
if (!response.ok) {
|
|
221
187
|
throw new Error(`Project link in About section on ${repoUrl} is not returning a proper status code: the link returns status code ${response.status} (${response.statusText}).`);
|
|
222
188
|
}
|
|
@@ -228,6 +194,14 @@ var linkOnGithubAbout$1 = {
|
|
|
228
194
|
'default': linkOnGithubAbout
|
|
229
195
|
};
|
|
230
196
|
|
|
197
|
+
const CRLF = '\r\n';
|
|
198
|
+
function normalizeNewline(input) {
|
|
199
|
+
if (typeof input !== 'string') {
|
|
200
|
+
throw new TypeError(`Expected a \`string\`, got \`${typeof input}\``);
|
|
201
|
+
}
|
|
202
|
+
return input.replace(new RegExp(CRLF, 'g'), '\n');
|
|
203
|
+
}
|
|
204
|
+
|
|
231
205
|
const title$4 = 'node_modules/ folder ignored in Git';
|
|
232
206
|
async function nodeModulesIgnoredFromGit() {
|
|
233
207
|
if ((await execaCommand('git ls-files node_modules/')).stdout !== '') {
|
|
@@ -236,13 +210,10 @@ async function nodeModulesIgnoredFromGit() {
|
|
|
236
210
|
${commandExample('git rm -r --cached node_modules')}
|
|
237
211
|
`);
|
|
238
212
|
}
|
|
239
|
-
|
|
240
213
|
if ((await execaCommand('git ls-files .gitignore')).stdout !== '.gitignore') {
|
|
241
214
|
throw new Error('.gitignore file not found');
|
|
242
215
|
}
|
|
243
|
-
|
|
244
216
|
const nodeModulesInGitignore = normalizeNewline(await promises.readFile('./.gitignore', 'utf8')).split('\n').reduce((found, line) => found || /^\/?node_modules\/?$/.test(line), false);
|
|
245
|
-
|
|
246
217
|
if (!nodeModulesInGitignore) {
|
|
247
218
|
throw new Error('node_modules not found in .gitignore');
|
|
248
219
|
}
|
|
@@ -260,7 +231,6 @@ const preflightPackageJson = /*#__PURE__*/JSON.parse(await /*#__PURE__*/promises
|
|
|
260
231
|
const title$5 = 'Next.js project has sharp installed';
|
|
261
232
|
function nextJsProjectHasSharpInstalled() {
|
|
262
233
|
const dependenciesPackageNames = Object.keys(projectPackageJson.dependencies);
|
|
263
|
-
|
|
264
234
|
if (dependenciesPackageNames.includes('next') && !dependenciesPackageNames.includes('sharp')) {
|
|
265
235
|
throw new Error(`Next.js projects should have sharp installed for better image optimization. Install it with:
|
|
266
236
|
|
|
@@ -269,13 +239,16 @@ function nextJsProjectHasSharpInstalled() {
|
|
|
269
239
|
}
|
|
270
240
|
}
|
|
271
241
|
|
|
272
|
-
const client = /*#__PURE__*/algoliasearch(
|
|
242
|
+
const client = /*#__PURE__*/algoliasearch(
|
|
243
|
+
// Application ID and API key specific to UpLeveled
|
|
273
244
|
// Preflight. Please don't use anywhere else without
|
|
274
245
|
// asking Algolia's permission.
|
|
275
|
-
'OFCNCOG2CU',
|
|
246
|
+
'OFCNCOG2CU',
|
|
247
|
+
// Application ID
|
|
276
248
|
'ec73550aa8b2936dab436d4e02144784');
|
|
277
249
|
const index = /*#__PURE__*/client.initIndex('npm-search');
|
|
278
|
-
const title$6 = 'No dependencies without types';
|
|
250
|
+
const title$6 = 'No dependencies without types';
|
|
251
|
+
// This is a naive check for matching @types/<pkg name> packages
|
|
279
252
|
// that the student hasn't yet installed. It is not intended to
|
|
280
253
|
// be an exhaustive check for any types for all packages.
|
|
281
254
|
//
|
|
@@ -283,7 +256,6 @@ const title$6 = 'No dependencies without types'; // This is a naive check for ma
|
|
|
283
256
|
// `styled-components`:
|
|
284
257
|
//
|
|
285
258
|
// https://learn.upleveled.io/courses/btcmp-l-webfs-gen-0/modules/122-cheatsheet-css-in-js/#eslint-errors-with-styled-components
|
|
286
|
-
|
|
287
259
|
async function noDependenciesWithoutTypes() {
|
|
288
260
|
const {
|
|
289
261
|
devDependencies = {},
|
|
@@ -291,45 +263,41 @@ async function noDependenciesWithoutTypes() {
|
|
|
291
263
|
} = projectPackageJson;
|
|
292
264
|
const dependenciesWithMissingTypes = await pReduce(Object.keys(dependencies), async (filteredDependencies, dependency) => {
|
|
293
265
|
var _results$types;
|
|
294
|
-
|
|
266
|
+
// Return early here because:
|
|
267
|
+
// - Algolia reports "ObjectID does not exist" for `@upleveled/react-scripts`
|
|
268
|
+
// - `@upleveled/react-scripts` has no types to install
|
|
269
|
+
if (dependency === '@upleveled/react-scripts') {
|
|
270
|
+
return filteredDependencies;
|
|
271
|
+
}
|
|
295
272
|
try {
|
|
296
273
|
const packageJsonPath = require.resolve(`${dependency}/package.json`);
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
274
|
+
const modulePackageJson = JSON.parse(await promises.readFile(packageJsonPath, 'utf-8'));
|
|
275
|
+
// If the keys "types" or "typings" are in the module's `package.json`, bail out
|
|
300
276
|
if ('types' in modulePackageJson || 'typings' in modulePackageJson) {
|
|
301
277
|
return filteredDependencies;
|
|
302
278
|
}
|
|
303
279
|
} catch (err) {}
|
|
304
|
-
|
|
305
280
|
let indexDTsPath;
|
|
306
|
-
|
|
307
281
|
try {
|
|
308
282
|
indexDTsPath = require.resolve(`${dependency}/index.d.ts`);
|
|
309
|
-
} catch (err) {}
|
|
310
|
-
|
|
311
|
-
|
|
283
|
+
} catch (err) {}
|
|
284
|
+
// If the index.d.ts file exists inside the module's directory, bail out
|
|
312
285
|
if (indexDTsPath && existsSync(indexDTsPath)) {
|
|
313
286
|
return filteredDependencies;
|
|
314
287
|
}
|
|
315
|
-
|
|
316
288
|
const results = await index.getObject(dependency, {
|
|
317
289
|
attributesToRetrieve: ['types']
|
|
318
290
|
});
|
|
319
291
|
const definitelyTypedPackageName = (_results$types = results.types) == null ? void 0 : _results$types.definitelyTyped;
|
|
320
|
-
|
|
321
292
|
if (definitelyTypedPackageName) {
|
|
322
293
|
// If a matching `@types/<package name>` has been already installed in devDependencies, bail out
|
|
323
294
|
if (Object.keys(devDependencies).includes(definitelyTypedPackageName)) {
|
|
324
295
|
return filteredDependencies;
|
|
325
296
|
}
|
|
326
|
-
|
|
327
297
|
filteredDependencies.push([dependency, definitelyTypedPackageName]);
|
|
328
298
|
}
|
|
329
|
-
|
|
330
299
|
return filteredDependencies;
|
|
331
300
|
}, []);
|
|
332
|
-
|
|
333
301
|
if (dependenciesWithMissingTypes.length > 0) {
|
|
334
302
|
throw new Error(`Dependencies found without types. Add the missing types with:
|
|
335
303
|
|
|
@@ -348,35 +316,40 @@ const {
|
|
|
348
316
|
|
|
349
317
|
const title$7 = 'No unused dependencies';
|
|
350
318
|
async function noUnusedAndMissingDependencies() {
|
|
351
|
-
const ignoredPackagePatterns = [
|
|
352
|
-
|
|
353
|
-
'@
|
|
354
|
-
|
|
355
|
-
'
|
|
356
|
-
|
|
319
|
+
const ignoredPackagePatterns = [
|
|
320
|
+
// Unused dependency detected in https://github.com/upleveled/next-portfolio-dev
|
|
321
|
+
'@graphql-codegen/cli',
|
|
322
|
+
// Unused dependency detected in create-react-app
|
|
323
|
+
'@testing-library/user-event',
|
|
324
|
+
// Tailwind CSS
|
|
325
|
+
'@tailwindcss/jit', 'autoprefixer', 'postcss', 'tailwindcss',
|
|
326
|
+
// Sass (eg. in create-react-app)
|
|
327
|
+
'sass',
|
|
328
|
+
// ESLint configuration
|
|
329
|
+
'babel-eslint', 'eslint-config-next',
|
|
330
|
+
// TODO: Remove this once depcheck issue is fixed:
|
|
357
331
|
// PR: https://github.com/depcheck/depcheck/pull/790
|
|
358
332
|
// Issue: https://github.com/depcheck/depcheck/issues/791
|
|
359
333
|
//
|
|
360
334
|
// Stylelint configuration
|
|
361
|
-
'stylelint', 'stylelint-config-upleveled',
|
|
362
|
-
|
|
363
|
-
'
|
|
335
|
+
'stylelint', 'stylelint-config-upleveled',
|
|
336
|
+
// Testing
|
|
337
|
+
'babel-jest', 'cypress', 'jest', 'jest-environment-jsdom', 'jest-puppeteer', 'playwright', 'puppeteer',
|
|
338
|
+
// TypeScript
|
|
339
|
+
'typescript', '@types/*',
|
|
340
|
+
// Next.js
|
|
364
341
|
'sharp'].join(',');
|
|
365
|
-
|
|
366
342
|
try {
|
|
367
343
|
await execaCommand(`${preflightBinPath}/depcheck --ignores="${ignoredPackagePatterns}"`);
|
|
368
344
|
} catch (error) {
|
|
369
345
|
const {
|
|
370
346
|
stdout
|
|
371
347
|
} = error;
|
|
372
|
-
|
|
373
348
|
if (!stdout.startsWith('Unused dependencies') && !stdout.startsWith('Unused devDependencies') && !stdout.startsWith('Missing dependencies')) {
|
|
374
349
|
throw error;
|
|
375
350
|
}
|
|
376
|
-
|
|
377
351
|
const [unusedDependenciesStdout, missingDependenciesStdout] = stdout.split('Missing dependencies');
|
|
378
352
|
const messages = [];
|
|
379
|
-
|
|
380
353
|
if (unusedDependenciesStdout) {
|
|
381
354
|
messages.push(`Unused dependencies found:
|
|
382
355
|
${unusedDependenciesStdout.split('\n').filter(str => str.includes('* ')).join('\n')}
|
|
@@ -386,7 +359,6 @@ async function noUnusedAndMissingDependencies() {
|
|
|
386
359
|
${commandExample('pnpm remove <dependency name here>')}
|
|
387
360
|
`);
|
|
388
361
|
}
|
|
389
|
-
|
|
390
362
|
if (missingDependenciesStdout) {
|
|
391
363
|
/**
|
|
392
364
|
* Temporary workaround to filter out eslint-config-upleveled peer dependencies
|
|
@@ -398,7 +370,6 @@ async function noUnusedAndMissingDependencies() {
|
|
|
398
370
|
const missingDependenciesStdoutFiltered = missingDependenciesStdout.split('\n').filter(missingDependency => {
|
|
399
371
|
return !(missingDependency.includes('./.eslintrc.cjs') && ['@next/eslint-plugin-next', '@typescript-eslint/eslint-plugin', '@typescript-eslint/parser', 'eslint-plugin-upleveled', 'eslint-config-react-app', 'eslint-import-resolver-typescript', 'eslint-plugin-import', 'eslint-plugin-jsx-a11y', 'eslint-plugin-jsx-expressions', 'eslint-plugin-react-hooks', 'eslint-plugin-react', 'eslint-plugin-security', 'eslint-plugin-sonarjs', 'eslint-plugin-unicorn'].some(excludedDependency => missingDependency.includes(excludedDependency)));
|
|
400
372
|
}).join('\n');
|
|
401
|
-
|
|
402
373
|
if (missingDependenciesStdoutFiltered) {
|
|
403
374
|
messages.push(`Missing dependencies found:
|
|
404
375
|
${missingDependenciesStdoutFiltered.split('\n').filter(str => str.includes('* ')).join('\n')}
|
|
@@ -409,7 +380,6 @@ async function noUnusedAndMissingDependencies() {
|
|
|
409
380
|
`);
|
|
410
381
|
}
|
|
411
382
|
}
|
|
412
|
-
|
|
413
383
|
if (messages.length > 0) throw new Error(messages.join('\n\n'));
|
|
414
384
|
}
|
|
415
385
|
}
|
|
@@ -419,7 +389,6 @@ async function noExtraneousFilesCommittedToGit() {
|
|
|
419
389
|
const {
|
|
420
390
|
stdout
|
|
421
391
|
} = await execaCommand('git ls-files .DS_Store yarn-error.log npm-debug.log');
|
|
422
|
-
|
|
423
392
|
if (stdout !== '') {
|
|
424
393
|
throw new Error(`Extraneous files committed to Git:
|
|
425
394
|
${stdout}
|
|
@@ -444,7 +413,6 @@ async function noSecretsCommittedToGit() {
|
|
|
444
413
|
const {
|
|
445
414
|
stdout
|
|
446
415
|
} = await execaCommand('git ls-files .env .env*.local');
|
|
447
|
-
|
|
448
416
|
if (stdout !== '') {
|
|
449
417
|
throw new Error(`Secrets committed to Git 😱:
|
|
450
418
|
${stdout}
|
|
@@ -475,7 +443,6 @@ async function preflightIsLatestVersion() {
|
|
|
475
443
|
const {
|
|
476
444
|
stdout: remoteVersion
|
|
477
445
|
} = await execaCommand('npm show @upleveled/preflight version');
|
|
478
|
-
|
|
479
446
|
if (semver.gt(remoteVersion, preflightPackageJson.version)) {
|
|
480
447
|
throw new Error(`Your current version of Preflight (${preflightPackageJson.version}) is older than the latest version ${remoteVersion} - upgrade with:
|
|
481
448
|
|
|
@@ -502,22 +469,25 @@ async function prettierCheck() {
|
|
|
502
469
|
stderr
|
|
503
470
|
} = error;
|
|
504
471
|
const stderrWithoutPackageJsonWarning = stderr.replace(/warning [/.\\]*package\.json: No license field[\r\n]*/g, '');
|
|
505
|
-
|
|
506
472
|
if (!stdout || stderrWithoutPackageJsonWarning) {
|
|
507
473
|
throw error;
|
|
508
474
|
}
|
|
509
|
-
|
|
510
|
-
|
|
475
|
+
const ignoredFilePatterns = [
|
|
476
|
+
// File from create-react-app not matching our formatting
|
|
511
477
|
// https://github.com/facebook/create-react-app/blob/fdbde1f3c256b43d5386b5ae3a75083dbd8f0aff/packages/cra-template/template/src/reportWebVitals.js
|
|
512
|
-
/src[/\\]reportWebVitals\.js$/,
|
|
478
|
+
/src[/\\]reportWebVitals\.js$/,
|
|
479
|
+
// Files from create-next-app not matching our formatting
|
|
513
480
|
// https://github.com/vercel/next.js/blob/5a73859fe8d3659d52e169f97188ae422e0d2ace/packages/create-next-app/templates/default/pages/api/hello.js
|
|
514
|
-
/pages[/\\]api[/\\]hello\.js$/,
|
|
481
|
+
/pages[/\\]api[/\\]hello\.js$/,
|
|
482
|
+
// https://github.com/vercel/next.js/blob/aacfa79ddf88e4e1488b63ac253af27110f0a151/packages/create-next-app/templates/default/pages/_app.js
|
|
515
483
|
/pages[/\\]_app\.js$/];
|
|
516
|
-
const unformattedFiles = normalizeNewline(stdout).split('\n')
|
|
484
|
+
const unformattedFiles = normalizeNewline(stdout).split('\n')
|
|
485
|
+
// Make paths relative to the project instead of Preflight, eg:
|
|
517
486
|
// before: ../../../../../../projects/random-color-generator-react-app/src/reportWebVitals.js
|
|
518
|
-
// after:
|
|
519
|
-
|
|
520
|
-
|
|
487
|
+
// after: src/reportWebVitals.js
|
|
488
|
+
.map(file => {
|
|
489
|
+
return file.replace(`${relative(dirname(fileURLToPath(import.meta.url)), process.cwd())}${sep}`, '');
|
|
490
|
+
}).filter(file => !ignoredFilePatterns.some(ignoredFilePattern => ignoredFilePattern.test(file)));
|
|
521
491
|
if (unformattedFiles.length > 0) {
|
|
522
492
|
throw new Error(`Prettier has not been run in the following files:
|
|
523
493
|
${unformattedFiles.join('\n')}
|
|
@@ -540,7 +510,6 @@ const title$c = 'Project folder name matches correct format';
|
|
|
540
510
|
function projectFolderNameMatchesCorrectFormat() {
|
|
541
511
|
const currentDirectoryName = path.basename(process.cwd());
|
|
542
512
|
const lowercaseHyphenedDirectoryName = currentDirectoryName.toLowerCase().replaceAll(' ', '-');
|
|
543
|
-
|
|
544
513
|
if (currentDirectoryName !== lowercaseHyphenedDirectoryName) {
|
|
545
514
|
throw new Error(`Project directory name "${currentDirectoryName}" doesn't match the correct format (no spaces or uppercase letters).
|
|
546
515
|
|
|
@@ -559,12 +528,109 @@ var projectFolderNameMatchesCorrectFormat$1 = {
|
|
|
559
528
|
'default': projectFolderNameMatchesCorrectFormat
|
|
560
529
|
};
|
|
561
530
|
|
|
562
|
-
const
|
|
531
|
+
const errorKey$1 = 'errored';
|
|
532
|
+
const supportedStylelintFileExtensions = ['css', 'sass', 'scss', 'less', 'js', 'tsx', 'jsx'];
|
|
533
|
+
const title$d = 'Stylelint';
|
|
534
|
+
async function stylelintCheck() {
|
|
535
|
+
try {
|
|
536
|
+
await execaCommand(`pnpm stylelint **/*.{${supportedStylelintFileExtensions.join(',')}} --max-warnings 0 --formatter json`);
|
|
537
|
+
} catch (error) {
|
|
538
|
+
const {
|
|
539
|
+
stdout
|
|
540
|
+
} = error;
|
|
541
|
+
// If no Stylelint errors detected, throw the error
|
|
542
|
+
if (!new RegExp(`"${errorKey$1}":`).test(stdout)) {
|
|
543
|
+
throw error;
|
|
544
|
+
}
|
|
545
|
+
throw new Error(`Stylelint problems found in the following files:
|
|
546
|
+
${JSON.parse(stdout).filter(stylelintResult => stylelintResult[errorKey$1] === true)
|
|
547
|
+
// Make paths relative to the project:
|
|
548
|
+
// before: /home/projects/random-color-generator-react-app/src/index.css
|
|
549
|
+
// after: src/index.css
|
|
550
|
+
.map(({
|
|
551
|
+
source
|
|
552
|
+
}) => source.replace(`${process.cwd()}${sep}`, '')).join('\n')}
|
|
553
|
+
|
|
554
|
+
Open these files in your editor - there should be problems to fix
|
|
555
|
+
`);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
var stylelint = {
|
|
560
|
+
__proto__: null,
|
|
561
|
+
supportedStylelintFileExtensions: supportedStylelintFileExtensions,
|
|
562
|
+
title: title$d,
|
|
563
|
+
'default': stylelintCheck
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
const require$2 = /*#__PURE__*/createRequire(`${/*#__PURE__*/process.cwd()}/`);
|
|
567
|
+
const title$e = 'Stylelint config is latest version';
|
|
568
|
+
async function stylelintConfigIsValid() {
|
|
569
|
+
const {
|
|
570
|
+
stdout: remoteVersion
|
|
571
|
+
} = await execaCommand('npm show stylelint-config-upleveled version');
|
|
572
|
+
let localVersion;
|
|
573
|
+
try {
|
|
574
|
+
const stylelintConfigPackageJsonPath = require$2.resolve('stylelint-config-upleveled/package.json');
|
|
575
|
+
localVersion = JSON.parse(await promises.readFile(stylelintConfigPackageJsonPath, 'utf-8')).version;
|
|
576
|
+
} catch (err) {}
|
|
577
|
+
if (typeof localVersion === 'undefined') {
|
|
578
|
+
throw new Error(`The UpLeveled Stylelint Config has not been installed - please install using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
579
|
+
`);
|
|
580
|
+
}
|
|
581
|
+
if (semver.gt(remoteVersion, localVersion)) {
|
|
582
|
+
throw new Error(`Your current version of the UpLeveled Stylelint Config (${localVersion}) is older than the latest version ${remoteVersion} - upgrade by running:
|
|
583
|
+
|
|
584
|
+
pnpm add stylelint-config-upleveled@${remoteVersion}`);
|
|
585
|
+
}
|
|
586
|
+
let stylelintConfigMatches;
|
|
587
|
+
try {
|
|
588
|
+
stylelintConfigMatches = (await promises.readFile('./stylelint.config.cjs', 'utf-8')).trim() === `/** @type { import('stylelint').Config } */
|
|
589
|
+
const config = {
|
|
590
|
+
extends: ['stylelint-config-upleveled'],
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
module.exports = config;`;
|
|
594
|
+
} catch (err) {
|
|
595
|
+
throw new Error(`Error reading your stylelint.config.cjs file - please delete the file if it exists and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
596
|
+
`);
|
|
597
|
+
}
|
|
598
|
+
if (!stylelintConfigMatches) {
|
|
599
|
+
throw new Error(`Your stylelint.config.cjs file does not match the configuration file template - please delete the file and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
600
|
+
`);
|
|
601
|
+
}
|
|
602
|
+
const stylelintDisableOccurrences = [];
|
|
603
|
+
for await (const {
|
|
604
|
+
path
|
|
605
|
+
} of readdirp('.', {
|
|
606
|
+
directoryFilter: ['!.git', '!.next', '!node_modules'],
|
|
607
|
+
fileFilter: supportedStylelintFileExtensions.map(fileExtension => `*.${fileExtension}`)
|
|
608
|
+
})) {
|
|
609
|
+
const fileContents = await promises.readFile(path, 'utf-8');
|
|
610
|
+
if (fileContents.includes('stylelint-disable')) {
|
|
611
|
+
stylelintDisableOccurrences.push(path);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
if (stylelintDisableOccurrences.length > 0) {
|
|
615
|
+
throw new Error(`Stylelint has been disabled in the following files:
|
|
616
|
+
${stylelintDisableOccurrences.join('\n')}
|
|
617
|
+
|
|
618
|
+
Remove all comments disabling or modifying Stylelint rule configuration (eg. stylelint-disable and stylelint-disable-next-line comments) and fix the problems
|
|
619
|
+
`);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
var stylelintConfigIsValid$1 = {
|
|
624
|
+
__proto__: null,
|
|
625
|
+
title: title$e,
|
|
626
|
+
'default': stylelintConfigIsValid
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
const title$f = 'Use single package manager';
|
|
563
630
|
async function useSinglePackageManager() {
|
|
564
631
|
const {
|
|
565
632
|
stdout
|
|
566
633
|
} = await execaCommand('git ls-files package-lock.json yarn.lock');
|
|
567
|
-
|
|
568
634
|
if (stdout !== '') {
|
|
569
635
|
throw new Error(`package-lock.json or yarn.lock file committed to Git. Remove it with:
|
|
570
636
|
|
|
@@ -583,20 +649,25 @@ async function useSinglePackageManager() {
|
|
|
583
649
|
|
|
584
650
|
var useSinglePackageManager$1 = {
|
|
585
651
|
__proto__: null,
|
|
586
|
-
title: title$
|
|
652
|
+
title: title$f,
|
|
587
653
|
'default': useSinglePackageManager
|
|
588
654
|
};
|
|
589
655
|
|
|
656
|
+
const projectDependencies = projectPackageJson.dependencies || {};
|
|
590
657
|
console.log(`🚀 UpLeveled Preflight v${preflightPackageJson.version}`);
|
|
591
|
-
const listrTasks = /*#__PURE__*/[
|
|
658
|
+
const listrTasks = /*#__PURE__*/[
|
|
659
|
+
// ======= Sync Tasks =======
|
|
592
660
|
// Git
|
|
593
|
-
allChangesCommittedToGit$1, nodeModulesIgnoredFromGit$1, noExtraneousFilesCommittedToGit$1, noSecretsCommittedToGit$1,
|
|
594
|
-
|
|
595
|
-
|
|
661
|
+
allChangesCommittedToGit$1, nodeModulesIgnoredFromGit$1, noExtraneousFilesCommittedToGit$1, noSecretsCommittedToGit$1,
|
|
662
|
+
// Package managers
|
|
663
|
+
useSinglePackageManager$1,
|
|
664
|
+
// Project setup
|
|
665
|
+
projectFolderNameMatchesCorrectFormat$1,
|
|
666
|
+
// ======= Async Tasks =======
|
|
596
667
|
// Dependencies
|
|
597
668
|
{
|
|
598
669
|
title: 'No dependency problems',
|
|
599
|
-
task: (ctx, task) => task.newListr([...(!
|
|
670
|
+
task: (ctx, task) => task.newListr([...(!Object.keys(projectDependencies).includes('next') ? [] : [{
|
|
600
671
|
title: title$5,
|
|
601
672
|
task: nextJsProjectHasSharpInstalled
|
|
602
673
|
}]), {
|
|
@@ -606,10 +677,13 @@ projectFolderNameMatchesCorrectFormat$1, // ======= Async Tasks =======
|
|
|
606
677
|
title: title$6,
|
|
607
678
|
task: noDependenciesWithoutTypes
|
|
608
679
|
}])
|
|
609
|
-
},
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
680
|
+
},
|
|
681
|
+
// GitHub
|
|
682
|
+
linkOnGithubAbout$1,
|
|
683
|
+
// Linting
|
|
684
|
+
eslint, ...(!('@upleveled/react-scripts' in projectDependencies || 'next' in projectDependencies) ? [] : [stylelint]), prettier,
|
|
685
|
+
// Version and configuration checks
|
|
686
|
+
eslintConfigIsValid$1, ...(!('@upleveled/react-scripts' in projectDependencies || 'next' in projectDependencies) ? [] : [stylelintConfigIsValid$1]), preflightIsLatestVersion$1].map(module => {
|
|
613
687
|
if ('task' in module) return module;
|
|
614
688
|
return {
|
|
615
689
|
title: module.title,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preflight.esm.js","sources":["../src/util/commandExample.ts","../src/util/isDrone.ts","../src/checks/allChangesCommittedToGit.ts","../src/util/normalizeNewline.ts","../src/checks/eslint.ts","../src/checks/eslintConfigIsValid.ts","../src/util/randomUserAgent.ts","../src/checks/linkOnGithubAbout.ts","../src/checks/nodeModulesIgnoredFromGit.ts","../src/util/packageJson.ts","../src/checks/noDependencyProblems/nextJsProjectHasSharpInstalled.ts","../src/checks/noDependencyProblems/noDependenciesWithoutTypes.ts","../src/util/preflightBinPath.ts","../src/checks/noDependencyProblems/noUnusedDependencies.ts","../src/checks/noExtraneousFilesCommittedToGit.ts","../src/checks/noSecretsCommittedToGit.ts","../src/checks/preflightIsLatestVersion.ts","../src/checks/prettier.ts","../src/checks/projectFolderNameMatchesCorrectFormat.ts","../src/checks/useSinglePackageManager.ts","../src/index.ts"],"sourcesContent":["import chalk from 'chalk';\n\n// https://www.compart.com/en/unicode/U+2800\n// eslint-disable-next-line security/detect-bidi-characters -- Intentional use of unusual character for formatting\nconst emptyBrailleCharacter = '';\n\nexport default function commandExample(command: string) {\n return `${emptyBrailleCharacter} ${chalk.dim('$')} ${command}`;\n}\n","import { execaCommand } from 'execa';\n\nexport async function isDrone() {\n const { stdout } = await execaCommand('cat /etc/os-release', {\n reject: false,\n });\n return /Alpine Linux/.test(stdout);\n}\n","import { promises as fs } from 'node:fs';\nimport { execaCommand } from 'execa';\nimport commandExample from '../util/commandExample';\nimport { isDrone } from '../util/isDrone';\n\nexport const title = 'All changes committed to Git';\n\nexport default async function allChangesCommittedToGit() {\n const { stdout: replSlug } = await execaCommand('echo $REPL_SLUG');\n\n const isRunningInReplIt = replSlug !== '';\n\n if (isRunningInReplIt) {\n await fs.writeFile('.git/info/exclude', '.replit\\n');\n }\n\n const { stdout } = await execaCommand('git status --porcelain');\n\n if (stdout !== '') {\n const onlyPnpmLockModifiedOnDrone =\n stdout.trim() === 'M pnpm-lock.yaml' && (await isDrone());\n throw new Error(\n `Some changes have not been committed to Git:\n ${stdout}${\n onlyPnpmLockModifiedOnDrone\n ? `\n\n The only file with changes is the pnpm-lock.yaml file, indicating that npm was incorrectly used in addition to pnpm (eg. an \"npm install\" command was run). To fix this, force regeneration of the pnpm-lock.yaml file locally with the following command and then commit the changes:\n\n ${commandExample('pnpm install --force')}`\n : ''\n }\n `,\n );\n }\n}\n","const CRLF = '\\r\\n';\n\nexport default function normalizeNewline(input: string) {\n if (typeof input !== 'string') {\n throw new TypeError(`Expected a \\`string\\`, got \\`${typeof input}\\``);\n }\n\n return input.replace(new RegExp(CRLF, 'g'), '\\n');\n}\n","import { execaCommand } from 'execa';\nimport normalizeNewline from '../util/normalizeNewline';\n\nexport const title = 'ESLint';\n\nexport default async function eslintCheck() {\n try {\n await execaCommand('pnpm eslint . --max-warnings 0 --format compact');\n } catch (error) {\n const { stdout } = error as { stdout: string };\n const lines = stdout.split('\\n');\n\n // If no ESLint problems detected, throw the error\n if (!/^\\d+ problems?$/.test(lines[lines.length - 2]!)) {\n throw error;\n }\n\n throw new Error(\n `ESLint problems found in the following files:\n ${normalizeNewline(stdout)\n .split('\\n')\n // Match lines starting with slashes (macOS, Linux) or drive letters (Windows)\n .filter((line) => /^(\\/|[A-Z]:\\\\)/.test(line))\n // Strip out the filename\n .map((line) => line.match(/^(([A-Z]:)?[^:]+):/)?.[1])\n // Remove duplicate filenames\n .reduce((linesWithoutDuplicates: string[], line) => {\n if (line && !linesWithoutDuplicates.includes(line)) {\n linesWithoutDuplicates.push(line);\n }\n return linesWithoutDuplicates;\n }, [])\n .join('\\n')}\n\n Open these files in your editor - there should be problems to fix\n `,\n );\n }\n}\n","import { promises as fs } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { execaCommand } from 'execa';\nimport readdirp from 'readdirp';\nimport semver from 'semver';\n\nconst require = createRequire(`${process.cwd()}/`);\n\nexport const title = 'ESLint config is latest version';\n\nexport default async function eslintConfigIsValid() {\n const { stdout: remoteVersion } = await execaCommand(\n 'npm show eslint-config-upleveled version',\n );\n\n let localVersion;\n\n try {\n const eslintConfigPackageJsonPath = require.resolve(\n 'eslint-config-upleveled/package.json',\n );\n\n localVersion = JSON.parse(\n await fs.readFile(eslintConfigPackageJsonPath, 'utf-8'),\n ).version;\n } catch (err) {}\n\n if (typeof localVersion === 'undefined') {\n throw new Error(\n `The UpLeveled ESLint Config has not been installed - please install using the instructions on https://www.npmjs.com/package/eslint-config-upleveled\n `,\n );\n }\n\n if (semver.gt(remoteVersion, localVersion)) {\n throw new Error(\n `Your current version of the UpLeveled ESLint Config (${localVersion}) is older than the latest version ${remoteVersion} - upgrade by running all lines of the install instructions on https://www.npmjs.com/package/eslint-config-upleveled\n `,\n );\n }\n\n let eslintConfigMatches;\n\n try {\n eslintConfigMatches =\n (await fs.readFile('./.eslintrc.cjs', 'utf-8')).trim() ===\n `/** @type {import('@typescript-eslint/utils').TSESLint.Linter.Config} */\nconst config = {\n extends: ['upleveled'],\n};\n\nmodule.exports = config;`;\n } catch (err) {\n throw new Error(\n `Error reading your .eslintrc.cjs file - please reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled\n `,\n );\n }\n\n if (!eslintConfigMatches) {\n throw new Error(\n `Your ESLint config file .eslintrc.cjs does not match the configuration file template - please reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled\n `,\n );\n }\n\n const eslintDisableOccurrences = [];\n\n for await (const { path } of readdirp('.', {\n directoryFilter: ['!.git', '!.next', '!node_modules'],\n fileFilter: ['*.js', '*.jsx', '*.ts', '*.tsx'],\n })) {\n const fileContents = await fs.readFile(path, 'utf-8');\n if (/eslint-disable|eslint [a-z0-9@/-]+: (0|off)/.test(fileContents)) {\n eslintDisableOccurrences.push(path);\n }\n }\n\n if (eslintDisableOccurrences.length > 0) {\n throw new Error(\n `ESLint has been disabled in the following files:\n ${eslintDisableOccurrences.join('\\n')}\n\n Remove all comments disabling or modifying ESLint rule configuration (eg. eslint-disable and eslint-disable-next-line comments) and fix the problems\n `,\n );\n }\n}\n","import userAgents from 'top-user-agents';\n\nexport default function randomUserAgent() {\n const randomIndex = Math.floor(Math.random() * (userAgents.length - 1));\n return userAgents[randomIndex]!;\n}\n","import cheerio from 'cheerio';\nimport type { Element } from 'domhandler';\nimport { execaCommand } from 'execa';\nimport fetch from 'node-fetch';\nimport randomUserAgent from '../util/randomUserAgent';\n\nexport const title = 'GitHub repo has deployed project link under About';\n\nexport default async function linkOnGithubAbout() {\n const { stdout } = await execaCommand('git remote get-url origin');\n\n const repoUrl = stdout\n .replace('git@github.com:', 'https://github.com/')\n .replace('.git', '');\n\n const html = await (await fetch(repoUrl)).text();\n\n const $ = cheerio.load(html);\n\n const urlInAboutSection = $('h2')\n .filter(function (this: Element) {\n return $(this).text().trim() === 'About';\n })\n .nextAll('div')\n .filter(function (this: Element) {\n return $(this).children('.octicon.octicon-link').length > 0;\n })\n .children('.octicon.octicon-link')\n .next()\n .children('a[href]')\n .attr('href');\n\n if (!urlInAboutSection) {\n throw new Error(\n `Deployed project link not found in About section on ${repoUrl}. Click on the cog symbol to the right of the About heading and paste the Repl.it / Netlify / Fly.io link in the Website box.`,\n );\n }\n\n const response = await fetch(urlInAboutSection, {\n headers: {\n // For repl.it\n 'user-agent': randomUserAgent(),\n },\n });\n\n if (!response.ok) {\n throw new Error(\n `Project link in About section on ${repoUrl} is not returning a proper status code: the link returns status code ${response.status} (${response.statusText}).`,\n );\n }\n}\n","import { promises as fs } from 'node:fs';\nimport { execaCommand } from 'execa';\nimport commandExample from '../util/commandExample';\nimport normalizeNewline from '../util/normalizeNewline';\n\nexport const title = 'node_modules/ folder ignored in Git';\n\nexport default async function nodeModulesIgnoredFromGit() {\n if ((await execaCommand('git ls-files node_modules/')).stdout !== '') {\n throw new Error(\n `node_modules/ folder committed to Git. Remove it using:\n\n ${commandExample('git rm -r --cached node_modules')}\n `,\n );\n }\n\n if ((await execaCommand('git ls-files .gitignore')).stdout !== '.gitignore') {\n throw new Error('.gitignore file not found');\n }\n\n const nodeModulesInGitignore = normalizeNewline(\n await fs.readFile('./.gitignore', 'utf8'),\n )\n .split('\\n')\n .reduce((found, line) => found || /^\\/?node_modules\\/?$/.test(line), false);\n\n if (!nodeModulesInGitignore) {\n throw new Error('node_modules not found in .gitignore');\n }\n}\n","import { promises as fs } from 'node:fs';\nimport { URL } from 'node:url';\n\ntype PackageJson = {\n name: string;\n version: string;\n description?: string;\n keywords?: string;\n homepage?: string;\n bugs?: {\n email?: string;\n url?: string;\n };\n license?: string;\n author?:\n | string\n | {\n name: string;\n email?: string;\n url?: string;\n };\n contributors?:\n | string[]\n | {\n name: string;\n email?: string;\n url?: string;\n }[];\n files?: string[];\n main?: string;\n browser?: string;\n bin?: Record<string, string>;\n man?: string;\n directories?: {\n lib?: string;\n bin?: string;\n man?: string;\n doc?: string;\n example?: string;\n test?: string;\n };\n repository?: {\n type?: 'git';\n url?: string;\n directory?: string;\n };\n scripts?: Record<string, string>;\n config?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n bundledDependencies?: string[];\n engines?: Record<string, string>;\n os?: string[];\n cpu?: string[];\n};\n\nexport const projectPackageJson = JSON.parse(\n await fs.readFile('package.json', 'utf-8'),\n) as PackageJson;\n\nexport const preflightPackageJson = JSON.parse(\n await fs.readFile(new URL('../package.json', import.meta.url), 'utf-8'),\n) as PackageJson;\n","import commandExample from '../../util/commandExample';\nimport { projectPackageJson } from '../../util/packageJson';\n\nexport const title = 'Next.js project has sharp installed';\n\nexport default function nextJsProjectHasSharpInstalled() {\n const dependenciesPackageNames = Object.keys(\n projectPackageJson.dependencies!,\n );\n if (\n dependenciesPackageNames.includes('next') &&\n !dependenciesPackageNames.includes('sharp')\n ) {\n throw new Error(\n `Next.js projects should have sharp installed for better image optimization. Install it with:\n\n ${commandExample('pnpm add sharp')}\n `,\n );\n }\n}\n","import { existsSync, promises as fs } from 'node:fs';\nimport algoliasearch from 'algoliasearch';\nimport pReduce from 'p-reduce';\nimport commandExample from '../../util/commandExample';\nimport { projectPackageJson } from '../../util/packageJson';\n\nconst client = algoliasearch(\n // Application ID and API key specific to UpLeveled\n // Preflight. Please don't use anywhere else without\n // asking Algolia's permission.\n 'OFCNCOG2CU', // Application ID\n 'ec73550aa8b2936dab436d4e02144784', // API Key\n);\nconst index = client.initIndex('npm-search');\n\ninterface AlgoliaObj {\n types?: {\n definitelyTyped?: string;\n };\n}\n\nexport const title = 'No dependencies without types';\n\n// This is a naive check for matching @types/<pkg name> packages\n// that the student hasn't yet installed. It is not intended to\n// be an exhaustive check for any types for all packages.\n//\n// It attempts to address scenarios such as this with\n// `styled-components`:\n//\n// https://learn.upleveled.io/courses/btcmp-l-webfs-gen-0/modules/122-cheatsheet-css-in-js/#eslint-errors-with-styled-components\nexport default async function noDependenciesWithoutTypes() {\n const { devDependencies = {}, dependencies = {} } = projectPackageJson;\n\n const dependenciesWithMissingTypes = await pReduce(\n Object.keys(dependencies),\n async (filteredDependencies: [string, string][], dependency: string) => {\n try {\n const packageJsonPath = require.resolve(`${dependency}/package.json`);\n\n const modulePackageJson = JSON.parse(\n await fs.readFile(packageJsonPath, 'utf-8'),\n );\n\n // If the keys \"types\" or \"typings\" are in the module's `package.json`, bail out\n if ('types' in modulePackageJson || 'typings' in modulePackageJson) {\n return filteredDependencies;\n }\n } catch (err) {}\n\n let indexDTsPath;\n\n try {\n indexDTsPath = require.resolve(`${dependency}/index.d.ts`);\n } catch (err) {}\n\n // If the index.d.ts file exists inside the module's directory, bail out\n if (indexDTsPath && existsSync(indexDTsPath)) {\n return filteredDependencies;\n }\n\n const results = await index.getObject<AlgoliaObj>(dependency, {\n attributesToRetrieve: ['types'],\n });\n\n const definitelyTypedPackageName = results.types?.definitelyTyped;\n\n if (definitelyTypedPackageName) {\n // If a matching `@types/<package name>` has been already installed in devDependencies, bail out\n if (Object.keys(devDependencies).includes(definitelyTypedPackageName)) {\n return filteredDependencies;\n }\n\n filteredDependencies.push([dependency, definitelyTypedPackageName]);\n }\n\n return filteredDependencies;\n },\n [],\n );\n\n if (dependenciesWithMissingTypes.length > 0) {\n throw new Error(\n `Dependencies found without types. Add the missing types with:\n\n ${commandExample(\n `pnpm add --save-dev ${dependenciesWithMissingTypes\n .map(([, definitelyTypedPackageName]) => definitelyTypedPackageName)\n .join(' ')}`,\n )}\n\n If the dependencies above are already in your package.json, check that they have not been incorrectly installed as regular dependencies in the \"dependencies\" object - they should be installed inside \"devDependencies\" (using the --save-dev flag mentioned above). To fix this situation, remove the dependencies and run the command above exactly.\n `,\n );\n }\n}\n","import { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { execaCommand } from 'execa';\n\nconst { stdout: preflightBinPath } = await execaCommand(`pnpm bin`, {\n cwd: dirname(fileURLToPath(import.meta.url)),\n});\n\nexport default preflightBinPath;\n","import { execaCommand } from 'execa';\nimport commandExample from '../../util/commandExample';\nimport preflightBinPath from '../../util/preflightBinPath';\n\nexport const title = 'No unused dependencies';\n\nexport default async function noUnusedAndMissingDependencies() {\n const ignoredPackagePatterns = [\n // Unused dependency detected in https://github.com/upleveled/next-portfolio-dev\n '@graphql-codegen/cli',\n\n // Unused dependency detected in create-react-app\n '@testing-library/user-event',\n\n // Tailwind CSS\n '@tailwindcss/jit',\n 'autoprefixer',\n 'postcss',\n 'tailwindcss',\n\n // Sass (eg. in create-react-app)\n 'sass',\n\n // ESLint configuration\n 'babel-eslint',\n 'eslint-config-next',\n\n // TODO: Remove this once depcheck issue is fixed:\n // PR: https://github.com/depcheck/depcheck/pull/790\n // Issue: https://github.com/depcheck/depcheck/issues/791\n //\n // Stylelint configuration\n 'stylelint',\n 'stylelint-config-upleveled',\n\n // Testing\n 'babel-jest',\n 'cypress',\n 'jest',\n 'jest-environment-jsdom',\n 'jest-puppeteer',\n 'playwright',\n 'puppeteer',\n\n // TypeScript\n 'typescript',\n '@types/*',\n\n // Next.js\n 'sharp',\n ].join(',');\n\n try {\n await execaCommand(\n `${preflightBinPath}/depcheck --ignores=\"${ignoredPackagePatterns}\"`,\n );\n } catch (error) {\n const { stdout } = error as { stdout: string };\n if (\n !stdout.startsWith('Unused dependencies') &&\n !stdout.startsWith('Unused devDependencies') &&\n !stdout.startsWith('Missing dependencies')\n ) {\n throw error;\n }\n\n const [unusedDependenciesStdout, missingDependenciesStdout] = stdout.split(\n 'Missing dependencies',\n );\n\n const messages = [];\n\n if (unusedDependenciesStdout) {\n messages.push(`Unused dependencies found:\n ${unusedDependenciesStdout\n .split('\\n')\n .filter((str: string) => str.includes('* '))\n .join('\\n')}\n\n Remove these dependencies by running the following command for each dependency:\n\n ${commandExample('pnpm remove <dependency name here>')}\n `);\n }\n\n if (missingDependenciesStdout) {\n /**\n * Temporary workaround to filter out eslint-config-upleveled peer dependencies\n * not listed in `package.json`, which are flagged as missing dependencies by depcheck\n *\n * TODO: Remove this variable once this depcheck issue is fixed:\n * https://github.com/depcheck/depcheck/issues/789\n */\n const missingDependenciesStdoutFiltered = missingDependenciesStdout\n .split('\\n')\n .filter((missingDependency) => {\n return !(\n missingDependency.includes('./.eslintrc.cjs') &&\n [\n '@next/eslint-plugin-next',\n '@typescript-eslint/eslint-plugin',\n '@typescript-eslint/parser',\n 'eslint-plugin-upleveled',\n 'eslint-config-react-app',\n 'eslint-import-resolver-typescript',\n 'eslint-plugin-import',\n 'eslint-plugin-jsx-a11y',\n 'eslint-plugin-jsx-expressions',\n 'eslint-plugin-react-hooks',\n 'eslint-plugin-react',\n 'eslint-plugin-security',\n 'eslint-plugin-sonarjs',\n 'eslint-plugin-unicorn',\n ].some((excludedDependency) =>\n missingDependency.includes(excludedDependency),\n )\n );\n })\n .join('\\n');\n\n if (missingDependenciesStdoutFiltered) {\n messages.push(`Missing dependencies found:\n ${missingDependenciesStdoutFiltered\n .split('\\n')\n .filter((str: string) => str.includes('* '))\n .join('\\n')}\n\n Add these missing dependencies by running the following command for each dependency:\n\n ${commandExample('pnpm add <dependency name here>')}\n `);\n }\n }\n\n if (messages.length > 0) throw new Error(messages.join('\\n\\n'));\n }\n}\n","import { execaCommand } from 'execa';\nimport commandExample from '../util/commandExample';\n\nexport const title = 'No extraneous files committed to Git';\n\nexport default async function noExtraneousFilesCommittedToGit() {\n const { stdout } = await execaCommand(\n 'git ls-files .DS_Store yarn-error.log npm-debug.log',\n );\n\n if (stdout !== '') {\n throw new Error(\n `Extraneous files committed to Git:\n ${stdout}\n\n Remove these files from your repo by running the following command for each file:\n\n ${commandExample('git rm --cached <filename here>')}\n\n Once you've removed all files, make sure that it doesn't happen again by adding the filenames above to your .gitignore file.\n `,\n );\n }\n}\n","import { execaCommand } from 'execa';\nimport commandExample from '../util/commandExample';\n\nexport const title = 'No secrets committed to Git';\n\nexport default async function noSecretsCommittedToGit() {\n const { stdout } = await execaCommand('git ls-files .env .env*.local');\n\n if (stdout !== '') {\n throw new Error(\n `Secrets committed to Git 😱:\n ${stdout}\n\n Remove these files from your repo by installing BFG from the System Setup Guide (see Optional Software at the bottom) and running it on each of your files like this:\n\n ${commandExample('bfg --delete-files <filename here>')}\n\n Once you've done this for every secret file, then force push to your repository:\n\n ${commandExample('git push --force')}\n\n More info: https://docs.github.com/en/github/authenticating-to-github/removing-sensitive-data-from-a-repository\n\n Finally, make sure that this doesn't happen again by adding the filenames above to your .gitignore file.\n `,\n );\n }\n}\n","import os from 'node:os';\nimport { execaCommand } from 'execa';\nimport semver from 'semver';\nimport commandExample from '../util/commandExample';\nimport { preflightPackageJson } from '../util/packageJson';\n\nexport const title = 'Preflight is latest version';\n\nexport default async function preflightIsLatestVersion() {\n const { stdout: remoteVersion } = await execaCommand(\n 'npm show @upleveled/preflight version',\n );\n\n if (semver.gt(remoteVersion, preflightPackageJson.version)) {\n throw new Error(\n `Your current version of Preflight (${\n preflightPackageJson.version\n }) is older than the latest version ${remoteVersion} - upgrade with:\n\n ${commandExample(\n `${\n os.platform() === 'linux' ? 'sudo ' : ''\n }pnpm add --global @upleveled/preflight`,\n )}\n `,\n );\n }\n}\n","import { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { execaCommand } from 'execa';\nimport normalizeNewline from '../util/normalizeNewline';\n\nexport const title = 'Prettier';\n\nexport default async function prettierCheck() {\n try {\n await execaCommand(\n `../node_modules/.bin/prettier --list-different ${process.cwd()}/**/*.{js,jsx,ts,jsx} --ignore-path ${process.cwd()}/.eslintignore --config ${process.cwd()}/prettier.config.cjs --end-of-line auto`,\n { cwd: dirname(fileURLToPath(import.meta.url)) },\n );\n } catch (error) {\n const { stdout, stderr } = error as { stdout: string; stderr: string };\n\n const stderrWithoutPackageJsonWarning = stderr.replace(\n /warning [/.\\\\]*package\\.json: No license field[\\r\\n]*/g,\n '',\n );\n\n if (!stdout || stderrWithoutPackageJsonWarning) {\n throw error;\n }\n\n const ignoredFilePatterns = [\n // File from create-react-app not matching our formatting\n // https://github.com/facebook/create-react-app/blob/fdbde1f3c256b43d5386b5ae3a75083dbd8f0aff/packages/cra-template/template/src/reportWebVitals.js\n /src[/\\\\]reportWebVitals\\.js$/,\n\n // Files from create-next-app not matching our formatting\n // https://github.com/vercel/next.js/blob/5a73859fe8d3659d52e169f97188ae422e0d2ace/packages/create-next-app/templates/default/pages/api/hello.js\n /pages[/\\\\]api[/\\\\]hello\\.js$/,\n // https://github.com/vercel/next.js/blob/aacfa79ddf88e4e1488b63ac253af27110f0a151/packages/create-next-app/templates/default/pages/_app.js\n /pages[/\\\\]_app\\.js$/,\n ];\n\n const unformattedFiles = normalizeNewline(stdout)\n .split('\\n')\n .map((file) =>\n // Make paths relative to the project instead of Preflight, eg:\n // before: ../../../../../../projects/random-color-generator-react-app/src/reportWebVitals.js\n // after: random-color-generator-react-app/src/reportWebVitals.js\n file.replace(/^([A-Z]:|\\.\\.[/\\\\])[a-zA-Z0-9-_/.\\\\ ]*projects[/\\\\]/, ''),\n )\n .filter(\n (file) =>\n !ignoredFilePatterns.some((ignoredFilePattern) =>\n ignoredFilePattern.test(file),\n ),\n );\n\n if (unformattedFiles.length > 0) {\n throw new Error(\n `Prettier has not been run in the following files:\n ${unformattedFiles.join('\\n')}\n\n For each of the files above, open the file in your editor and save the file. This will format the file with Prettier, which will cause changes to appear in Git.\n\n In some very uncommon cases (this probably doesn't apply to you), the mismatch may come from inconsistent end of line characters. Read more here: https://github.com/upleveled/answers/issues/31\n `,\n );\n }\n }\n}\n","import path from 'node:path';\nimport commandExample from '../util/commandExample';\n\nexport const title = 'Project folder name matches correct format';\n\nexport default function projectFolderNameMatchesCorrectFormat() {\n const currentDirectoryName = path.basename(process.cwd());\n const lowercaseHyphenedDirectoryName = currentDirectoryName\n .toLowerCase()\n .replaceAll(' ', '-');\n\n if (currentDirectoryName !== lowercaseHyphenedDirectoryName) {\n throw new Error(\n `Project directory name \"${currentDirectoryName}\" doesn't match the correct format (no spaces or uppercase letters).\n\n Rename the directory to the correct name \"${lowercaseHyphenedDirectoryName}\" with the following sequence of commands:\n\n ${commandExample('cd ..')}\n ${commandExample(\n `mv ${currentDirectoryName} ${lowercaseHyphenedDirectoryName}`,\n )}\n ${commandExample(`cd ${lowercaseHyphenedDirectoryName}`)}\n `,\n );\n }\n}\n","import { execaCommand } from 'execa';\nimport commandExample from '../util/commandExample';\n\nexport const title = 'Use single package manager';\n\nexport default async function useSinglePackageManager() {\n const { stdout } = await execaCommand(\n 'git ls-files package-lock.json yarn.lock',\n );\n\n if (stdout !== '') {\n throw new Error(\n `package-lock.json or yarn.lock file committed to Git. Remove it with:\n\n ${commandExample('git rm --cached <filename>')}\n\n After you've removed it, you can delete the file with:\n\n ${commandExample('rm <filename>')}\n\n The presence of this file indicates that another package manager was used in addition to pnpm (eg. \"npm install\" or \"yarn add\" was run). In order to avoid issues with the state of the pnpm-lock.yaml file, we suggest also forcing regeneration this file with the following command:\n\n ${commandExample('pnpm install --force')}\n `,\n );\n }\n}\n","import { Listr } from 'listr2';\nimport * as allChangesCommittedToGit from './checks/allChangesCommittedToGit.js';\nimport * as eslint from './checks/eslint.js';\nimport * as eslintConfigIsValid from './checks/eslintConfigIsValid.js';\nimport * as linkOnGithubAbout from './checks/linkOnGithubAbout.js';\nimport * as nodeModulesIgnoredFromGit from './checks/nodeModulesIgnoredFromGit.js';\nimport * as nextJsProjectHasSharpInstalled from './checks/noDependencyProblems/nextJsProjectHasSharpInstalled.js';\nimport * as noDependenciesWithoutTypes from './checks/noDependencyProblems/noDependenciesWithoutTypes.js';\nimport * as noUnusedAndMissingDependencies from './checks/noDependencyProblems/noUnusedDependencies.js';\nimport * as noExtraneousFilesCommittedToGit from './checks/noExtraneousFilesCommittedToGit.js';\nimport * as noSecretsCommittedToGit from './checks/noSecretsCommittedToGit.js';\nimport * as preflightIsLatestVersion from './checks/preflightIsLatestVersion.js';\nimport * as prettier from './checks/prettier.js';\nimport * as projectFolderNameMatchesCorrectFormat from './checks/projectFolderNameMatchesCorrectFormat.js';\nimport * as useSinglePackageManager from './checks/useSinglePackageManager.js';\nimport { CtxParam } from './types/CtxParam.js';\nimport { TaskParam } from './types/TaskParam.js';\nimport {\n preflightPackageJson,\n projectPackageJson,\n} from './util/packageJson.js';\n\nconsole.log(`🚀 UpLeveled Preflight v${preflightPackageJson.version}`);\n\nconst listrTasks = [\n // ======= Sync Tasks =======\n // Git\n allChangesCommittedToGit,\n nodeModulesIgnoredFromGit,\n noExtraneousFilesCommittedToGit,\n noSecretsCommittedToGit,\n\n // Package managers\n useSinglePackageManager,\n\n // Project setup\n projectFolderNameMatchesCorrectFormat,\n\n // ======= Async Tasks =======\n // Dependencies\n {\n title: 'No dependency problems',\n task: (ctx: CtxParam, task: TaskParam): Listr =>\n task.newListr([\n ...(!projectPackageJson.dependencies ||\n !Object.keys(projectPackageJson.dependencies).includes('next')\n ? []\n : [\n {\n title: nextJsProjectHasSharpInstalled.title,\n task: nextJsProjectHasSharpInstalled.default,\n },\n ]),\n {\n title: noUnusedAndMissingDependencies.title,\n task: noUnusedAndMissingDependencies.default,\n },\n {\n title: noDependenciesWithoutTypes.title,\n task: noDependenciesWithoutTypes.default,\n },\n ]),\n },\n\n // GitHub\n linkOnGithubAbout,\n\n // Linting\n eslint,\n prettier,\n\n // Version and configuration checks\n eslintConfigIsValid,\n preflightIsLatestVersion,\n].map((module) => {\n if ('task' in module) return module;\n return {\n title: module.title,\n task: module.default,\n };\n});\n\nawait new Listr(listrTasks, {\n exitOnError: false,\n rendererOptions: {\n collapseErrors: false,\n removeEmptyLines: false,\n formatOutput: 'wrap',\n },\n fallbackRenderer: 'verbose',\n concurrent: 5,\n}).run();\n"],"names":["emptyBrailleCharacter","commandExample","command","chalk","dim","isDrone","stdout","execaCommand","reject","test","title","allChangesCommittedToGit","replSlug","isRunningInReplIt","fs","writeFile","onlyPnpmLockModifiedOnDrone","trim","Error","CRLF","normalizeNewline","input","TypeError","replace","RegExp","eslintCheck","error","lines","split","length","filter","line","map","match","reduce","linesWithoutDuplicates","includes","push","join","require","createRequire","process","cwd","eslintConfigIsValid","remoteVersion","localVersion","eslintConfigPackageJsonPath","resolve","JSON","parse","readFile","version","err","semver","gt","eslintConfigMatches","eslintDisableOccurrences","path","readdirp","directoryFilter","fileFilter","fileContents","randomUserAgent","randomIndex","Math","floor","random","userAgents","linkOnGithubAbout","repoUrl","html","fetch","text","$","cheerio","load","urlInAboutSection","nextAll","children","next","attr","response","headers","ok","status","statusText","nodeModulesIgnoredFromGit","nodeModulesInGitignore","found","projectPackageJson","preflightPackageJson","URL","import","meta","url","nextJsProjectHasSharpInstalled","dependenciesPackageNames","Object","keys","dependencies","client","algoliasearch","index","initIndex","noDependenciesWithoutTypes","devDependencies","dependenciesWithMissingTypes","pReduce","filteredDependencies","dependency","packageJsonPath","modulePackageJson","indexDTsPath","existsSync","results","getObject","attributesToRetrieve","definitelyTypedPackageName","types","definitelyTyped","preflightBinPath","dirname","fileURLToPath","noUnusedAndMissingDependencies","ignoredPackagePatterns","startsWith","unusedDependenciesStdout","missingDependenciesStdout","messages","str","missingDependenciesStdoutFiltered","missingDependency","some","excludedDependency","noExtraneousFilesCommittedToGit","noSecretsCommittedToGit","preflightIsLatestVersion","os","platform","prettierCheck","stderr","stderrWithoutPackageJsonWarning","ignoredFilePatterns","unformattedFiles","file","ignoredFilePattern","projectFolderNameMatchesCorrectFormat","currentDirectoryName","basename","lowercaseHyphenedDirectoryName","toLowerCase","replaceAll","useSinglePackageManager","console","log","listrTasks","task","ctx","newListr","eslint","prettier","module","default","Listr","exitOnError","rendererOptions","collapseErrors","removeEmptyLines","formatOutput","fallbackRenderer","concurrent","run"],"mappings":";;;;;;;;;;;;;;;;AAGA;;AACA,MAAMA,qBAAqB,GAAG,GAA9B;SAEwBC,eAAeC;AACrC,YAAUF,0BAA0BG,KAAK,CAACC,GAAN,CAAU,GAAV,KAAkBF,SAAtD;AACD;;ACNM,eAAeG,OAAf;AACL,QAAM;AAAEC,IAAAA;AAAF,MAAa,MAAMC,YAAY,CAAC,qBAAD,EAAwB;AAC3DC,IAAAA,MAAM,EAAE;AADmD,GAAxB,CAArC;AAGA,SAAO,eAAeC,IAAf,CAAoBH,MAApB,CAAP;AACD;;ACFM,MAAMI,KAAK,GAAG,8BAAd;AAEP,AAAe,eAAeC,wBAAf;AACb,QAAM;AAAEL,IAAAA,MAAM,EAAEM;AAAV,MAAuB,MAAML,YAAY,CAAC,iBAAD,CAA/C;AAEA,QAAMM,iBAAiB,GAAGD,QAAQ,KAAK,EAAvC;;AAEA,MAAIC,iBAAJ,EAAuB;AACrB,UAAMC,QAAE,CAACC,SAAH,CAAa,mBAAb,EAAkC,WAAlC,CAAN;AACD;;AAED,QAAM;AAAET,IAAAA;AAAF,MAAa,MAAMC,YAAY,CAAC,wBAAD,CAArC;;AAEA,MAAID,MAAM,KAAK,EAAf,EAAmB;AACjB,UAAMU,2BAA2B,GAC/BV,MAAM,CAACW,IAAP,OAAkB,kBAAlB,KAAyC,MAAMZ,OAAO,EAAtD,CADF;AAEA,UAAM,IAAIa,KAAJ;UAEAZ,SACFU,2BAA2B;;;;UAKzBf,cAAc,CAAC,sBAAD,GALW,GAMvB;OATF,CAAN;AAaD;AACF;;;;;;;;ACnCD,MAAMkB,IAAI,GAAG,MAAb;AAEA,SAAwBC,iBAAiBC;AACvC,MAAI,OAAOA,KAAP,KAAiB,QAArB,EAA+B;AAC7B,UAAM,IAAIC,SAAJ,iCAA8C,OAAOD,SAArD,CAAN;AACD;;AAED,SAAOA,KAAK,CAACE,OAAN,CAAc,IAAIC,MAAJ,CAAWL,IAAX,EAAiB,GAAjB,CAAd,EAAqC,IAArC,CAAP;AACD;;ACLM,MAAMT,OAAK,GAAG,QAAd;AAEP,AAAe,eAAee,WAAf;AACb,MAAI;AACF,UAAMlB,YAAY,CAAC,kDAAD,CAAlB;AACD,GAFD,CAEE,OAAOmB,KAAP,EAAc;AACd,UAAM;AAAEpB,MAAAA;AAAF,QAAaoB,KAAnB;AACA,UAAMC,KAAK,GAAGrB,MAAM,CAACsB,KAAP,CAAa,IAAb,CAAd,CAFc;;AAKd,QAAI,CAAC,kBAAkBnB,IAAlB,CAAuBkB,KAAK,CAACA,KAAK,CAACE,MAAN,GAAe,CAAhB,CAA5B,CAAL,EAAuD;AACrD,YAAMH,KAAN;AACD;;AAED,UAAM,IAAIR,KAAJ;UAEAE,gBAAgB,CAACd,MAAD,CAAhB,CACCsB,KADD,CACO,IADP;AAAA,KAGCE,MAHD,CAGSC,IAAD,IAAU,iBAAiBtB,IAAjB,CAAsBsB,IAAtB,CAHlB;AAAA,KAKCC,GALD,CAKMD,IAAD;AAAA;;AAAA,4BAAUA,IAAI,CAACE,KAAL,CAAW,oBAAX,CAAV,qBAAU,YAAmC,CAAnC,CAAV;AAAA,KALL;AAAA,KAOCC,MAPD,CAOQ,CAACC,sBAAD,EAAmCJ,IAAnC;AACN,UAAIA,IAAI,IAAI,CAACI,sBAAsB,CAACC,QAAvB,CAAgCL,IAAhC,CAAb,EAAoD;AAClDI,QAAAA,sBAAsB,CAACE,IAAvB,CAA4BN,IAA5B;AACD;;AACD,aAAOI,sBAAP;AACD,KAZD,EAYG,EAZH,EAaCG,IAbD,CAaM,IAbN;;;OAFA,CAAN;AAoBD;AACF;;;;;;;;AChCD,MAAMC,SAAO,gBAAGC,aAAa,iBAAIC,OAAO,CAACC,GAAR,KAAJ,CAA7B;;AAEA,AAAO,MAAMhC,OAAK,GAAG,iCAAd;AAEP,AAAe,eAAeiC,mBAAf;AACb,QAAM;AAAErC,IAAAA,MAAM,EAAEsC;AAAV,MAA4B,MAAMrC,YAAY,CAClD,0CADkD,CAApD;AAIA,MAAIsC,YAAJ;;AAEA,MAAI;AACF,UAAMC,2BAA2B,GAAGP,SAAO,CAACQ,OAAR,CAClC,sCADkC,CAApC;;AAIAF,IAAAA,YAAY,GAAGG,IAAI,CAACC,KAAL,CACb,MAAMnC,QAAE,CAACoC,QAAH,CAAYJ,2BAAZ,EAAyC,OAAzC,CADO,EAEbK,OAFF;AAGD,GARD,CAQE,OAAOC,GAAP,EAAY;;AAEd,MAAI,OAAOP,YAAP,KAAwB,WAA5B,EAAyC;AACvC,UAAM,IAAI3B,KAAJ;OAAA,CAAN;AAID;;AAED,MAAImC,MAAM,CAACC,EAAP,CAAUV,aAAV,EAAyBC,YAAzB,CAAJ,EAA4C;AAC1C,UAAM,IAAI3B,KAAJ,yDACoD2B,kDAAkDD;OADtG,CAAN;AAID;;AAED,MAAIW,mBAAJ;;AAEA,MAAI;AACFA,IAAAA,mBAAmB,GACjB,CAAC,MAAMzC,QAAE,CAACoC,QAAH,CAAY,iBAAZ,EAA+B,OAA/B,CAAP,EAAgDjC,IAAhD;;;;;yBADF;AAQD,GATD,CASE,OAAOmC,GAAP,EAAY;AACZ,UAAM,IAAIlC,KAAJ;OAAA,CAAN;AAID;;AAED,MAAI,CAACqC,mBAAL,EAA0B;AACxB,UAAM,IAAIrC,KAAJ;OAAA,CAAN;AAID;;AAED,QAAMsC,wBAAwB,GAAG,EAAjC;;AAEA,aAAW,MAAM;AAAEC,IAAAA;AAAF,GAAjB,IAA6BC,QAAQ,CAAC,GAAD,EAAM;AACzCC,IAAAA,eAAe,EAAE,CAAC,OAAD,EAAU,QAAV,EAAoB,eAApB,CADwB;AAEzCC,IAAAA,UAAU,EAAE,CAAC,MAAD,EAAS,OAAT,EAAkB,MAAlB,EAA0B,OAA1B;AAF6B,GAAN,CAArC,EAGI;AACF,UAAMC,YAAY,GAAG,MAAM/C,QAAE,CAACoC,QAAH,CAAYO,IAAZ,EAAkB,OAAlB,CAA3B;;AACA,QAAI,8CAA8ChD,IAA9C,CAAmDoD,YAAnD,CAAJ,EAAsE;AACpEL,MAAAA,wBAAwB,CAACnB,IAAzB,CAA8BoB,IAA9B;AACD;AACF;;AAED,MAAID,wBAAwB,CAAC3B,MAAzB,GAAkC,CAAtC,EAAyC;AACvC,UAAM,IAAIX,KAAJ;UAEAsC,wBAAwB,CAAClB,IAAzB,CAA8B,IAA9B;;;OAFA,CAAN;AAOD;AACF;;;;;;;;SCrFuBwB;AACtB,QAAMC,WAAW,GAAGC,IAAI,CAACC,KAAL,CAAWD,IAAI,CAACE,MAAL,MAAiBC,UAAU,CAACtC,MAAX,GAAoB,CAArC,CAAX,CAApB;AACA,SAAOsC,UAAU,CAACJ,WAAD,CAAjB;AACD;;ACCM,MAAMrD,OAAK,GAAG,mDAAd;AAEP,AAAe,eAAe0D,iBAAf;AACb,QAAM;AAAE9D,IAAAA;AAAF,MAAa,MAAMC,YAAY,CAAC,2BAAD,CAArC;AAEA,QAAM8D,OAAO,GAAG/D,MAAM,CACnBiB,OADa,CACL,iBADK,EACc,qBADd,EAEbA,OAFa,CAEL,MAFK,EAEG,EAFH,CAAhB;AAIA,QAAM+C,IAAI,GAAG,MAAM,CAAC,MAAMC,KAAK,CAACF,OAAD,CAAZ,EAAuBG,IAAvB,EAAnB;AAEA,QAAMC,CAAC,GAAGC,OAAO,CAACC,IAAR,CAAaL,IAAb,CAAV;AAEA,QAAMM,iBAAiB,GAAGH,CAAC,CAAC,IAAD,CAAD,CACvB3C,MADuB,CAChB;AACN,WAAO2C,CAAC,CAAC,IAAD,CAAD,CAAQD,IAAR,GAAevD,IAAf,OAA0B,OAAjC;AACD,GAHuB,EAIvB4D,OAJuB,CAIf,KAJe,EAKvB/C,MALuB,CAKhB;AACN,WAAO2C,CAAC,CAAC,IAAD,CAAD,CAAQK,QAAR,CAAiB,uBAAjB,EAA0CjD,MAA1C,GAAmD,CAA1D;AACD,GAPuB,EAQvBiD,QARuB,CAQd,uBARc,EASvBC,IATuB,GAUvBD,QAVuB,CAUd,SAVc,EAWvBE,IAXuB,CAWlB,MAXkB,CAA1B;;AAaA,MAAI,CAACJ,iBAAL,EAAwB;AACtB,UAAM,IAAI1D,KAAJ,wDACmDmD,sIADnD,CAAN;AAGD;;AAED,QAAMY,QAAQ,GAAG,MAAMV,KAAK,CAACK,iBAAD,EAAoB;AAC9CM,IAAAA,OAAO,EAAE;AACP;AACA,oBAAcpB,eAAe;AAFtB;AADqC,GAApB,CAA5B;;AAOA,MAAI,CAACmB,QAAQ,CAACE,EAAd,EAAkB;AAChB,UAAM,IAAIjE,KAAJ,qCACgCmD,+EAA+EY,QAAQ,CAACG,WAAWH,QAAQ,CAACI,cAD5I,CAAN;AAGD;AACF;;;;;;;;AC7CM,MAAM3E,OAAK,GAAG,qCAAd;AAEP,AAAe,eAAe4E,yBAAf;AACb,MAAI,CAAC,MAAM/E,YAAY,CAAC,4BAAD,CAAnB,EAAmDD,MAAnD,KAA8D,EAAlE,EAAsE;AACpE,UAAM,IAAIY,KAAJ;;UAGAjB,cAAc,CAAC,iCAAD;OAHd,CAAN;AAMD;;AAED,MAAI,CAAC,MAAMM,YAAY,CAAC,yBAAD,CAAnB,EAAgDD,MAAhD,KAA2D,YAA/D,EAA6E;AAC3E,UAAM,IAAIY,KAAJ,CAAU,2BAAV,CAAN;AACD;;AAED,QAAMqE,sBAAsB,GAAGnE,gBAAgB,CAC7C,MAAMN,QAAE,CAACoC,QAAH,CAAY,cAAZ,EAA4B,MAA5B,CADuC,CAAhB,CAG5BtB,KAH4B,CAGtB,IAHsB,EAI5BM,MAJ4B,CAIrB,CAACsD,KAAD,EAAQzD,IAAR,KAAiByD,KAAK,IAAI,uBAAuB/E,IAAvB,CAA4BsB,IAA5B,CAJL,EAIwC,KAJxC,CAA/B;;AAMA,MAAI,CAACwD,sBAAL,EAA6B;AAC3B,UAAM,IAAIrE,KAAJ,CAAU,sCAAV,CAAN;AACD;AACF;;;;;;;;AC4BM,MAAMuE,kBAAkB,gBAAGzC,IAAI,CAACC,KAAL,CAChC,mBAAMnC,QAAE,CAACoC,QAAH,CAAY,cAAZ,EAA4B,OAA5B,CAD0B,CAA3B;AAIP,AAAO,MAAMwC,oBAAoB,gBAAG1C,IAAI,CAACC,KAAL,CAClC,mBAAMnC,QAAE,CAACoC,QAAH,eAAY,IAAIyC,GAAJ,CAAQ,iBAAR,EAA2BC,MAAM,CAACC,IAAP,CAAYC,GAAvC,CAAZ,EAAyD,OAAzD,CAD4B,CAA7B;;AC3DA,MAAMpF,OAAK,GAAG,qCAAd;AAEP,SAAwBqF;AACtB,QAAMC,wBAAwB,GAAGC,MAAM,CAACC,IAAP,CAC/BT,kBAAkB,CAACU,YADY,CAAjC;;AAGA,MACEH,wBAAwB,CAAC5D,QAAzB,CAAkC,MAAlC,KACA,CAAC4D,wBAAwB,CAAC5D,QAAzB,CAAkC,OAAlC,CAFH,EAGE;AACA,UAAM,IAAIlB,KAAJ;;UAGAjB,cAAc,CAAC,gBAAD;OAHd,CAAN;AAMD;AACF;;ACdD,MAAMmG,MAAM,gBAAGC,aAAa;AAE1B;AACA;AACA,YAJ0B;AAK1B,kCAL0B,CAA5B;AAOA,MAAMC,KAAK,gBAAGF,MAAM,CAACG,SAAP,CAAiB,YAAjB,CAAd;AAQA,AAAO,MAAM7F,OAAK,GAAG,+BAAd;AAGP;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,AAAe,eAAe8F,0BAAf;AACb,QAAM;AAAEC,IAAAA,eAAe,GAAG,EAApB;AAAwBN,IAAAA,YAAY,GAAG;AAAvC,MAA8CV,kBAApD;AAEA,QAAMiB,4BAA4B,GAAG,MAAMC,OAAO,CAChDV,MAAM,CAACC,IAAP,CAAYC,YAAZ,CADgD,EAEhD,OAAOS,oBAAP,EAAiDC,UAAjD;;;AACE,QAAI;AACF,YAAMC,eAAe,GAAGvE,OAAO,CAACQ,OAAR,IAAmB8D,yBAAnB,CAAxB;;AAEA,YAAME,iBAAiB,GAAG/D,IAAI,CAACC,KAAL,CACxB,MAAMnC,QAAE,CAACoC,QAAH,CAAY4D,eAAZ,EAA6B,OAA7B,CADkB,CAA1B,CAHE;;AAQF,UAAI,WAAWC,iBAAX,IAAgC,aAAaA,iBAAjD,EAAoE;AAClE,eAAOH,oBAAP;AACD;AACF,KAXD,CAWE,OAAOxD,GAAP,EAAY;;AAEd,QAAI4D,YAAJ;;AAEA,QAAI;AACFA,MAAAA,YAAY,GAAGzE,OAAO,CAACQ,OAAR,IAAmB8D,uBAAnB,CAAf;AACD,KAFD,CAEE,OAAOzD,GAAP,EAAY;;;AAGd,QAAI4D,YAAY,IAAIC,UAAU,CAACD,YAAD,CAA9B,EAA8C;AAC5C,aAAOJ,oBAAP;AACD;;AAED,UAAMM,OAAO,GAAG,MAAMZ,KAAK,CAACa,SAAN,CAA4BN,UAA5B,EAAwC;AAC5DO,MAAAA,oBAAoB,EAAE,CAAC,OAAD;AADsC,KAAxC,CAAtB;AAIA,UAAMC,0BAA0B,qBAAGH,OAAO,CAACI,KAAX,qBAAG,eAAeC,eAAlD;;AAEA,QAAIF,0BAAJ,EAAgC;AAC9B;AACA,UAAIpB,MAAM,CAACC,IAAP,CAAYO,eAAZ,EAA6BrE,QAA7B,CAAsCiF,0BAAtC,CAAJ,EAAuE;AACrE,eAAOT,oBAAP;AACD;;AAEDA,MAAAA,oBAAoB,CAACvE,IAArB,CAA0B,CAACwE,UAAD,EAAaQ,0BAAb,CAA1B;AACD;;AAED,WAAOT,oBAAP;AACD,GA3C+C,EA4ChD,EA5CgD,CAAlD;;AA+CA,MAAIF,4BAA4B,CAAC7E,MAA7B,GAAsC,CAA1C,EAA6C;AAC3C,UAAM,IAAIX,KAAJ;;QAGFjB,cAAc,wBACSyG,4BAA4B,CAChD1E,GADoB,CAChB,CAAC,GAAGqF,0BAAH,CAAD,KAAoCA,0BADpB,EAEpB/E,IAFoB,CAEf,GAFe,GADT;;;OAHZ,CAAN;AAYD;AACF;;AC3FD,MAAM;AAAEhC,EAAAA,MAAM,EAAEkH;AAAV,IAA+B,mBAAMjH,YAAY,WAAA,EAAa;AAClEmC,EAAAA,GAAG,eAAE+E,OAAO,eAACC,aAAa,CAAC9B,MAAM,CAACC,IAAP,CAAYC,GAAb,CAAd;AADsD,CAAb,CAAvD;;ACAO,MAAMpF,OAAK,GAAG,wBAAd;AAEP,AAAe,eAAeiH,8BAAf;AACb,QAAMC,sBAAsB,GAAG;AAE7B,wBAF6B;AAK7B,+BAL6B;AAQ7B,oBAR6B,EAS7B,cAT6B,EAU7B,SAV6B,EAW7B,aAX6B;AAc7B,QAd6B;AAiB7B,gBAjB6B,EAkB7B,oBAlB6B;AAqB7B;AACA;AACA;AACA;AACA,aAzB6B,EA0B7B,4BA1B6B;AA6B7B,cA7B6B,EA8B7B,SA9B6B,EA+B7B,MA/B6B,EAgC7B,wBAhC6B,EAiC7B,gBAjC6B,EAkC7B,YAlC6B,EAmC7B,WAnC6B;AAsC7B,cAtC6B,EAuC7B,UAvC6B;AA0C7B,SA1C6B,EA2C7BtF,IA3C6B,CA2CxB,GA3CwB,CAA/B;;AA6CA,MAAI;AACF,UAAM/B,YAAY,IACbiH,wCAAwCI,yBAD3B,CAAlB;AAGD,GAJD,CAIE,OAAOlG,KAAP,EAAc;AACd,UAAM;AAAEpB,MAAAA;AAAF,QAAaoB,KAAnB;;AACA,QACE,CAACpB,MAAM,CAACuH,UAAP,CAAkB,qBAAlB,CAAD,IACA,CAACvH,MAAM,CAACuH,UAAP,CAAkB,wBAAlB,CADD,IAEA,CAACvH,MAAM,CAACuH,UAAP,CAAkB,sBAAlB,CAHH,EAIE;AACA,YAAMnG,KAAN;AACD;;AAED,UAAM,CAACoG,wBAAD,EAA2BC,yBAA3B,IAAwDzH,MAAM,CAACsB,KAAP,CAC5D,sBAD4D,CAA9D;AAIA,UAAMoG,QAAQ,GAAG,EAAjB;;AAEA,QAAIF,wBAAJ,EAA8B;AAC5BE,MAAAA,QAAQ,CAAC3F,IAAT;UACIyF,wBAAwB,CACvBlG,KADD,CACO,IADP,EAECE,MAFD,CAESmG,GAAD,IAAiBA,GAAG,CAAC7F,QAAJ,CAAa,IAAb,CAFzB,EAGCE,IAHD,CAGM,IAHN;;;;UAOArC,cAAc,CAAC,oCAAD;OARlB;AAUD;;AAED,QAAI8H,yBAAJ,EAA+B;AAC7B;;;;;;;AAOA,YAAMG,iCAAiC,GAAGH,yBAAyB,CAChEnG,KADuC,CACjC,IADiC,EAEvCE,MAFuC,CAE/BqG,iBAAD;AACN,eAAO,EACLA,iBAAiB,CAAC/F,QAAlB,CAA2B,iBAA3B,KACA,CACE,0BADF,EAEE,kCAFF,EAGE,2BAHF,EAIE,yBAJF,EAKE,yBALF,EAME,mCANF,EAOE,sBAPF,EAQE,wBARF,EASE,+BATF,EAUE,2BAVF,EAWE,qBAXF,EAYE,wBAZF,EAaE,uBAbF,EAcE,uBAdF,EAeEgG,IAfF,CAeQC,kBAAD,IACLF,iBAAiB,CAAC/F,QAAlB,CAA2BiG,kBAA3B,CAhBF,CAFK,CAAP;AAqBD,OAxBuC,EAyBvC/F,IAzBuC,CAyBlC,IAzBkC,CAA1C;;AA2BA,UAAI4F,iCAAJ,EAAuC;AACrCF,QAAAA,QAAQ,CAAC3F,IAAT;UACE6F,iCAAiC,CAChCtG,KADD,CACO,IADP,EAECE,MAFD,CAESmG,GAAD,IAAiBA,GAAG,CAAC7F,QAAJ,CAAa,IAAb,CAFzB,EAGCE,IAHD,CAGM,IAHN;;;;UAOArC,cAAc,CAAC,iCAAD;OARhB;AAUD;AACF;;AAED,QAAI+H,QAAQ,CAACnG,MAAT,GAAkB,CAAtB,EAAyB,MAAM,IAAIX,KAAJ,CAAU8G,QAAQ,CAAC1F,IAAT,CAAc,MAAd,CAAV,CAAN;AAC1B;AACF;;ACrIM,MAAM5B,OAAK,GAAG,sCAAd;AAEP,AAAe,eAAe4H,+BAAf;AACb,QAAM;AAAEhI,IAAAA;AAAF,MAAa,MAAMC,YAAY,CACnC,qDADmC,CAArC;;AAIA,MAAID,MAAM,KAAK,EAAf,EAAmB;AACjB,UAAM,IAAIY,KAAJ;UAEAZ;;;;UAIAL,cAAc,CAAC,iCAAD;;;OANd,CAAN;AAWD;AACF;;;;;;;;ACpBM,MAAMS,OAAK,GAAG,6BAAd;AAEP,AAAe,eAAe6H,uBAAf;AACb,QAAM;AAAEjI,IAAAA;AAAF,MAAa,MAAMC,YAAY,CAAC,+BAAD,CAArC;;AAEA,MAAID,MAAM,KAAK,EAAf,EAAmB;AACjB,UAAM,IAAIY,KAAJ;UAEAZ;;;;UAIAL,cAAc,CAAC,oCAAD;;;;UAIdA,cAAc,CAAC,kBAAD;;;;;OAVd,CAAN;AAiBD;AACF;;;;;;;;ACrBM,MAAMS,OAAK,GAAG,6BAAd;AAEP,AAAe,eAAe8H,wBAAf;AACb,QAAM;AAAElI,IAAAA,MAAM,EAAEsC;AAAV,MAA4B,MAAMrC,YAAY,CAClD,uCADkD,CAApD;;AAIA,MAAI8C,MAAM,CAACC,EAAP,CAAUV,aAAV,EAAyB8C,oBAAoB,CAACvC,OAA9C,CAAJ,EAA4D;AAC1D,UAAM,IAAIjC,KAAJ,uCAEFwE,oBAAoB,CAACvC,6CACeP;;UAElC3C,cAAc,IAEZwI,EAAE,CAACC,QAAH,OAAkB,OAAlB,GAA4B,OAA5B,GAAsC,0CAF1B;OALd,CAAN;AAYD;AACF;;;;;;;;ACtBM,MAAMhI,OAAK,GAAG,UAAd;AAEP,AAAe,eAAeiI,aAAf;AACb,MAAI;AACF,UAAMpI,YAAY,mDACkCkC,OAAO,CAACC,GAAR,yCAAoDD,OAAO,CAACC,GAAR,6BAAwCD,OAAO,CAACC,GAAR,2CAD9H,EAEhB;AAAEA,MAAAA,GAAG,EAAE+E,OAAO,CAACC,aAAa,CAAC9B,MAAM,CAACC,IAAP,CAAYC,GAAb,CAAd;AAAd,KAFgB,CAAlB;AAID,GALD,CAKE,OAAOpE,KAAP,EAAc;AACd,UAAM;AAAEpB,MAAAA,MAAF;AAAUsI,MAAAA;AAAV,QAAqBlH,KAA3B;AAEA,UAAMmH,+BAA+B,GAAGD,MAAM,CAACrH,OAAP,CACtC,wDADsC,EAEtC,EAFsC,CAAxC;;AAKA,QAAI,CAACjB,MAAD,IAAWuI,+BAAf,EAAgD;AAC9C,YAAMnH,KAAN;AACD;;AAED,UAAMoH,mBAAmB,GAAG;AAE1B;AACA,kCAH0B;AAM1B;AACA,kCAP0B;AAS1B,yBAT0B,CAA5B;AAYA,UAAMC,gBAAgB,GAAG3H,gBAAgB,CAACd,MAAD,CAAhB,CACtBsB,KADsB,CAChB,IADgB,EAEtBI,GAFsB,CAEjBgH,IAAD;AAEH;AACA;AACAA,IAAAA,IAAI,CAACzH,OAAL,CAAa,qDAAb,EAAoE,EAApE,CANqB,EAQtBO,MARsB,CASpBkH,IAAD,IACE,CAACF,mBAAmB,CAACV,IAApB,CAA0Ba,kBAAD,IACxBA,kBAAkB,CAACxI,IAAnB,CAAwBuI,IAAxB,CADD,CAVkB,CAAzB;;AAeA,QAAID,gBAAgB,CAAClH,MAAjB,GAA0B,CAA9B,EAAiC;AAC/B,YAAM,IAAIX,KAAJ;YAEA6H,gBAAgB,CAACzG,IAAjB,CAAsB,IAAtB;;;;;SAFA,CAAN;AASD;AACF;AACF;;;;;;;;AC7DM,MAAM5B,OAAK,GAAG,4CAAd;AAEP,SAAwBwI;AACtB,QAAMC,oBAAoB,GAAG1F,IAAI,CAAC2F,QAAL,CAAc3G,OAAO,CAACC,GAAR,EAAd,CAA7B;AACA,QAAM2G,8BAA8B,GAAGF,oBAAoB,CACxDG,WADoC,GAEpCC,UAFoC,CAEzB,GAFyB,EAEpB,GAFoB,CAAvC;;AAIA,MAAIJ,oBAAoB,KAAKE,8BAA7B,EAA6D;AAC3D,UAAM,IAAInI,KAAJ,4BACuBiI;;oDAEmBE;;UAE1CpJ,cAAc,CAAC,OAAD;UACdA,cAAc,OACRkJ,wBAAwBE,gCADhB;UAGdpJ,cAAc,OAAOoJ,gCAAP;OATd,CAAN;AAYD;AACF;;;;;;;;ACtBM,MAAM3I,OAAK,GAAG,4BAAd;AAEP,AAAe,eAAe8I,uBAAf;AACb,QAAM;AAAElJ,IAAAA;AAAF,MAAa,MAAMC,YAAY,CACnC,0CADmC,CAArC;;AAIA,MAAID,MAAM,KAAK,EAAf,EAAmB;AACjB,UAAM,IAAIY,KAAJ;;UAGAjB,cAAc,CAAC,4BAAD;;;;UAIdA,cAAc,CAAC,eAAD;;;;UAIdA,cAAc,CAAC,sBAAD;OAXd,CAAN;AAcD;AACF;;;;;;;;ACJDwJ,OAAO,CAACC,GAAR,4BAAuChE,oBAAoB,CAACvC,SAA5D;AAEA,MAAMwG,UAAU,gBAAG;AAEjB;AACAhJ,0BAHiB,EAIjB2E,2BAJiB,EAKjBgD,iCALiB,EAMjBC,yBANiB;AASjBiB,yBATiB;AAYjBN,uCAZiB;AAejB;AACA;AACExI,EAAAA,KAAK,EAAE,wBADT;AAEEkJ,EAAAA,IAAI,EAAE,CAACC,GAAD,EAAgBD,IAAhB,KACJA,IAAI,CAACE,QAAL,CAAc,CACZ,IAAI,CAACrE,kBAAkB,CAACU,YAApB,IACJ,CAACF,MAAM,CAACC,IAAP,CAAYT,kBAAkB,CAACU,YAA/B,EAA6C/D,QAA7C,CAAsD,MAAtD,CADG,GAEA,EAFA,GAGA,CACE;AACE1B,IAAAA,KAAK,EAAEqF,OADT;AAEE6D,IAAAA,IAAI,EAAE7D;AAFR,GADF,CAHJ,CADY,EAUZ;AACErF,IAAAA,KAAK,EAAEiH,OADT;AAEEiC,IAAAA,IAAI,EAAEjC;AAFR,GAVY,EAcZ;AACEjH,IAAAA,KAAK,EAAE8F,OADT;AAEEoD,IAAAA,IAAI,EAAEpD;AAFR,GAdY,CAAd;AAHJ,CAhBiB;AAyCjBpC,mBAzCiB;AA4CjB2F,MA5CiB,EA6CjBC,QA7CiB;AAgDjBrH,qBAhDiB,EAiDjB6F,0BAjDiB,EAkDjBxG,GAlDiB,CAkDZiI,MAAD;AACJ,MAAI,UAAUA,MAAd,EAAsB,OAAOA,MAAP;AACtB,SAAO;AACLvJ,IAAAA,KAAK,EAAEuJ,MAAM,CAACvJ,KADT;AAELkJ,IAAAA,IAAI,EAAEK,MAAM,CAACC;AAFR,GAAP;AAID,CAxDkB,CAAnB;AA0DA,MAAM,IAAIC,KAAJ,CAAUR,UAAV,EAAsB;AAC1BS,EAAAA,WAAW,EAAE,KADa;AAE1BC,EAAAA,eAAe,EAAE;AACfC,IAAAA,cAAc,EAAE,KADD;AAEfC,IAAAA,gBAAgB,EAAE,KAFH;AAGfC,IAAAA,YAAY,EAAE;AAHC,GAFS;AAO1BC,EAAAA,gBAAgB,EAAE,SAPQ;AAQ1BC,EAAAA,UAAU,EAAE;AARc,CAAtB,EASHC,GATG,EAAN"}
|
|
1
|
+
{"version":3,"file":"preflight.esm.js","sources":["../src/util/commandExample.ts","../src/util/isDrone.ts","../src/checks/allChangesCommittedToGit.ts","../src/checks/eslint.ts","../src/checks/eslintConfigIsValid.ts","../src/util/randomUserAgent.ts","../src/checks/linkOnGithubAbout.ts","../src/util/normalizeNewline.ts","../src/checks/nodeModulesIgnoredFromGit.ts","../src/util/packageJson.ts","../src/checks/noDependencyProblems/nextJsProjectHasSharpInstalled.ts","../src/checks/noDependencyProblems/noDependenciesWithoutTypes.ts","../src/util/preflightBinPath.ts","../src/checks/noDependencyProblems/noUnusedDependencies.ts","../src/checks/noExtraneousFilesCommittedToGit.ts","../src/checks/noSecretsCommittedToGit.ts","../src/checks/preflightIsLatestVersion.ts","../src/checks/prettier.ts","../src/checks/projectFolderNameMatchesCorrectFormat.ts","../src/checks/stylelint.ts","../src/checks/stylelintConfigIsValid.ts","../src/checks/useSinglePackageManager.ts","../src/index.ts"],"sourcesContent":["import chalk from 'chalk';\n\n// https://www.compart.com/en/unicode/U+2800\n// eslint-disable-next-line security/detect-bidi-characters -- Intentional use of unusual character for formatting\nconst emptyBrailleCharacter = '';\n\nexport default function commandExample(command: string) {\n return `${emptyBrailleCharacter} ${chalk.dim('$')} ${command}`;\n}\n","import { execaCommand } from 'execa';\n\nexport async function isDrone() {\n const { stdout } = await execaCommand('cat /etc/os-release', {\n reject: false,\n });\n return /Alpine Linux/.test(stdout);\n}\n","import { promises as fs } from 'node:fs';\nimport { execaCommand } from 'execa';\nimport commandExample from '../util/commandExample';\nimport { isDrone } from '../util/isDrone';\n\nexport const title = 'All changes committed to Git';\n\nexport default async function allChangesCommittedToGit() {\n const { stdout: replSlug } = await execaCommand('echo $REPL_SLUG');\n\n const isRunningInReplIt = replSlug !== '';\n\n if (isRunningInReplIt) {\n await fs.writeFile('.git/info/exclude', '.replit\\n');\n }\n\n const { stdout } = await execaCommand('git status --porcelain');\n\n if (stdout !== '') {\n const onlyPnpmLockModifiedOnDrone =\n stdout.trim() === 'M pnpm-lock.yaml' && (await isDrone());\n throw new Error(\n `Some changes have not been committed to Git:\n ${stdout}${\n onlyPnpmLockModifiedOnDrone\n ? `\n\n The only file with changes is the pnpm-lock.yaml file, indicating that npm was incorrectly used in addition to pnpm (eg. an \"npm install\" command was run). To fix this, force regeneration of the pnpm-lock.yaml file locally with the following command and then commit the changes:\n\n ${commandExample('pnpm install --force')}`\n : ''\n }\n `,\n );\n }\n}\n","import { sep } from 'node:path';\nimport { ESLint } from 'eslint';\nimport { execaCommand } from 'execa';\n\nconst errorKey = 'errorCount' as const;\nconst warningKey = 'warningCount' as const;\n\nexport const title = 'ESLint';\n\nexport default async function eslintCheck() {\n try {\n await execaCommand('pnpm eslint . --max-warnings 0 --format json');\n } catch (error) {\n const { stdout } = error as { stdout: string };\n\n // If no ESLint problems detected, throw the error\n if (!new RegExp(`\"${errorKey}\":|\"${warningKey}\":`).test(stdout)) {\n throw error;\n }\n\n throw new Error(\n `ESLint problems found in the following files:\n ${(JSON.parse(stdout) as ESLint.LintResult[])\n .filter(\n (eslintResult) =>\n !(eslintResult[errorKey] === 0 && eslintResult[warningKey] === 0),\n )\n // Make paths relative to the project:\n // before: /home/projects/next-student-project/app/api/hello/route.js\n // after: app/api/hello/route.js\n .map(({ filePath }) => filePath.replace(`${process.cwd()}${sep}`, ''))\n .join('\\n')}\n\n Open these files in your editor - there should be problems to fix\n `,\n );\n }\n}\n","import { promises as fs } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { execaCommand } from 'execa';\nimport readdirp from 'readdirp';\nimport semver from 'semver';\n\nconst require = createRequire(`${process.cwd()}/`);\n\nexport const title = 'ESLint config is latest version';\n\nexport default async function eslintConfigIsValid() {\n const { stdout: remoteVersion } = await execaCommand(\n 'npm show eslint-config-upleveled version',\n );\n\n let localVersion;\n\n try {\n const eslintConfigPackageJsonPath = require.resolve(\n 'eslint-config-upleveled/package.json',\n );\n\n localVersion = JSON.parse(\n await fs.readFile(eslintConfigPackageJsonPath, 'utf-8'),\n ).version;\n } catch (err) {}\n\n if (typeof localVersion === 'undefined') {\n throw new Error(\n `The UpLeveled ESLint Config has not been installed - please install using the instructions on https://www.npmjs.com/package/eslint-config-upleveled\n `,\n );\n }\n\n if (semver.gt(remoteVersion, localVersion)) {\n throw new Error(\n `Your current version of the UpLeveled ESLint Config (${localVersion}) is older than the latest version ${remoteVersion} - upgrade by running all lines of the install instructions on https://www.npmjs.com/package/eslint-config-upleveled\n `,\n );\n }\n\n let eslintConfigMatches;\n\n try {\n eslintConfigMatches =\n (await fs.readFile('./.eslintrc.cjs', 'utf-8')).trim() ===\n `/** @type {import('@typescript-eslint/utils').TSESLint.Linter.Config} */\nconst config = {\n extends: ['upleveled'],\n};\n\nmodule.exports = config;`;\n } catch (err) {\n throw new Error(\n `Error reading your .eslintrc.cjs file - please delete the file if it exists and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled\n `,\n );\n }\n\n if (!eslintConfigMatches) {\n throw new Error(\n `Your .eslintrc.cjs file does not match the configuration file template - please delete the file and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled\n `,\n );\n }\n\n const eslintDisableOccurrences = [];\n\n for await (const { path } of readdirp('.', {\n directoryFilter: ['!.git', '!.next', '!node_modules'],\n fileFilter: ['*.js', '*.jsx', '*.ts', '*.tsx'],\n })) {\n const fileContents = await fs.readFile(path, 'utf-8');\n if (/eslint-disable|eslint [a-z0-9@/-]+: (0|off)/.test(fileContents)) {\n eslintDisableOccurrences.push(path);\n }\n }\n\n if (eslintDisableOccurrences.length > 0) {\n throw new Error(\n `ESLint has been disabled in the following files:\n ${eslintDisableOccurrences.join('\\n')}\n\n Remove all comments disabling or modifying ESLint rule configuration (eg. eslint-disable and eslint-disable-next-line comments) and fix the problems\n `,\n );\n }\n}\n","import userAgents from 'top-user-agents';\n\nexport default function randomUserAgent() {\n const randomIndex = Math.floor(Math.random() * (userAgents.length - 1));\n return userAgents[randomIndex]!;\n}\n","import cheerio from 'cheerio';\nimport type { Element } from 'domhandler';\nimport { execaCommand } from 'execa';\nimport fetch from 'node-fetch';\nimport randomUserAgent from '../util/randomUserAgent';\n\nexport const title = 'GitHub repo has deployed project link under About';\n\nexport default async function linkOnGithubAbout() {\n const { stdout } = await execaCommand('git remote get-url origin');\n\n const repoUrl = stdout\n .replace('git@github.com:', 'https://github.com/')\n .replace('.git', '');\n\n const html = await (await fetch(repoUrl)).text();\n\n const $ = cheerio.load(html);\n\n const urlInAboutSection = $('h2')\n .filter(function (this: Element) {\n return $(this).text().trim() === 'About';\n })\n .nextAll('div')\n .filter(function (this: Element) {\n return $(this).children('.octicon.octicon-link').length > 0;\n })\n .children('.octicon.octicon-link')\n .next()\n .children('a[href]')\n .attr('href');\n\n if (!urlInAboutSection) {\n throw new Error(\n `Deployed project link not found in About section on ${repoUrl}. Click on the cog symbol to the right of the About heading and paste the Repl.it / Netlify / Fly.io link in the Website box.`,\n );\n }\n\n const response = await fetch(urlInAboutSection, {\n headers: {\n // For repl.it\n 'user-agent': randomUserAgent(),\n },\n });\n\n if (!response.ok) {\n throw new Error(\n `Project link in About section on ${repoUrl} is not returning a proper status code: the link returns status code ${response.status} (${response.statusText}).`,\n );\n }\n}\n","const CRLF = '\\r\\n';\n\nexport default function normalizeNewline(input: string) {\n if (typeof input !== 'string') {\n throw new TypeError(`Expected a \\`string\\`, got \\`${typeof input}\\``);\n }\n\n return input.replace(new RegExp(CRLF, 'g'), '\\n');\n}\n","import { promises as fs } from 'node:fs';\nimport { execaCommand } from 'execa';\nimport commandExample from '../util/commandExample';\nimport normalizeNewline from '../util/normalizeNewline';\n\nexport const title = 'node_modules/ folder ignored in Git';\n\nexport default async function nodeModulesIgnoredFromGit() {\n if ((await execaCommand('git ls-files node_modules/')).stdout !== '') {\n throw new Error(\n `node_modules/ folder committed to Git. Remove it using:\n\n ${commandExample('git rm -r --cached node_modules')}\n `,\n );\n }\n\n if ((await execaCommand('git ls-files .gitignore')).stdout !== '.gitignore') {\n throw new Error('.gitignore file not found');\n }\n\n const nodeModulesInGitignore = normalizeNewline(\n await fs.readFile('./.gitignore', 'utf8'),\n )\n .split('\\n')\n .reduce((found, line) => found || /^\\/?node_modules\\/?$/.test(line), false);\n\n if (!nodeModulesInGitignore) {\n throw new Error('node_modules not found in .gitignore');\n }\n}\n","import { promises as fs } from 'node:fs';\nimport { URL } from 'node:url';\n\ntype PackageJson = {\n name: string;\n version: string;\n description?: string;\n keywords?: string;\n homepage?: string;\n bugs?: {\n email?: string;\n url?: string;\n };\n license?: string;\n author?:\n | string\n | {\n name: string;\n email?: string;\n url?: string;\n };\n contributors?:\n | string[]\n | {\n name: string;\n email?: string;\n url?: string;\n }[];\n files?: string[];\n main?: string;\n browser?: string;\n bin?: Record<string, string>;\n man?: string;\n directories?: {\n lib?: string;\n bin?: string;\n man?: string;\n doc?: string;\n example?: string;\n test?: string;\n };\n repository?: {\n type?: 'git';\n url?: string;\n directory?: string;\n };\n scripts?: Record<string, string>;\n config?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n bundledDependencies?: string[];\n engines?: Record<string, string>;\n os?: string[];\n cpu?: string[];\n};\n\nexport const projectPackageJson = JSON.parse(\n await fs.readFile('package.json', 'utf-8'),\n) as PackageJson;\n\nexport const preflightPackageJson = JSON.parse(\n await fs.readFile(new URL('../package.json', import.meta.url), 'utf-8'),\n) as PackageJson;\n","import commandExample from '../../util/commandExample';\nimport { projectPackageJson } from '../../util/packageJson';\n\nexport const title = 'Next.js project has sharp installed';\n\nexport default function nextJsProjectHasSharpInstalled() {\n const dependenciesPackageNames = Object.keys(\n projectPackageJson.dependencies!,\n );\n if (\n dependenciesPackageNames.includes('next') &&\n !dependenciesPackageNames.includes('sharp')\n ) {\n throw new Error(\n `Next.js projects should have sharp installed for better image optimization. Install it with:\n\n ${commandExample('pnpm add sharp')}\n `,\n );\n }\n}\n","import { existsSync, promises as fs } from 'node:fs';\nimport algoliasearch from 'algoliasearch';\nimport pReduce from 'p-reduce';\nimport commandExample from '../../util/commandExample';\nimport { projectPackageJson } from '../../util/packageJson';\n\nconst client = algoliasearch(\n // Application ID and API key specific to UpLeveled\n // Preflight. Please don't use anywhere else without\n // asking Algolia's permission.\n 'OFCNCOG2CU', // Application ID\n 'ec73550aa8b2936dab436d4e02144784', // API Key\n);\nconst index = client.initIndex('npm-search');\n\ninterface AlgoliaObj {\n types?: {\n definitelyTyped?: string;\n };\n}\n\nexport const title = 'No dependencies without types';\n\n// This is a naive check for matching @types/<pkg name> packages\n// that the student hasn't yet installed. It is not intended to\n// be an exhaustive check for any types for all packages.\n//\n// It attempts to address scenarios such as this with\n// `styled-components`:\n//\n// https://learn.upleveled.io/courses/btcmp-l-webfs-gen-0/modules/122-cheatsheet-css-in-js/#eslint-errors-with-styled-components\nexport default async function noDependenciesWithoutTypes() {\n const { devDependencies = {}, dependencies = {} } = projectPackageJson;\n\n const dependenciesWithMissingTypes = await pReduce(\n Object.keys(dependencies),\n async (filteredDependencies: [string, string][], dependency: string) => {\n // Return early here because:\n // - Algolia reports \"ObjectID does not exist\" for `@upleveled/react-scripts`\n // - `@upleveled/react-scripts` has no types to install\n if (dependency === '@upleveled/react-scripts') {\n return filteredDependencies;\n }\n\n try {\n const packageJsonPath = require.resolve(`${dependency}/package.json`);\n\n const modulePackageJson = JSON.parse(\n await fs.readFile(packageJsonPath, 'utf-8'),\n );\n\n // If the keys \"types\" or \"typings\" are in the module's `package.json`, bail out\n if ('types' in modulePackageJson || 'typings' in modulePackageJson) {\n return filteredDependencies;\n }\n } catch (err) {}\n\n let indexDTsPath;\n\n try {\n indexDTsPath = require.resolve(`${dependency}/index.d.ts`);\n } catch (err) {}\n\n // If the index.d.ts file exists inside the module's directory, bail out\n if (indexDTsPath && existsSync(indexDTsPath)) {\n return filteredDependencies;\n }\n\n const results = await index.getObject<AlgoliaObj>(dependency, {\n attributesToRetrieve: ['types'],\n });\n\n const definitelyTypedPackageName = results.types?.definitelyTyped;\n\n if (definitelyTypedPackageName) {\n // If a matching `@types/<package name>` has been already installed in devDependencies, bail out\n if (Object.keys(devDependencies).includes(definitelyTypedPackageName)) {\n return filteredDependencies;\n }\n\n filteredDependencies.push([dependency, definitelyTypedPackageName]);\n }\n\n return filteredDependencies;\n },\n [],\n );\n\n if (dependenciesWithMissingTypes.length > 0) {\n throw new Error(\n `Dependencies found without types. Add the missing types with:\n\n ${commandExample(\n `pnpm add --save-dev ${dependenciesWithMissingTypes\n .map(([, definitelyTypedPackageName]) => definitelyTypedPackageName)\n .join(' ')}`,\n )}\n\n If the dependencies above are already in your package.json, check that they have not been incorrectly installed as regular dependencies in the \"dependencies\" object - they should be installed inside \"devDependencies\" (using the --save-dev flag mentioned above). To fix this situation, remove the dependencies and run the command above exactly.\n `,\n );\n }\n}\n","import { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { execaCommand } from 'execa';\n\nconst { stdout: preflightBinPath } = await execaCommand(`pnpm bin`, {\n cwd: dirname(fileURLToPath(import.meta.url)),\n});\n\nexport default preflightBinPath;\n","import { execaCommand } from 'execa';\nimport commandExample from '../../util/commandExample';\nimport preflightBinPath from '../../util/preflightBinPath';\n\nexport const title = 'No unused dependencies';\n\nexport default async function noUnusedAndMissingDependencies() {\n const ignoredPackagePatterns = [\n // Unused dependency detected in https://github.com/upleveled/next-portfolio-dev\n '@graphql-codegen/cli',\n\n // Unused dependency detected in create-react-app\n '@testing-library/user-event',\n\n // Tailwind CSS\n '@tailwindcss/jit',\n 'autoprefixer',\n 'postcss',\n 'tailwindcss',\n\n // Sass (eg. in create-react-app)\n 'sass',\n\n // ESLint configuration\n 'babel-eslint',\n 'eslint-config-next',\n\n // TODO: Remove this once depcheck issue is fixed:\n // PR: https://github.com/depcheck/depcheck/pull/790\n // Issue: https://github.com/depcheck/depcheck/issues/791\n //\n // Stylelint configuration\n 'stylelint',\n 'stylelint-config-upleveled',\n\n // Testing\n 'babel-jest',\n 'cypress',\n 'jest',\n 'jest-environment-jsdom',\n 'jest-puppeteer',\n 'playwright',\n 'puppeteer',\n\n // TypeScript\n 'typescript',\n '@types/*',\n\n // Next.js\n 'sharp',\n ].join(',');\n\n try {\n await execaCommand(\n `${preflightBinPath}/depcheck --ignores=\"${ignoredPackagePatterns}\"`,\n );\n } catch (error) {\n const { stdout } = error as { stdout: string };\n if (\n !stdout.startsWith('Unused dependencies') &&\n !stdout.startsWith('Unused devDependencies') &&\n !stdout.startsWith('Missing dependencies')\n ) {\n throw error;\n }\n\n const [unusedDependenciesStdout, missingDependenciesStdout] = stdout.split(\n 'Missing dependencies',\n );\n\n const messages = [];\n\n if (unusedDependenciesStdout) {\n messages.push(`Unused dependencies found:\n ${unusedDependenciesStdout\n .split('\\n')\n .filter((str: string) => str.includes('* '))\n .join('\\n')}\n\n Remove these dependencies by running the following command for each dependency:\n\n ${commandExample('pnpm remove <dependency name here>')}\n `);\n }\n\n if (missingDependenciesStdout) {\n /**\n * Temporary workaround to filter out eslint-config-upleveled peer dependencies\n * not listed in `package.json`, which are flagged as missing dependencies by depcheck\n *\n * TODO: Remove this variable once this depcheck issue is fixed:\n * https://github.com/depcheck/depcheck/issues/789\n */\n const missingDependenciesStdoutFiltered = missingDependenciesStdout\n .split('\\n')\n .filter((missingDependency) => {\n return !(\n missingDependency.includes('./.eslintrc.cjs') &&\n [\n '@next/eslint-plugin-next',\n '@typescript-eslint/eslint-plugin',\n '@typescript-eslint/parser',\n 'eslint-plugin-upleveled',\n 'eslint-config-react-app',\n 'eslint-import-resolver-typescript',\n 'eslint-plugin-import',\n 'eslint-plugin-jsx-a11y',\n 'eslint-plugin-jsx-expressions',\n 'eslint-plugin-react-hooks',\n 'eslint-plugin-react',\n 'eslint-plugin-security',\n 'eslint-plugin-sonarjs',\n 'eslint-plugin-unicorn',\n ].some((excludedDependency) =>\n missingDependency.includes(excludedDependency),\n )\n );\n })\n .join('\\n');\n\n if (missingDependenciesStdoutFiltered) {\n messages.push(`Missing dependencies found:\n ${missingDependenciesStdoutFiltered\n .split('\\n')\n .filter((str: string) => str.includes('* '))\n .join('\\n')}\n\n Add these missing dependencies by running the following command for each dependency:\n\n ${commandExample('pnpm add <dependency name here>')}\n `);\n }\n }\n\n if (messages.length > 0) throw new Error(messages.join('\\n\\n'));\n }\n}\n","import { execaCommand } from 'execa';\nimport commandExample from '../util/commandExample';\n\nexport const title = 'No extraneous files committed to Git';\n\nexport default async function noExtraneousFilesCommittedToGit() {\n const { stdout } = await execaCommand(\n 'git ls-files .DS_Store yarn-error.log npm-debug.log',\n );\n\n if (stdout !== '') {\n throw new Error(\n `Extraneous files committed to Git:\n ${stdout}\n\n Remove these files from your repo by running the following command for each file:\n\n ${commandExample('git rm --cached <filename here>')}\n\n Once you've removed all files, make sure that it doesn't happen again by adding the filenames above to your .gitignore file.\n `,\n );\n }\n}\n","import { execaCommand } from 'execa';\nimport commandExample from '../util/commandExample';\n\nexport const title = 'No secrets committed to Git';\n\nexport default async function noSecretsCommittedToGit() {\n const { stdout } = await execaCommand('git ls-files .env .env*.local');\n\n if (stdout !== '') {\n throw new Error(\n `Secrets committed to Git 😱:\n ${stdout}\n\n Remove these files from your repo by installing BFG from the System Setup Guide (see Optional Software at the bottom) and running it on each of your files like this:\n\n ${commandExample('bfg --delete-files <filename here>')}\n\n Once you've done this for every secret file, then force push to your repository:\n\n ${commandExample('git push --force')}\n\n More info: https://docs.github.com/en/github/authenticating-to-github/removing-sensitive-data-from-a-repository\n\n Finally, make sure that this doesn't happen again by adding the filenames above to your .gitignore file.\n `,\n );\n }\n}\n","import os from 'node:os';\nimport { execaCommand } from 'execa';\nimport semver from 'semver';\nimport commandExample from '../util/commandExample';\nimport { preflightPackageJson } from '../util/packageJson';\n\nexport const title = 'Preflight is latest version';\n\nexport default async function preflightIsLatestVersion() {\n const { stdout: remoteVersion } = await execaCommand(\n 'npm show @upleveled/preflight version',\n );\n\n if (semver.gt(remoteVersion, preflightPackageJson.version)) {\n throw new Error(\n `Your current version of Preflight (${\n preflightPackageJson.version\n }) is older than the latest version ${remoteVersion} - upgrade with:\n\n ${commandExample(\n `${\n os.platform() === 'linux' ? 'sudo ' : ''\n }pnpm add --global @upleveled/preflight`,\n )}\n `,\n );\n }\n}\n","import { dirname, relative, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { execaCommand } from 'execa';\nimport normalizeNewline from '../util/normalizeNewline';\n\nexport const title = 'Prettier';\n\nexport default async function prettierCheck() {\n try {\n await execaCommand(\n `../node_modules/.bin/prettier --list-different ${process.cwd()}/**/*.{js,jsx,ts,jsx} --ignore-path ${process.cwd()}/.eslintignore --config ${process.cwd()}/prettier.config.cjs --end-of-line auto`,\n { cwd: dirname(fileURLToPath(import.meta.url)) },\n );\n } catch (error) {\n const { stdout, stderr } = error as { stdout: string; stderr: string };\n\n const stderrWithoutPackageJsonWarning = stderr.replace(\n /warning [/.\\\\]*package\\.json: No license field[\\r\\n]*/g,\n '',\n );\n\n if (!stdout || stderrWithoutPackageJsonWarning) {\n throw error;\n }\n\n const ignoredFilePatterns = [\n // File from create-react-app not matching our formatting\n // https://github.com/facebook/create-react-app/blob/fdbde1f3c256b43d5386b5ae3a75083dbd8f0aff/packages/cra-template/template/src/reportWebVitals.js\n /src[/\\\\]reportWebVitals\\.js$/,\n\n // Files from create-next-app not matching our formatting\n // https://github.com/vercel/next.js/blob/5a73859fe8d3659d52e169f97188ae422e0d2ace/packages/create-next-app/templates/default/pages/api/hello.js\n /pages[/\\\\]api[/\\\\]hello\\.js$/,\n // https://github.com/vercel/next.js/blob/aacfa79ddf88e4e1488b63ac253af27110f0a151/packages/create-next-app/templates/default/pages/_app.js\n /pages[/\\\\]_app\\.js$/,\n ];\n\n const unformattedFiles = normalizeNewline(stdout)\n .split('\\n')\n // Make paths relative to the project instead of Preflight, eg:\n // before: ../../../../../../projects/random-color-generator-react-app/src/reportWebVitals.js\n // after: src/reportWebVitals.js\n .map((file) => {\n return file.replace(\n `${relative(\n dirname(fileURLToPath(import.meta.url)),\n process.cwd(),\n )}${sep}`,\n '',\n );\n })\n .filter(\n (file) =>\n !ignoredFilePatterns.some((ignoredFilePattern) =>\n ignoredFilePattern.test(file),\n ),\n );\n\n if (unformattedFiles.length > 0) {\n throw new Error(\n `Prettier has not been run in the following files:\n ${unformattedFiles.join('\\n')}\n\n For each of the files above, open the file in your editor and save the file. This will format the file with Prettier, which will cause changes to appear in Git.\n\n In some very uncommon cases (this probably doesn't apply to you), the mismatch may come from inconsistent end of line characters. Read more here: https://github.com/upleveled/answers/issues/31\n `,\n );\n }\n }\n}\n","import path from 'node:path';\nimport commandExample from '../util/commandExample';\n\nexport const title = 'Project folder name matches correct format';\n\nexport default function projectFolderNameMatchesCorrectFormat() {\n const currentDirectoryName = path.basename(process.cwd());\n const lowercaseHyphenedDirectoryName = currentDirectoryName\n .toLowerCase()\n .replaceAll(' ', '-');\n\n if (currentDirectoryName !== lowercaseHyphenedDirectoryName) {\n throw new Error(\n `Project directory name \"${currentDirectoryName}\" doesn't match the correct format (no spaces or uppercase letters).\n\n Rename the directory to the correct name \"${lowercaseHyphenedDirectoryName}\" with the following sequence of commands:\n\n ${commandExample('cd ..')}\n ${commandExample(\n `mv ${currentDirectoryName} ${lowercaseHyphenedDirectoryName}`,\n )}\n ${commandExample(`cd ${lowercaseHyphenedDirectoryName}`)}\n `,\n );\n }\n}\n","import { sep } from 'node:path';\nimport { execaCommand } from 'execa';\nimport { LintResult } from 'stylelint';\n\nconst errorKey = 'errored' as const;\n\nexport const supportedStylelintFileExtensions = [\n 'css',\n 'sass',\n 'scss',\n 'less',\n 'js',\n 'tsx',\n 'jsx',\n];\n\nexport const title = 'Stylelint';\n\nexport default async function stylelintCheck() {\n try {\n await execaCommand(\n `pnpm stylelint **/*.{${supportedStylelintFileExtensions.join(\n ',',\n )}} --max-warnings 0 --formatter json`,\n );\n } catch (error) {\n const { stdout } = error as { stdout: string };\n\n // If no Stylelint errors detected, throw the error\n if (!new RegExp(`\"${errorKey}\":`).test(stdout)) {\n throw error;\n }\n\n throw new Error(\n `Stylelint problems found in the following files:\n ${(JSON.parse(stdout) as LintResult[])\n .filter((stylelintResult) => stylelintResult[errorKey] === true)\n // Make paths relative to the project:\n // before: /home/projects/random-color-generator-react-app/src/index.css\n // after: src/index.css\n .map(({ source }) => source!.replace(`${process.cwd()}${sep}`, ''))\n .join('\\n')}\n\n Open these files in your editor - there should be problems to fix\n `,\n );\n }\n}\n","import { promises as fs } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { execaCommand } from 'execa';\nimport readdirp from 'readdirp';\nimport semver from 'semver';\nimport { supportedStylelintFileExtensions } from './stylelint';\n\nconst require = createRequire(`${process.cwd()}/`);\n\nexport const title = 'Stylelint config is latest version';\n\nexport default async function stylelintConfigIsValid() {\n const { stdout: remoteVersion } = await execaCommand(\n 'npm show stylelint-config-upleveled version',\n );\n\n let localVersion;\n\n try {\n const stylelintConfigPackageJsonPath = require.resolve(\n 'stylelint-config-upleveled/package.json',\n );\n\n localVersion = JSON.parse(\n await fs.readFile(stylelintConfigPackageJsonPath, 'utf-8'),\n ).version;\n } catch (err) {}\n\n if (typeof localVersion === 'undefined') {\n throw new Error(\n `The UpLeveled Stylelint Config has not been installed - please install using the instructions on https://www.npmjs.com/package/eslint-config-upleveled\n `,\n );\n }\n\n if (semver.gt(remoteVersion, localVersion)) {\n throw new Error(\n `Your current version of the UpLeveled Stylelint Config (${localVersion}) is older than the latest version ${remoteVersion} - upgrade by running:\n\n pnpm add stylelint-config-upleveled@${remoteVersion}`,\n );\n }\n\n let stylelintConfigMatches;\n\n try {\n stylelintConfigMatches =\n (await fs.readFile('./stylelint.config.cjs', 'utf-8')).trim() ===\n `/** @type { import('stylelint').Config } */\nconst config = {\n extends: ['stylelint-config-upleveled'],\n};\n\nmodule.exports = config;`;\n } catch (err) {\n throw new Error(\n `Error reading your stylelint.config.cjs file - please delete the file if it exists and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled\n `,\n );\n }\n\n if (!stylelintConfigMatches) {\n throw new Error(\n `Your stylelint.config.cjs file does not match the configuration file template - please delete the file and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled\n `,\n );\n }\n\n const stylelintDisableOccurrences = [];\n\n for await (const { path } of readdirp('.', {\n directoryFilter: ['!.git', '!.next', '!node_modules'],\n fileFilter: supportedStylelintFileExtensions.map(\n (fileExtension) => `*.${fileExtension}`,\n ),\n })) {\n const fileContents = await fs.readFile(path, 'utf-8');\n if (fileContents.includes('stylelint-disable')) {\n stylelintDisableOccurrences.push(path);\n }\n }\n\n if (stylelintDisableOccurrences.length > 0) {\n throw new Error(\n `Stylelint has been disabled in the following files:\n ${stylelintDisableOccurrences.join('\\n')}\n\n Remove all comments disabling or modifying Stylelint rule configuration (eg. stylelint-disable and stylelint-disable-next-line comments) and fix the problems\n `,\n );\n }\n}\n","import { execaCommand } from 'execa';\nimport commandExample from '../util/commandExample';\n\nexport const title = 'Use single package manager';\n\nexport default async function useSinglePackageManager() {\n const { stdout } = await execaCommand(\n 'git ls-files package-lock.json yarn.lock',\n );\n\n if (stdout !== '') {\n throw new Error(\n `package-lock.json or yarn.lock file committed to Git. Remove it with:\n\n ${commandExample('git rm --cached <filename>')}\n\n After you've removed it, you can delete the file with:\n\n ${commandExample('rm <filename>')}\n\n The presence of this file indicates that another package manager was used in addition to pnpm (eg. \"npm install\" or \"yarn add\" was run). In order to avoid issues with the state of the pnpm-lock.yaml file, we suggest also forcing regeneration this file with the following command:\n\n ${commandExample('pnpm install --force')}\n `,\n );\n }\n}\n","import { Listr } from 'listr2';\nimport * as allChangesCommittedToGit from './checks/allChangesCommittedToGit.js';\nimport * as eslint from './checks/eslint.js';\nimport * as eslintConfigIsValid from './checks/eslintConfigIsValid.js';\nimport * as linkOnGithubAbout from './checks/linkOnGithubAbout.js';\nimport * as nodeModulesIgnoredFromGit from './checks/nodeModulesIgnoredFromGit.js';\nimport * as nextJsProjectHasSharpInstalled from './checks/noDependencyProblems/nextJsProjectHasSharpInstalled.js';\nimport * as noDependenciesWithoutTypes from './checks/noDependencyProblems/noDependenciesWithoutTypes.js';\nimport * as noUnusedAndMissingDependencies from './checks/noDependencyProblems/noUnusedDependencies.js';\nimport * as noExtraneousFilesCommittedToGit from './checks/noExtraneousFilesCommittedToGit.js';\nimport * as noSecretsCommittedToGit from './checks/noSecretsCommittedToGit.js';\nimport * as preflightIsLatestVersion from './checks/preflightIsLatestVersion.js';\nimport * as prettier from './checks/prettier.js';\nimport * as projectFolderNameMatchesCorrectFormat from './checks/projectFolderNameMatchesCorrectFormat.js';\nimport * as stylelint from './checks/stylelint.js';\nimport * as stylelintConfigIsValid from './checks/stylelintConfigIsValid.js';\nimport * as useSinglePackageManager from './checks/useSinglePackageManager.js';\nimport { CtxParam } from './types/CtxParam.js';\nimport { TaskParam } from './types/TaskParam.js';\nimport {\n preflightPackageJson,\n projectPackageJson,\n} from './util/packageJson.js';\n\nconst projectDependencies = projectPackageJson.dependencies || {};\n\nconsole.log(`🚀 UpLeveled Preflight v${preflightPackageJson.version}`);\n\nconst listrTasks = [\n // ======= Sync Tasks =======\n // Git\n allChangesCommittedToGit,\n nodeModulesIgnoredFromGit,\n noExtraneousFilesCommittedToGit,\n noSecretsCommittedToGit,\n\n // Package managers\n useSinglePackageManager,\n\n // Project setup\n projectFolderNameMatchesCorrectFormat,\n\n // ======= Async Tasks =======\n // Dependencies\n {\n title: 'No dependency problems',\n task: (ctx: CtxParam, task: TaskParam): Listr =>\n task.newListr([\n ...(!Object.keys(projectDependencies).includes('next')\n ? []\n : [\n {\n title: nextJsProjectHasSharpInstalled.title,\n task: nextJsProjectHasSharpInstalled.default,\n },\n ]),\n {\n title: noUnusedAndMissingDependencies.title,\n task: noUnusedAndMissingDependencies.default,\n },\n {\n title: noDependenciesWithoutTypes.title,\n task: noDependenciesWithoutTypes.default,\n },\n ]),\n },\n\n // GitHub\n linkOnGithubAbout,\n\n // Linting\n eslint,\n ...(!(\n '@upleveled/react-scripts' in projectDependencies ||\n 'next' in projectDependencies\n )\n ? []\n : [stylelint]),\n prettier,\n\n // Version and configuration checks\n eslintConfigIsValid,\n ...(!(\n '@upleveled/react-scripts' in projectDependencies ||\n 'next' in projectDependencies\n )\n ? []\n : [stylelintConfigIsValid]),\n preflightIsLatestVersion,\n].map((module) => {\n if ('task' in module) return module;\n return {\n title: module.title,\n task: module.default,\n };\n});\n\nawait new Listr(listrTasks, {\n exitOnError: false,\n rendererOptions: {\n collapseErrors: false,\n removeEmptyLines: false,\n formatOutput: 'wrap',\n },\n fallbackRenderer: 'verbose',\n concurrent: 5,\n}).run();\n"],"names":["emptyBrailleCharacter","commandExample","command","chalk","dim","isDrone","stdout","execaCommand","reject","test","title","allChangesCommittedToGit","replSlug","isRunningInReplIt","fs","writeFile","onlyPnpmLockModifiedOnDrone","trim","Error","errorKey","warningKey","eslintCheck","error","RegExp","JSON","parse","filter","eslintResult","map","filePath","replace","process","cwd","sep","join","require","createRequire","eslintConfigIsValid","remoteVersion","localVersion","eslintConfigPackageJsonPath","resolve","readFile","version","err","semver","gt","eslintConfigMatches","eslintDisableOccurrences","path","readdirp","directoryFilter","fileFilter","fileContents","push","length","randomUserAgent","randomIndex","Math","floor","random","userAgents","linkOnGithubAbout","repoUrl","html","fetch","text","$","cheerio","load","urlInAboutSection","nextAll","children","next","attr","response","headers","ok","status","statusText","CRLF","normalizeNewline","input","TypeError","nodeModulesIgnoredFromGit","nodeModulesInGitignore","split","reduce","found","line","projectPackageJson","preflightPackageJson","URL","import","meta","url","nextJsProjectHasSharpInstalled","dependenciesPackageNames","Object","keys","dependencies","includes","client","algoliasearch","index","initIndex","noDependenciesWithoutTypes","devDependencies","dependenciesWithMissingTypes","pReduce","filteredDependencies","dependency","packageJsonPath","modulePackageJson","indexDTsPath","existsSync","results","getObject","attributesToRetrieve","definitelyTypedPackageName","_results$types","types","definitelyTyped","preflightBinPath","dirname","fileURLToPath","noUnusedAndMissingDependencies","ignoredPackagePatterns","startsWith","unusedDependenciesStdout","missingDependenciesStdout","messages","str","missingDependenciesStdoutFiltered","missingDependency","some","excludedDependency","noExtraneousFilesCommittedToGit","noSecretsCommittedToGit","preflightIsLatestVersion","os","platform","prettierCheck","stderr","stderrWithoutPackageJsonWarning","ignoredFilePatterns","unformattedFiles","file","relative","ignoredFilePattern","projectFolderNameMatchesCorrectFormat","currentDirectoryName","basename","lowercaseHyphenedDirectoryName","toLowerCase","replaceAll","supportedStylelintFileExtensions","stylelintCheck","stylelintResult","source","stylelintConfigIsValid","stylelintConfigPackageJsonPath","stylelintConfigMatches","stylelintDisableOccurrences","fileExtension","useSinglePackageManager","projectDependencies","console","log","listrTasks","task","ctx","newListr","eslint","stylelint","prettier","module","default","Listr","exitOnError","rendererOptions","collapseErrors","removeEmptyLines","formatOutput","fallbackRenderer","concurrent","run"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@upleveled/preflight",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0-0",
|
|
4
4
|
"repository": "upleveled/preflight",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "UpLeveled (https://github.com/upleveled)",
|
|
@@ -38,18 +38,19 @@
|
|
|
38
38
|
]
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
+
"@types/eslint": "8.37.0",
|
|
41
42
|
"algoliasearch": "4.17.0",
|
|
42
43
|
"chalk": "5.2.0",
|
|
43
44
|
"cheerio": "1.0.0-rc.12",
|
|
44
45
|
"depcheck": "1.4.3",
|
|
45
46
|
"execa": "7.1.1",
|
|
46
|
-
"listr2": "6.
|
|
47
|
+
"listr2": "6.3.1",
|
|
47
48
|
"node-fetch": "3.3.1",
|
|
48
49
|
"p-reduce": "3.0.0",
|
|
49
50
|
"patch-package": "6.5.1",
|
|
50
51
|
"prettier": "2.8.7",
|
|
51
52
|
"readdirp": "3.6.0",
|
|
52
|
-
"semver": "7.
|
|
53
|
+
"semver": "7.5.0",
|
|
53
54
|
"top-user-agents": "1.0.52"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
@@ -58,18 +59,18 @@
|
|
|
58
59
|
"@next/eslint-plugin-next": "13.3.0",
|
|
59
60
|
"@size-limit/file": "8.2.4",
|
|
60
61
|
"@types/domhandler": "2.4.2",
|
|
61
|
-
"@types/jest": "29.5.
|
|
62
|
-
"@types/node": "18.15.
|
|
62
|
+
"@types/jest": "29.5.1",
|
|
63
|
+
"@types/node": "18.15.12",
|
|
63
64
|
"@types/p-map": "2.0.0",
|
|
64
|
-
"@types/react": "18.0.
|
|
65
|
+
"@types/react": "18.0.37",
|
|
65
66
|
"@types/react-dom": "18.0.11",
|
|
66
67
|
"@types/semver": "7.3.13",
|
|
67
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
68
|
-
"@typescript-eslint/parser": "5.
|
|
68
|
+
"@typescript-eslint/eslint-plugin": "5.59.0",
|
|
69
|
+
"@typescript-eslint/parser": "5.59.0",
|
|
69
70
|
"babel-jest": "29.5.0",
|
|
70
71
|
"eslint": "8.38.0",
|
|
71
72
|
"eslint-config-react-app": "7.0.1",
|
|
72
|
-
"eslint-config-upleveled": "4.1.
|
|
73
|
+
"eslint-config-upleveled": "4.1.3",
|
|
73
74
|
"eslint-import-resolver-typescript": "3.5.5",
|
|
74
75
|
"eslint-plugin-cypress": "2.13.2",
|
|
75
76
|
"eslint-plugin-flowtype": "8.0.3",
|
|
@@ -88,6 +89,7 @@
|
|
|
88
89
|
"p-map": "5.5.0",
|
|
89
90
|
"postinstall-postinstall": "2.1.0",
|
|
90
91
|
"size-limit": "8.2.4",
|
|
92
|
+
"stylelint": "15.5.0",
|
|
91
93
|
"tsdx": "0.14.1",
|
|
92
94
|
"tslib": "2.5.0",
|
|
93
95
|
"typescript": "5.0.4"
|
package/src/checks/eslint.ts
CHANGED
|
@@ -1,35 +1,34 @@
|
|
|
1
|
+
import { sep } from 'node:path';
|
|
2
|
+
import { ESLint } from 'eslint';
|
|
1
3
|
import { execaCommand } from 'execa';
|
|
2
|
-
|
|
4
|
+
|
|
5
|
+
const errorKey = 'errorCount' as const;
|
|
6
|
+
const warningKey = 'warningCount' as const;
|
|
3
7
|
|
|
4
8
|
export const title = 'ESLint';
|
|
5
9
|
|
|
6
10
|
export default async function eslintCheck() {
|
|
7
11
|
try {
|
|
8
|
-
await execaCommand('pnpm eslint . --max-warnings 0 --format
|
|
12
|
+
await execaCommand('pnpm eslint . --max-warnings 0 --format json');
|
|
9
13
|
} catch (error) {
|
|
10
14
|
const { stdout } = error as { stdout: string };
|
|
11
|
-
const lines = stdout.split('\n');
|
|
12
15
|
|
|
13
16
|
// If no ESLint problems detected, throw the error
|
|
14
|
-
if (
|
|
17
|
+
if (!new RegExp(`"${errorKey}":|"${warningKey}":`).test(stdout)) {
|
|
15
18
|
throw error;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
throw new Error(
|
|
19
22
|
`ESLint problems found in the following files:
|
|
20
|
-
${
|
|
21
|
-
.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
linesWithoutDuplicates.push(line);
|
|
30
|
-
}
|
|
31
|
-
return linesWithoutDuplicates;
|
|
32
|
-
}, [])
|
|
23
|
+
${(JSON.parse(stdout) as ESLint.LintResult[])
|
|
24
|
+
.filter(
|
|
25
|
+
(eslintResult) =>
|
|
26
|
+
!(eslintResult[errorKey] === 0 && eslintResult[warningKey] === 0),
|
|
27
|
+
)
|
|
28
|
+
// Make paths relative to the project:
|
|
29
|
+
// before: /home/projects/next-student-project/app/api/hello/route.js
|
|
30
|
+
// after: app/api/hello/route.js
|
|
31
|
+
.map(({ filePath }) => filePath.replace(`${process.cwd()}${sep}`, ''))
|
|
33
32
|
.join('\n')}
|
|
34
33
|
|
|
35
34
|
Open these files in your editor - there should be problems to fix
|
|
@@ -52,14 +52,14 @@ const config = {
|
|
|
52
52
|
module.exports = config;`;
|
|
53
53
|
} catch (err) {
|
|
54
54
|
throw new Error(
|
|
55
|
-
`Error reading your .eslintrc.cjs file - please reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
55
|
+
`Error reading your .eslintrc.cjs file - please delete the file if it exists and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
56
56
|
`,
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
if (!eslintConfigMatches) {
|
|
61
61
|
throw new Error(
|
|
62
|
-
`Your
|
|
62
|
+
`Your .eslintrc.cjs file does not match the configuration file template - please delete the file and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
63
63
|
`,
|
|
64
64
|
);
|
|
65
65
|
}
|
|
@@ -35,6 +35,13 @@ export default async function noDependenciesWithoutTypes() {
|
|
|
35
35
|
const dependenciesWithMissingTypes = await pReduce(
|
|
36
36
|
Object.keys(dependencies),
|
|
37
37
|
async (filteredDependencies: [string, string][], dependency: string) => {
|
|
38
|
+
// Return early here because:
|
|
39
|
+
// - Algolia reports "ObjectID does not exist" for `@upleveled/react-scripts`
|
|
40
|
+
// - `@upleveled/react-scripts` has no types to install
|
|
41
|
+
if (dependency === '@upleveled/react-scripts') {
|
|
42
|
+
return filteredDependencies;
|
|
43
|
+
}
|
|
44
|
+
|
|
38
45
|
try {
|
|
39
46
|
const packageJsonPath = require.resolve(`${dependency}/package.json`);
|
|
40
47
|
|
package/src/checks/prettier.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { dirname } from 'node:path';
|
|
1
|
+
import { dirname, relative, sep } from 'node:path';
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
import { execaCommand } from 'execa';
|
|
4
4
|
import normalizeNewline from '../util/normalizeNewline';
|
|
@@ -37,12 +37,18 @@ export default async function prettierCheck() {
|
|
|
37
37
|
|
|
38
38
|
const unformattedFiles = normalizeNewline(stdout)
|
|
39
39
|
.split('\n')
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
file.replace(
|
|
45
|
-
|
|
40
|
+
// Make paths relative to the project instead of Preflight, eg:
|
|
41
|
+
// before: ../../../../../../projects/random-color-generator-react-app/src/reportWebVitals.js
|
|
42
|
+
// after: src/reportWebVitals.js
|
|
43
|
+
.map((file) => {
|
|
44
|
+
return file.replace(
|
|
45
|
+
`${relative(
|
|
46
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
47
|
+
process.cwd(),
|
|
48
|
+
)}${sep}`,
|
|
49
|
+
'',
|
|
50
|
+
);
|
|
51
|
+
})
|
|
46
52
|
.filter(
|
|
47
53
|
(file) =>
|
|
48
54
|
!ignoredFilePatterns.some((ignoredFilePattern) =>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { sep } from 'node:path';
|
|
2
|
+
import { execaCommand } from 'execa';
|
|
3
|
+
import { LintResult } from 'stylelint';
|
|
4
|
+
|
|
5
|
+
const errorKey = 'errored' as const;
|
|
6
|
+
|
|
7
|
+
export const supportedStylelintFileExtensions = [
|
|
8
|
+
'css',
|
|
9
|
+
'sass',
|
|
10
|
+
'scss',
|
|
11
|
+
'less',
|
|
12
|
+
'js',
|
|
13
|
+
'tsx',
|
|
14
|
+
'jsx',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export const title = 'Stylelint';
|
|
18
|
+
|
|
19
|
+
export default async function stylelintCheck() {
|
|
20
|
+
try {
|
|
21
|
+
await execaCommand(
|
|
22
|
+
`pnpm stylelint **/*.{${supportedStylelintFileExtensions.join(
|
|
23
|
+
',',
|
|
24
|
+
)}} --max-warnings 0 --formatter json`,
|
|
25
|
+
);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
const { stdout } = error as { stdout: string };
|
|
28
|
+
|
|
29
|
+
// If no Stylelint errors detected, throw the error
|
|
30
|
+
if (!new RegExp(`"${errorKey}":`).test(stdout)) {
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Stylelint problems found in the following files:
|
|
36
|
+
${(JSON.parse(stdout) as LintResult[])
|
|
37
|
+
.filter((stylelintResult) => stylelintResult[errorKey] === true)
|
|
38
|
+
// Make paths relative to the project:
|
|
39
|
+
// before: /home/projects/random-color-generator-react-app/src/index.css
|
|
40
|
+
// after: src/index.css
|
|
41
|
+
.map(({ source }) => source!.replace(`${process.cwd()}${sep}`, ''))
|
|
42
|
+
.join('\n')}
|
|
43
|
+
|
|
44
|
+
Open these files in your editor - there should be problems to fix
|
|
45
|
+
`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { execaCommand } from 'execa';
|
|
4
|
+
import readdirp from 'readdirp';
|
|
5
|
+
import semver from 'semver';
|
|
6
|
+
import { supportedStylelintFileExtensions } from './stylelint';
|
|
7
|
+
|
|
8
|
+
const require = createRequire(`${process.cwd()}/`);
|
|
9
|
+
|
|
10
|
+
export const title = 'Stylelint config is latest version';
|
|
11
|
+
|
|
12
|
+
export default async function stylelintConfigIsValid() {
|
|
13
|
+
const { stdout: remoteVersion } = await execaCommand(
|
|
14
|
+
'npm show stylelint-config-upleveled version',
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
let localVersion;
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const stylelintConfigPackageJsonPath = require.resolve(
|
|
21
|
+
'stylelint-config-upleveled/package.json',
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
localVersion = JSON.parse(
|
|
25
|
+
await fs.readFile(stylelintConfigPackageJsonPath, 'utf-8'),
|
|
26
|
+
).version;
|
|
27
|
+
} catch (err) {}
|
|
28
|
+
|
|
29
|
+
if (typeof localVersion === 'undefined') {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`The UpLeveled Stylelint Config has not been installed - please install using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
32
|
+
`,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (semver.gt(remoteVersion, localVersion)) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Your current version of the UpLeveled Stylelint Config (${localVersion}) is older than the latest version ${remoteVersion} - upgrade by running:
|
|
39
|
+
|
|
40
|
+
pnpm add stylelint-config-upleveled@${remoteVersion}`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let stylelintConfigMatches;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
stylelintConfigMatches =
|
|
48
|
+
(await fs.readFile('./stylelint.config.cjs', 'utf-8')).trim() ===
|
|
49
|
+
`/** @type { import('stylelint').Config } */
|
|
50
|
+
const config = {
|
|
51
|
+
extends: ['stylelint-config-upleveled'],
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
module.exports = config;`;
|
|
55
|
+
} catch (err) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Error reading your stylelint.config.cjs file - please delete the file if it exists and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
58
|
+
`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!stylelintConfigMatches) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Your stylelint.config.cjs file does not match the configuration file template - please delete the file and reinstall the config using the instructions on https://www.npmjs.com/package/eslint-config-upleveled
|
|
65
|
+
`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const stylelintDisableOccurrences = [];
|
|
70
|
+
|
|
71
|
+
for await (const { path } of readdirp('.', {
|
|
72
|
+
directoryFilter: ['!.git', '!.next', '!node_modules'],
|
|
73
|
+
fileFilter: supportedStylelintFileExtensions.map(
|
|
74
|
+
(fileExtension) => `*.${fileExtension}`,
|
|
75
|
+
),
|
|
76
|
+
})) {
|
|
77
|
+
const fileContents = await fs.readFile(path, 'utf-8');
|
|
78
|
+
if (fileContents.includes('stylelint-disable')) {
|
|
79
|
+
stylelintDisableOccurrences.push(path);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (stylelintDisableOccurrences.length > 0) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`Stylelint has been disabled in the following files:
|
|
86
|
+
${stylelintDisableOccurrences.join('\n')}
|
|
87
|
+
|
|
88
|
+
Remove all comments disabling or modifying Stylelint rule configuration (eg. stylelint-disable and stylelint-disable-next-line comments) and fix the problems
|
|
89
|
+
`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,8 @@ import * as noSecretsCommittedToGit from './checks/noSecretsCommittedToGit.js';
|
|
|
12
12
|
import * as preflightIsLatestVersion from './checks/preflightIsLatestVersion.js';
|
|
13
13
|
import * as prettier from './checks/prettier.js';
|
|
14
14
|
import * as projectFolderNameMatchesCorrectFormat from './checks/projectFolderNameMatchesCorrectFormat.js';
|
|
15
|
+
import * as stylelint from './checks/stylelint.js';
|
|
16
|
+
import * as stylelintConfigIsValid from './checks/stylelintConfigIsValid.js';
|
|
15
17
|
import * as useSinglePackageManager from './checks/useSinglePackageManager.js';
|
|
16
18
|
import { CtxParam } from './types/CtxParam.js';
|
|
17
19
|
import { TaskParam } from './types/TaskParam.js';
|
|
@@ -20,6 +22,8 @@ import {
|
|
|
20
22
|
projectPackageJson,
|
|
21
23
|
} from './util/packageJson.js';
|
|
22
24
|
|
|
25
|
+
const projectDependencies = projectPackageJson.dependencies || {};
|
|
26
|
+
|
|
23
27
|
console.log(`🚀 UpLeveled Preflight v${preflightPackageJson.version}`);
|
|
24
28
|
|
|
25
29
|
const listrTasks = [
|
|
@@ -42,8 +46,7 @@ const listrTasks = [
|
|
|
42
46
|
title: 'No dependency problems',
|
|
43
47
|
task: (ctx: CtxParam, task: TaskParam): Listr =>
|
|
44
48
|
task.newListr([
|
|
45
|
-
...(!
|
|
46
|
-
!Object.keys(projectPackageJson.dependencies).includes('next')
|
|
49
|
+
...(!Object.keys(projectDependencies).includes('next')
|
|
47
50
|
? []
|
|
48
51
|
: [
|
|
49
52
|
{
|
|
@@ -67,10 +70,22 @@ const listrTasks = [
|
|
|
67
70
|
|
|
68
71
|
// Linting
|
|
69
72
|
eslint,
|
|
73
|
+
...(!(
|
|
74
|
+
'@upleveled/react-scripts' in projectDependencies ||
|
|
75
|
+
'next' in projectDependencies
|
|
76
|
+
)
|
|
77
|
+
? []
|
|
78
|
+
: [stylelint]),
|
|
70
79
|
prettier,
|
|
71
80
|
|
|
72
81
|
// Version and configuration checks
|
|
73
82
|
eslintConfigIsValid,
|
|
83
|
+
...(!(
|
|
84
|
+
'@upleveled/react-scripts' in projectDependencies ||
|
|
85
|
+
'next' in projectDependencies
|
|
86
|
+
)
|
|
87
|
+
? []
|
|
88
|
+
: [stylelintConfigIsValid]),
|
|
74
89
|
preflightIsLatestVersion,
|
|
75
90
|
].map((module) => {
|
|
76
91
|
if ('task' in module) return module;
|