Skip to content

Commit 4cd8b23

Browse files
timneutkensstyfle
andauthored
Enable @typescript-eslint/no-use-before-define for functions (#39602)
Follow-up to the earlier enabling of classes/variables etc. Bug Related issues linked using fixes #number Integration tests added Errors have helpful link attached, see contributing.md Feature Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. Related issues linked using fixes #number Integration tests added Documentation added Telemetry added. In case of a feature if it's used or not. Errors have helpful link attached, see contributing.md Documentation / Examples Make sure the linting passes by running pnpm lint The examples guidelines are followed from our contributing doc Co-authored-by: Steven <[email protected]>
1 parent 683db9a commit 4cd8b23

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+3312
-3309
lines changed

.eslintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
"@typescript-eslint/no-use-before-define": [
6969
"warn",
7070
{
71-
"functions": false,
71+
"functions": true,
7272
"classes": true,
7373
"variables": true,
7474
"enums": true,

packages/next/build/analysis/extract-const-value.ts

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,52 +17,6 @@ import type {
1717

1818
export class NoSuchDeclarationError extends Error {}
1919

20-
/**
21-
* Extracts the value of an exported const variable named `exportedName`
22-
* (e.g. "export const config = { runtime: 'experimental-edge' }") from swc's AST.
23-
* The value must be one of (or throws UnsupportedValueError):
24-
* - string
25-
* - boolean
26-
* - number
27-
* - null
28-
* - undefined
29-
* - array containing values listed in this list
30-
* - object containing values listed in this list
31-
*
32-
* Throws NoSuchDeclarationError if the declaration is not found.
33-
*/
34-
export function extractExportedConstValue(
35-
module: Module,
36-
exportedName: string
37-
): any {
38-
for (const moduleItem of module.body) {
39-
if (!isExportDeclaration(moduleItem)) {
40-
continue
41-
}
42-
43-
const declaration = moduleItem.declaration
44-
if (!isVariableDeclaration(declaration)) {
45-
continue
46-
}
47-
48-
if (declaration.kind !== 'const') {
49-
continue
50-
}
51-
52-
for (const decl of declaration.declarations) {
53-
if (
54-
isIdentifier(decl.id) &&
55-
decl.id.value === exportedName &&
56-
decl.init
57-
) {
58-
return extractValue(decl.init, [exportedName])
59-
}
60-
}
61-
}
62-
63-
throw new NoSuchDeclarationError()
64-
}
65-
6620
function isExportDeclaration(node: Node): node is ExportDeclaration {
6721
return node.type === 'ExportDeclaration'
6822
}
@@ -247,3 +201,49 @@ function extractValue(node: Node, path?: string[]): any {
247201
)
248202
}
249203
}
204+
205+
/**
206+
* Extracts the value of an exported const variable named `exportedName`
207+
* (e.g. "export const config = { runtime: 'experimental-edge' }") from swc's AST.
208+
* The value must be one of (or throws UnsupportedValueError):
209+
* - string
210+
* - boolean
211+
* - number
212+
* - null
213+
* - undefined
214+
* - array containing values listed in this list
215+
* - object containing values listed in this list
216+
*
217+
* Throws NoSuchDeclarationError if the declaration is not found.
218+
*/
219+
export function extractExportedConstValue(
220+
module: Module,
221+
exportedName: string
222+
): any {
223+
for (const moduleItem of module.body) {
224+
if (!isExportDeclaration(moduleItem)) {
225+
continue
226+
}
227+
228+
const declaration = moduleItem.declaration
229+
if (!isVariableDeclaration(declaration)) {
230+
continue
231+
}
232+
233+
if (declaration.kind !== 'const') {
234+
continue
235+
}
236+
237+
for (const decl of declaration.declarations) {
238+
if (
239+
isIdentifier(decl.id) &&
240+
decl.id.value === exportedName &&
241+
decl.init
242+
) {
243+
return extractValue(decl.init, [exportedName])
244+
}
245+
}
246+
}
247+
248+
throw new NoSuchDeclarationError()
249+
}

packages/next/build/analysis/get-page-static-info.ts

Lines changed: 94 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -22,79 +22,6 @@ export interface PageStaticInfo {
2222
middleware?: Partial<MiddlewareConfig>
2323
}
2424

25-
/**
26-
* For a given pageFilePath and nextConfig, if the config supports it, this
27-
* function will read the file and return the runtime that should be used.
28-
* It will look into the file content only if the page *requires* a runtime
29-
* to be specified, that is, when gSSP or gSP is used.
30-
* Related discussion: https://github.com/vercel/next.js/discussions/34179
31-
*/
32-
export async function getPageStaticInfo(params: {
33-
nextConfig: Partial<NextConfig>
34-
pageFilePath: string
35-
isDev?: boolean
36-
page?: string
37-
}): Promise<PageStaticInfo> {
38-
const { isDev, pageFilePath, nextConfig, page } = params
39-
40-
const fileContent = (await tryToReadFile(pageFilePath, !isDev)) || ''
41-
if (/runtime|getStaticProps|getServerSideProps|matcher/.test(fileContent)) {
42-
const swcAST = await parseModule(pageFilePath, fileContent)
43-
const { ssg, ssr } = checkExports(swcAST)
44-
45-
// default / failsafe value for config
46-
let config: any = {}
47-
try {
48-
config = extractExportedConstValue(swcAST, 'config')
49-
} catch (e) {
50-
if (e instanceof UnsupportedValueError) {
51-
warnAboutUnsupportedValue(pageFilePath, page, e)
52-
}
53-
// `export config` doesn't exist, or other unknown error throw by swc, silence them
54-
}
55-
56-
if (
57-
typeof config.runtime !== 'string' &&
58-
typeof config.runtime !== 'undefined'
59-
) {
60-
throw new Error(`Provided runtime `)
61-
} else if (!isServerRuntime(config.runtime)) {
62-
const options = Object.values(SERVER_RUNTIME).join(', ')
63-
if (typeof config.runtime !== 'string') {
64-
throw new Error(
65-
`The \`runtime\` config must be a string. Please leave it empty or choose one of: ${options}`
66-
)
67-
} else {
68-
throw new Error(
69-
`Provided runtime "${config.runtime}" is not supported. Please leave it empty or choose one of: ${options}`
70-
)
71-
}
72-
}
73-
74-
let runtime =
75-
SERVER_RUNTIME.edge === config?.runtime
76-
? SERVER_RUNTIME.edge
77-
: ssr || ssg
78-
? config?.runtime || nextConfig.experimental?.runtime
79-
: undefined
80-
81-
if (runtime === SERVER_RUNTIME.edge) {
82-
warnAboutExperimentalEdgeApiFunctions()
83-
}
84-
85-
const middlewareConfig = getMiddlewareConfig(config, nextConfig)
86-
87-
return {
88-
ssr,
89-
ssg,
90-
...(middlewareConfig && { middleware: middlewareConfig }),
91-
...(runtime && { runtime }),
92-
}
93-
}
94-
95-
return { ssr: false, ssg: false }
96-
}
97-
9825
/**
9926
* Receives a parsed AST from SWC and checks if it belongs to a module that
10027
* requires a runtime to be specified. Those are:
@@ -154,27 +81,6 @@ async function tryToReadFile(filePath: string, shouldThrow: boolean) {
15481
}
15582
}
15683

157-
function getMiddlewareConfig(
158-
config: any,
159-
nextConfig: NextConfig
160-
): Partial<MiddlewareConfig> {
161-
const result: Partial<MiddlewareConfig> = {}
162-
163-
if (config.matcher) {
164-
result.pathMatcher = new RegExp(
165-
getMiddlewareRegExpStrings(config.matcher, nextConfig).join('|')
166-
)
167-
168-
if (result.pathMatcher.source.length > 4096) {
169-
throw new Error(
170-
`generated matcher config must be less than 4096 characters.`
171-
)
172-
}
173-
}
174-
175-
return result
176-
}
177-
17884
function getMiddlewareRegExpStrings(
17985
matcherOrMatchers: unknown,
18086
nextConfig: NextConfig
@@ -226,6 +132,27 @@ function getMiddlewareRegExpStrings(
226132
}
227133
}
228134

135+
function getMiddlewareConfig(
136+
config: any,
137+
nextConfig: NextConfig
138+
): Partial<MiddlewareConfig> {
139+
const result: Partial<MiddlewareConfig> = {}
140+
141+
if (config.matcher) {
142+
result.pathMatcher = new RegExp(
143+
getMiddlewareRegExpStrings(config.matcher, nextConfig).join('|')
144+
)
145+
146+
if (result.pathMatcher.source.length > 4096) {
147+
throw new Error(
148+
`generated matcher config must be less than 4096 characters.`
149+
)
150+
}
151+
}
152+
153+
return result
154+
}
155+
229156
let warnedAboutExperimentalEdgeApiFunctions = false
230157
function warnAboutExperimentalEdgeApiFunctions() {
231158
if (warnedAboutExperimentalEdgeApiFunctions) {
@@ -258,3 +185,76 @@ function warnAboutUnsupportedValue(
258185

259186
warnedUnsupportedValueMap.set(pageFilePath, true)
260187
}
188+
189+
/**
190+
* For a given pageFilePath and nextConfig, if the config supports it, this
191+
* function will read the file and return the runtime that should be used.
192+
* It will look into the file content only if the page *requires* a runtime
193+
* to be specified, that is, when gSSP or gSP is used.
194+
* Related discussion: https://github.com/vercel/next.js/discussions/34179
195+
*/
196+
export async function getPageStaticInfo(params: {
197+
nextConfig: Partial<NextConfig>
198+
pageFilePath: string
199+
isDev?: boolean
200+
page?: string
201+
}): Promise<PageStaticInfo> {
202+
const { isDev, pageFilePath, nextConfig, page } = params
203+
204+
const fileContent = (await tryToReadFile(pageFilePath, !isDev)) || ''
205+
if (/runtime|getStaticProps|getServerSideProps|matcher/.test(fileContent)) {
206+
const swcAST = await parseModule(pageFilePath, fileContent)
207+
const { ssg, ssr } = checkExports(swcAST)
208+
209+
// default / failsafe value for config
210+
let config: any = {}
211+
try {
212+
config = extractExportedConstValue(swcAST, 'config')
213+
} catch (e) {
214+
if (e instanceof UnsupportedValueError) {
215+
warnAboutUnsupportedValue(pageFilePath, page, e)
216+
}
217+
// `export config` doesn't exist, or other unknown error throw by swc, silence them
218+
}
219+
220+
if (
221+
typeof config.runtime !== 'string' &&
222+
typeof config.runtime !== 'undefined'
223+
) {
224+
throw new Error(`Provided runtime `)
225+
} else if (!isServerRuntime(config.runtime)) {
226+
const options = Object.values(SERVER_RUNTIME).join(', ')
227+
if (typeof config.runtime !== 'string') {
228+
throw new Error(
229+
`The \`runtime\` config must be a string. Please leave it empty or choose one of: ${options}`
230+
)
231+
} else {
232+
throw new Error(
233+
`Provided runtime "${config.runtime}" is not supported. Please leave it empty or choose one of: ${options}`
234+
)
235+
}
236+
}
237+
238+
let runtime =
239+
SERVER_RUNTIME.edge === config?.runtime
240+
? SERVER_RUNTIME.edge
241+
: ssr || ssg
242+
? config?.runtime || nextConfig.experimental?.runtime
243+
: undefined
244+
245+
if (runtime === SERVER_RUNTIME.edge) {
246+
warnAboutExperimentalEdgeApiFunctions()
247+
}
248+
249+
const middlewareConfig = getMiddlewareConfig(config, nextConfig)
250+
251+
return {
252+
ssr,
253+
ssg,
254+
...(middlewareConfig && { middleware: middlewareConfig }),
255+
...(runtime && { runtime }),
256+
}
257+
}
258+
259+
return { ssr: false, ssg: false }
260+
}

0 commit comments

Comments
 (0)