Next.js website for Rocky Mountain Vending company featuring: - Product catalog with Stripe integration - Service areas and parts pages - Admin dashboard with Clerk authentication - SEO optimized pages with JSON-LD structured data Co-authored-by: Cursor <cursoragent@cursor.com>
224 lines
No EOL
11 KiB
Text
224 lines
No EOL
11 KiB
Text
import { NEXT_TS_ERRORS } from '../constant';
|
|
import { getSource, getTs, getTypeChecker } from '../utils';
|
|
const metadata = {
|
|
client: {
|
|
getSemanticDiagnosticsForExportVariableStatement (fileName, node) {
|
|
const source = getSource(fileName);
|
|
const ts = getTs();
|
|
// It is not allowed to export `metadata` or `generateMetadata` in client entry
|
|
if (ts.isFunctionDeclaration(node)) {
|
|
var _node_name;
|
|
if (((_node_name = node.name) == null ? void 0 : _node_name.getText()) === 'generateMetadata') {
|
|
return [
|
|
{
|
|
file: source,
|
|
category: ts.DiagnosticCategory.Error,
|
|
code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
|
|
messageText: `The Next.js 'generateMetadata' API is not allowed in a Client Component.`,
|
|
start: node.name.getStart(),
|
|
length: node.name.getWidth()
|
|
}
|
|
];
|
|
}
|
|
} else {
|
|
for (const declaration of node.declarationList.declarations){
|
|
const name = declaration.name.getText();
|
|
if (name === 'metadata') {
|
|
return [
|
|
{
|
|
file: source,
|
|
category: ts.DiagnosticCategory.Error,
|
|
code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
|
|
messageText: `The Next.js 'metadata' API is not allowed in a Client Component.`,
|
|
start: declaration.name.getStart(),
|
|
length: declaration.name.getWidth()
|
|
}
|
|
];
|
|
}
|
|
}
|
|
}
|
|
return [];
|
|
},
|
|
getSemanticDiagnosticsForExportDeclaration (fileName, node) {
|
|
const ts = getTs();
|
|
const source = getSource(fileName);
|
|
const diagnostics = [];
|
|
const exportClause = node.exportClause;
|
|
if (exportClause && ts.isNamedExports(exportClause)) {
|
|
for (const e of exportClause.elements){
|
|
if ([
|
|
'generateMetadata',
|
|
'metadata'
|
|
].includes(e.name.getText())) {
|
|
diagnostics.push({
|
|
file: source,
|
|
category: ts.DiagnosticCategory.Error,
|
|
code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
|
|
messageText: `The Next.js '${e.name.getText()}' API is not allowed in a Client Component.`,
|
|
start: e.name.getStart(),
|
|
length: e.name.getWidth()
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return diagnostics;
|
|
}
|
|
},
|
|
server: {
|
|
getSemanticDiagnosticsForExportVariableStatement (fileName, node) {
|
|
const source = getSource(fileName);
|
|
const ts = getTs();
|
|
if (ts.isFunctionDeclaration(node)) {
|
|
var _node_name;
|
|
if (((_node_name = node.name) == null ? void 0 : _node_name.getText()) === 'generateMetadata') {
|
|
var _node_modifiers;
|
|
if (hasType(node)) {
|
|
return [];
|
|
}
|
|
const isAsync = (_node_modifiers = node.modifiers) == null ? void 0 : _node_modifiers.some((m)=>m.kind === ts.SyntaxKind.AsyncKeyword);
|
|
return [
|
|
{
|
|
file: source,
|
|
category: ts.DiagnosticCategory.Warning,
|
|
code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
|
|
messageText: `The Next.js "generateMetadata" export should have a return type of ${isAsync ? '"Promise<Metadata>"' : '"Metadata"'} from "next".`,
|
|
start: node.name.getStart(),
|
|
length: node.name.getWidth()
|
|
}
|
|
];
|
|
}
|
|
} else {
|
|
for (const declaration of node.declarationList.declarations){
|
|
if (hasType(declaration)) {
|
|
return [];
|
|
}
|
|
const name = declaration.name.getText();
|
|
if (name === 'metadata') {
|
|
return [
|
|
{
|
|
file: source,
|
|
category: ts.DiagnosticCategory.Warning,
|
|
code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
|
|
messageText: `The Next.js "metadata" export should be type of "Metadata" from "next".`,
|
|
start: declaration.name.getStart(),
|
|
length: declaration.name.getWidth()
|
|
}
|
|
];
|
|
}
|
|
if (name === 'generateMetadata') {
|
|
// Check if it's a function expression or arrow function
|
|
if (declaration.initializer && (ts.isFunctionExpression(declaration.initializer) || ts.isArrowFunction(declaration.initializer))) {
|
|
var _declaration_initializer_modifiers;
|
|
const isAsync = (_declaration_initializer_modifiers = declaration.initializer.modifiers) == null ? void 0 : _declaration_initializer_modifiers.some((m)=>m.kind === ts.SyntaxKind.AsyncKeyword);
|
|
return [
|
|
{
|
|
file: source,
|
|
category: ts.DiagnosticCategory.Warning,
|
|
code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
|
|
messageText: `The Next.js "generateMetadata" export should have a return type of ${isAsync ? '"Promise<Metadata>"' : '"Metadata"'} from "next".`,
|
|
start: declaration.name.getStart(),
|
|
length: declaration.name.getWidth()
|
|
}
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return [];
|
|
},
|
|
getSemanticDiagnosticsForExportDeclaration (fileName, node) {
|
|
const typeChecker = getTypeChecker();
|
|
if (!typeChecker) {
|
|
return [];
|
|
}
|
|
const ts = getTs();
|
|
const source = getSource(fileName);
|
|
const diagnostics = [];
|
|
const exportClause = node.exportClause;
|
|
if (!node.isTypeOnly && exportClause && ts.isNamedExports(exportClause)) {
|
|
for (const e of exportClause.elements){
|
|
if (e.isTypeOnly) {
|
|
continue;
|
|
}
|
|
const exportName = e.name.getText();
|
|
if (exportName !== 'metadata' && exportName !== 'generateMetadata') {
|
|
continue;
|
|
}
|
|
const symbol = typeChecker.getSymbolAtLocation(e.name);
|
|
if (!symbol) {
|
|
continue;
|
|
}
|
|
const originalSymbol = typeChecker.getAliasedSymbol(symbol);
|
|
const declarations = originalSymbol.getDeclarations();
|
|
if (!declarations) {
|
|
continue;
|
|
}
|
|
const declaration = declarations[0];
|
|
if (hasType(declaration)) {
|
|
continue;
|
|
}
|
|
if (exportName === 'generateMetadata') {
|
|
let isAsync = false;
|
|
// async function() {}
|
|
if (ts.isFunctionDeclaration(declaration)) {
|
|
var _declaration_modifiers;
|
|
isAsync = ((_declaration_modifiers = declaration.modifiers) == null ? void 0 : _declaration_modifiers.some((m)=>m.kind === ts.SyntaxKind.AsyncKeyword)) ?? false;
|
|
}
|
|
// foo = async function() {}
|
|
// foo = async () => {}
|
|
if (ts.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
const initializer = declaration.initializer;
|
|
const isFunction = ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer);
|
|
if (isFunction) {
|
|
var _initializer_modifiers;
|
|
isAsync = ((_initializer_modifiers = initializer.modifiers) == null ? void 0 : _initializer_modifiers.some((m)=>m.kind === ts.SyntaxKind.AsyncKeyword)) ?? false;
|
|
}
|
|
}
|
|
diagnostics.push({
|
|
file: source,
|
|
category: ts.DiagnosticCategory.Warning,
|
|
code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
|
|
messageText: `The Next.js "generateMetadata" export should have a return type of ${isAsync ? '"Promise<Metadata>"' : '"Metadata"'} from "next".`,
|
|
start: e.name.getStart(),
|
|
length: e.name.getWidth()
|
|
});
|
|
} else {
|
|
diagnostics.push({
|
|
file: source,
|
|
category: ts.DiagnosticCategory.Warning,
|
|
code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
|
|
messageText: `The Next.js "metadata" export should be type of "Metadata" from "next".`,
|
|
start: e.name.getStart(),
|
|
length: e.name.getWidth()
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return diagnostics;
|
|
}
|
|
}
|
|
};
|
|
function hasType(node) {
|
|
const ts = getTs();
|
|
if (!ts.isVariableDeclaration(node) && !ts.isFunctionDeclaration(node) && !ts.isArrowFunction(node) && !ts.isFunctionExpression(node)) {
|
|
return false;
|
|
}
|
|
// For function declarations, expressions, and arrow functions, check if they have return type
|
|
if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node)) {
|
|
return !!node.type;
|
|
}
|
|
// For variable declarations
|
|
if (!node.name) return false;
|
|
const name = node.name.getText();
|
|
if (name === 'generateMetadata') {
|
|
// If it's a function expression or arrow function, check if it has return type
|
|
if (node.initializer && (ts.isFunctionExpression(node.initializer) || ts.isArrowFunction(node.initializer))) {
|
|
return !!node.initializer.type;
|
|
}
|
|
}
|
|
// For all other cases, check if the node has a type annotation
|
|
return !!node.type;
|
|
}
|
|
export default metadata;
|
|
|
|
//# sourceMappingURL=metadata.js.map |