@hansolbangul/notion-api
Version:
A lightweight library for fetching and statically generating data and TypeScript types from Notion pages.
142 lines (120 loc) • 3.7 kB
text/typescript
import { NotionAPI } from 'notion-client';
import { PropertyType as NotionPropertyType } from 'notion-types';
import fs from 'fs';
import * as process from 'node:process';
import { fileURLToPath } from 'url';
import path from 'path';
const notion = new NotionAPI();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
function loadEnv() {
const envPath = path.resolve(__dirname, '.env');
console.log('Resolved .env Path:', envPath); // 디버깅용 로그
if (fs.existsSync(envPath)) {
const envData = fs.readFileSync(envPath, 'utf8');
envData.split('\n').forEach((line) => {
const [key, value] = line.split('=').map((v) => v.trim());
if (key && value) {
process.env[key] = value;
}
});
} else {
console.error('.env file not found at:', envPath);
process.exit(1);
}
}
loadEnv();
interface Option {
id: string;
color: string;
value: string;
}
interface SchemaField {
name: string;
type: NotionPropertyType;
options?: Option[];
limit?: number;
}
type DynamicSchema = Record<string, SchemaField>;
async function fetchSchema(pageId: string): Promise<DynamicSchema> {
const recordMap = await notion.getPage(pageId);
const collection = Object.values(recordMap.collection)[0]?.value;
const schema = collection?.schema;
if (!schema) {
throw new Error('Schema not found in the given Notion page.');
}
return schema as DynamicSchema;
}
function generateType(schema: DynamicSchema): string {
let result = 'interface NotionProperties {\n';
for (const key in schema) {
const field = schema[key];
const fieldName = field.name;
const fieldType = field.type;
const type = (() => {
switch (fieldType) {
case 'title':
case 'text':
case 'url':
case 'email':
case 'phone_number':
return 'string';
case 'number':
return 'number';
case 'select':
return field.options
? `(${field.options.map((option) => `"${option.value}"`).join(' | ')})[]`
: 'string';
case 'multi_select':
return field.options
? `(${field.options
.map((option) => `"${option.value}"`)
.join(' | ')})[]`
: 'string[]';
case 'date':
return '{ type: string; start_date: string }';
case 'file':
return '{ url: string }[]';
case 'person':
return '{ id: string; name: string; profile_photo: string }[]';
case 'checkbox':
return 'boolean';
case 'created_time':
case 'last_edited_time':
case 'status':
return 'string';
default:
return 'unknown';
}
})();
result += ` ${fieldName}: ${type};\n`;
}
result += '}';
return result;
}
async function main() {
const args = process.env.pageId || process.argv.slice(1);
const pageId = typeof args === 'string' ? args : args[0];
if (!pageId) {
console.error(
'Error: Please provide a Notion page ID as the first argument.'
);
process.exit(1);
}
try {
console.log(`Fetching schema from Notion for page ID: ${pageId}...`);
const schema = await fetchSchema(pageId);
console.log('Generating TypeScript types...');
const types = generateType(schema);
console.log('Saving types to src/types.d.ts...');
fs.writeFileSync('./src/types.d.ts', types);
console.log('Type definitions generated successfully!');
} catch (error) {
if (error instanceof Error) {
console.error(error.message);
} else {
console.error('Unknown error', error);
}
}
}
main();