@mikemajara/notion-cms
Version:
A TypeScript library for using Notion as a headless CMS
68 lines (65 loc) • 14.2 kB
JavaScript
'use strict';var client=require('@notionhq/client'),_=require('fs'),T=require('path'),tsMorph=require('ts-morph');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var ___namespace=/*#__PURE__*/_interopNamespace(_);var T__namespace=/*#__PURE__*/_interopNamespace(T);function N(e){return /[^a-zA-Z0-9_$]/.test(e)?`"${e}"`:e}var v=(e,n)=>{switch(e){case "title":case "rich_text":case "url":case "email":case "phone_number":return "string";case "number":return "number";case "select":return n&&"select"in n&&n.select&&"options"in n.select&&Array.isArray(n.select.options)&&n.select.options.length>0?n.select.options.map(r=>`"${r.name}"`).join(" | "):"string";case "multi_select":return n&&"multi_select"in n&&n.multi_select&&"options"in n.multi_select&&Array.isArray(n.multi_select.options)&&n.multi_select.options.length>0?`Array<${n.multi_select.options.map(i=>`"${i.name}"`).join(" | ")}>`:"string[]";case "date":return "Date";case "people":return "string[]";case "files":return "{ name: string; url: string; }[]";case "checkbox":return "boolean";case "formula":return "any";case "relation":return "string[]";case "rollup":return "any";case "created_time":case "last_edited_time":return "string";case "created_by":case "last_edited_by":return "{ id: string; name: string | null; avatar_url: string | null; }";default:return "any"}};function x(e){let n=e.replace(/[^\w\s]/g,"").replace(/\s+(.)/g,(r,i)=>i.toUpperCase()).replace(/\s/g,"");return "Record"+n.charAt(0).toUpperCase()+n.slice(1)}function M(e){return `notion-types-${e.toLowerCase().replace(/[^\w\s]/g,"").replace(/\s+/g,"-")}.ts`}async function G(e,n,r,i=false){let p=await new client.Client({auth:r}).databases.retrieve({database_id:e}),d=p.properties,o="NotionDatabase",a=p;if(a.title&&Array.isArray(a.title)&&a.title.length>0){let c=a.title[0].plain_text;c&&(o=c);}if(o==="NotionDatabase"){o=e.replace(/-/g,"").substring(0,12);let c=Object.keys(d).find(u=>d[u].type==="title");c&&(o=c);}let f=x(o),t=M(o);___namespace.mkdirSync(n,{recursive:true});let s=T__namespace.join(n,t),l=new tsMorph.Project().createSourceFile(s,"",{overwrite:true});U(l,d,f,o),await l.save(),k(n,t);}function k(e,n){let r=T__namespace.join(e,"index.ts");___namespace.existsSync(r)||___namespace.writeFileSync(r,`// Auto-generated index file for Notion CMS types
// Export database-specific types
`);let i=___namespace.readFileSync(r,"utf8"),b=`export * from './${n.replace(".ts","")}';`;i.includes(b)||(i+=`${b}
`,___namespace.writeFileSync(r,i));}function U(e,n,r,i){try{e.addStatements(`/**
* THIS FILE IS AUTO-GENERATED BY NOTION-CMS
* DO NOT EDIT DIRECTLY - YOUR CHANGES WILL BE OVERWRITTEN
*
* Generated for database: ${i}
*/`),e.addImportDeclaration({moduleSpecifier:"@mikemajara/notion-cms",namedImports:["DatabaseRecord","NotionCMS","QueryBuilder","DatabaseFieldMetadata"]});let b=t=>{switch(t){case "title":return "{ content: string; annotations: any; href: string | null; link?: { url: string } | null }[]";case "rich_text":return "{ content: string; annotations: any; href: string | null; link?: { url: string } | null }[]";case "number":return "number";case "select":return "{ id: string; name: string; color: string } | null";case "multi_select":return "{ id: string; name: string; color: string }[]";case "date":return "{ start: string; end: string | null; time_zone: string | null; parsedStart: Date | null; parsedEnd: Date | null } | null";case "people":return "{ id: string; name: string | null; avatar_url: string | null; object: string; type: string; email?: string }[]";case "files":return "{ name: string; type: string; external?: { url: string }; file?: { url: string; expiry_time: string } }[]";case "checkbox":return "boolean";case "url":return "string";case "email":return "string";case "phone_number":return "string";case "formula":return "{ type: string; value: any }";case "relation":return "{ id: string }[]";case "rollup":return "{ type: string; function: string; array?: any[]; number?: number; date?: any }";case "created_time":return "{ timestamp: string; date: Date }";case "created_by":case "last_edited_by":return "{ id: string; name: string | null; avatar_url: string | null; object: string; type: string; email?: string }";case "last_edited_time":return "{ timestamp: string; date: Date }";case "status":return "{ id: string; name: string; color: string } | null";case "unique_id":return "{ prefix: string | null; number: number }";default:return "any"}},p=[];p.push(`export const ${r}FieldTypes = {`),p.push(' "id": { type: "unique_id" },');for(let[t,s]of Object.entries(n)){let h;if(s.type==="select"||s.type==="multi_select"){let l=(s.type==="select"?s.select.options:s.multi_select.options).map(c=>`"${c.name}"`).join(", ");p.push(` "${t}": {
type: "${s.type}",
options: [${l}] as const
},`);}else p.push(` "${t}": { type: "${s.type}" },`);}p.push("} as const satisfies DatabaseFieldMetadata;"),e.addStatements(p.join(`
`));let d=r,o=`${d}Advanced`,a=`${d}Raw`;e.addInterface({name:o,properties:[{name:"id",type:"string"},...Object.entries(n).map(([t,s])=>({name:N(t),type:b(s.type)}))],isExported:!0}),e.addInterface({name:a,properties:[{name:"id",type:"string"},{name:"properties",type:"Record<string, any>"}],isExported:!0}),e.addInterface({name:d,extends:["DatabaseRecord"],properties:[{name:"id",type:"string"},...Object.entries(n).map(([t,s])=>({name:N(t),type:v(s.type,s)})),{name:"advanced",type:o},{name:"raw",type:a}],isExported:!0});let f=`query${i.replace(/[^\w\s]/g,"").replace(/\s+(.)/g,(t,s)=>s.toUpperCase()).replace(/\s/g,"").replace(/^./,t=>t.toUpperCase())}`;e.addStatements(`
// Extend NotionCMS class with database-specific method
/* eslint-disable */
declare module "@mikemajara/notion-cms" {
interface NotionCMS {
/**
* Type-safe query method for the ${i} database
* @param databaseId The ID of the database to query
* @returns A type-safe QueryBuilder for the ${r} record type
*/
${f}(databaseId: string): QueryBuilder<${r}, typeof ${r}FieldTypes>;
}
}
// Implement the method on the NotionCMS prototype
NotionCMS.prototype.${f} = function(databaseId: string): QueryBuilder<${r}, typeof ${r}FieldTypes> {
return this.query<${r}, typeof ${r}FieldTypes>(databaseId, ${r}FieldTypes);
};
`);}catch(b){console.error("Error generating database-specific types:",b);}}function P(e,n){console.warn("processNotionRecord is deprecated. Use DatabaseService.processNotionRecord() for the unified processing method with proper file handling and layered access.");let r={id:e.id},i={id:e.id};for(let[p,d]of Object.entries(e.properties)){let o=d;r[p]=S(o),i[p]=S(o);}return {id:e.id,...r,advanced:{id:e.id,...i},raw:{id:e.id,properties:e.properties}}}function S(e){switch(e.type){case "title":return e.title?.[0]?.plain_text??"";case "rich_text":return e.rich_text?.[0]?.plain_text??"";case "number":return e.number;case "select":return e.select?.name??null;case "multi_select":return e.multi_select?.map(t=>t.name)??[];case "date":let i=e;return i.date?new Date(i.date.start):null;case "people":return e.people?.map(t=>t.name||"")??[];case "files":return e.files?.map(t=>({name:t.name,url:t.type==="external"?t.external?.url:t.file?.url}))??[];case "checkbox":return e.checkbox;case "url":return e.url;case "email":return e.email;case "phone_number":return e.phone_number;case "formula":return e.formula;case "relation":return e.relation?.map(t=>t.id)??[];case "rollup":return e.rollup;case "created_time":return e.created_time;case "created_by":let o=e.created_by;return o?{id:o.id,name:o.name,avatar_url:o.avatar_url}:null;case "last_edited_time":return e.last_edited_time;case "last_edited_by":let a=e.last_edited_by;return a?{id:a.id,name:a.name,avatar_url:a.avatar_url}:null;case "unique_id":return e.unique_id?.number??null;default:return null}}function w(e,n){return console.warn("processNotionRecords is deprecated. Use DatabaseService.processNotionRecords() for the unified processing method with proper file handling and layered access."),e.map(r=>P(r))}function Q(e){return P(e)}function Y(e){return w(e)}function V(e){return P(e)}function z(e){return w(e)}async function H(e,n,r,i=false){let b=new client.Client({auth:r}),d=T__namespace.join(n,"notion-types-combined.ts");if(___namespace.existsSync(d)&&!i){console.warn(`File ${d} already exists. Use --force to overwrite.`);return}let a=new tsMorph.Project().createSourceFile(d,"",{overwrite:true});a.addStatements(`/**
* THIS FILE IS AUTO-GENERATED BY NOTION-CMS
* DO NOT EDIT DIRECTLY - YOUR CHANGES WILL BE OVERWRITTEN
*
* Generated for multiple databases: ${e.join(", ")}
*/`),a.addImportDeclaration({moduleSpecifier:"@mikemajara/notion-cms",namedImports:["DatabaseRecord","NotionCMS","QueryBuilder","DatabaseFieldMetadata"]});let f=[];for(let t of e)try{console.log(`Processing database: ${t}`);let s=await b.databases.retrieve({database_id:t}),h=s.properties,l=`Database${t.substring(0,8)}`,c=s;if(c.title&&Array.isArray(c.title)&&c.title.length>0){let y=c.title[0].plain_text;y&&(l=y);}let u=x(l),m=`query${l.replace(/[^\w\s]/g,"").replace(/\s+(.)/g,(y,g)=>g.toUpperCase()).replace(/\s/g,"").replace(/^./,y=>y.toUpperCase())}`,R=1,E=m;for(;f.includes(m);)m=`${E}${R}`,R++;f.push(m),a.addStatements(`
// ============================================================================
// ${l} Database Types
// ============================================================================
`),a.addStatements(`export const ${u}FieldTypes = {`),a.addStatements(' "id": { type: "string" },');for(let[y,g]of Object.entries(h))if(g.type==="select"||g.type==="multi_select"){let F=(g.type==="select"?g.select.options:g.multi_select.options).map(C=>`"${C.name}"`).join(", ");a.addStatements(` "${y}": {
type: "${g.type}",
options: [${F}] as const
},`);}else a.addStatements(` "${y}": { type: "${g.type}" },`);a.addStatements("} as const satisfies DatabaseFieldMetadata;");let A=y=>{switch(y){case "title":return "{ content: string; annotations: any; href: string | null; link?: { url: string } | null }[]";case "rich_text":return "{ content: string; annotations: any; href: string | null; link?: { url: string } | null }[]";case "number":return "number";case "select":return "{ id: string; name: string; color: string } | null";case "multi_select":return "{ id: string; name: string; color: string }[]";case "date":return "{ start: string; end: string | null; time_zone: string | null; parsedStart: Date | null; parsedEnd: Date | null } | null";case "people":return "{ id: string; name: string | null; avatar_url: string | null; object: string; type: string; email?: string }[]";case "files":return "{ name: string; type: string; external?: { url: string }; file?: { url: string; expiry_time: string } }[]";case "checkbox":return "boolean";case "url":return "string";case "email":return "string";case "phone_number":return "string";case "formula":return "{ type: string; value: any }";case "relation":return "{ id: string }[]";case "rollup":return "{ type: string; function: string; array?: any[]; number?: number; date?: any }";case "created_time":return "{ timestamp: string; date: Date }";case "created_by":case "last_edited_by":return "{ id: string; name: string | null; avatar_url: string | null; object: string; type: string; email?: string }";case "last_edited_time":return "{ timestamp: string; date: Date }";case "status":return "{ id: string; name: string; color: string } | null";case "unique_id":return "{ prefix: string | null; number: number }";default:return "any"}},j=u,$=`${j}Advanced`,I=`${j}Raw`;a.addInterface({name:$,properties:[{name:"id",type:"string"},...Object.entries(h).map(([y,g])=>({name:N(y),type:A(g.type)}))],isExported:!0}),a.addInterface({name:I,properties:[{name:"id",type:"string"},{name:"properties",type:"Record<string, any>"}],isExported:!0}),a.addInterface({name:j,extends:["DatabaseRecord"],properties:[{name:"id",type:"string"},...Object.entries(h).map(([y,g])=>({name:N(y),type:v(g.type,g)})),{name:"advanced",type:$},{name:"raw",type:I}],isExported:!0});}catch(s){console.error(`Error processing database ${t}:`,s);}a.addStatements(`
// ============================================================================
// NotionCMS Extension Methods
// ============================================================================
// Extend NotionCMS class with database-specific methods
/* eslint-disable */
declare module "@mikemajara/notion-cms" {
interface NotionCMS {`);for(let t=0;t<e.length;t++){let s=e[t],h=f[t];try{let l=await b.databases.retrieve({database_id:s}),c=`Database${s.substring(0,8)}`,u=l;if(u.title&&Array.isArray(u.title)&&u.title.length>0){let R=u.title[0].plain_text;R&&(c=R);}let m=x(c);a.addStatements(` /**
* Type-safe query method for the ${c} database
* @param databaseId The ID of the database to query
* @returns A type-safe QueryBuilder for the ${m} record type
*/
${h}(databaseId: string): QueryBuilder<${m}, typeof ${m}FieldTypes>;`);}catch(l){console.error(`Error adding method signature for ${s}:`,l);}}a.addStatements(` }
}
`),a.addStatements(`
// ============================================================================
// Method Implementations
// ============================================================================
`);for(let t=0;t<e.length;t++){let s=e[t],h=f[t];try{let l=await b.databases.retrieve({database_id:s}),c=`Database${s.substring(0,8)}`,u=l;if(u.title&&Array.isArray(u.title)&&u.title.length>0){let R=u.title[0].plain_text;R&&(c=R);}let m=x(c);a.addStatements(`
// Implement ${h} method
NotionCMS.prototype.${h} = function(databaseId: string): QueryBuilder<${m}, typeof ${m}FieldTypes> {
return this.query<${m}, typeof ${m}FieldTypes>(databaseId, ${m}FieldTypes);
};
`);}catch(l){console.error(`Error adding method implementation for ${s}:`,l);}}await a.save(),console.log(`Generated combined types file: ${d}`);}exports.a=G;exports.b=P;exports.c=w;exports.d=Q;exports.e=Y;exports.f=V;exports.g=z;exports.h=H;