markopress 0.0.15 → 0.0.16

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.
@@ -77,6 +77,13 @@ export declare const MarkoPressConfigSchema: z.ZodObject<{
77
77
  exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
78
78
  transformItems: z.ZodOptional<z.ZodAny>;
79
79
  }, z.core.$loose>>;
80
+ robots: z.ZodOptional<z.ZodObject<{
81
+ userAgent: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
82
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
83
+ disallow: z.ZodOptional<z.ZodArray<z.ZodString>>;
84
+ crawlDelay: z.ZodOptional<z.ZodNumber>;
85
+ sitemap: z.ZodOptional<z.ZodString>;
86
+ }, z.core.$loose>>;
80
87
  }, z.core.$loose>>;
81
88
  plugins: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodTuple<[z.ZodString, z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>], null>, z.ZodObject<{
82
89
  name: z.ZodString;
@@ -158,6 +165,14 @@ export declare function validateConfig(config: unknown): {
158
165
  exclude?: string[];
159
166
  transformItems?: any;
160
167
  };
168
+ robots?: {
169
+ [x: string]: unknown;
170
+ userAgent?: string | string[];
171
+ allow?: string[];
172
+ disallow?: string[];
173
+ crawlDelay?: number;
174
+ sitemap?: string;
175
+ };
161
176
  };
162
177
  plugins?: (string | [string?, Record<string, unknown>?, ...unknown[]] | {
163
178
  name: string;
@@ -247,6 +262,14 @@ export declare function validateConfigSafe(config: unknown): {
247
262
  exclude?: string[];
248
263
  transformItems?: any;
249
264
  };
265
+ robots?: {
266
+ [x: string]: unknown;
267
+ userAgent?: string | string[];
268
+ allow?: string[];
269
+ disallow?: string[];
270
+ crawlDelay?: number;
271
+ sitemap?: string;
272
+ };
250
273
  };
251
274
  plugins?: (string | [string?, Record<string, unknown>?, ...unknown[]] | {
252
275
  name: string;
@@ -1 +1 @@
1
- import{z as o}from"zod";const e=o.object({type:o.enum(["meta","link","script","base"])}).passthrough(),t=o.object({title:o.string().min(1,{message:"Site title is required"}).max(100,{message:"Site title too long"}),description:o.string().max(500,{message:"Description too long"}).optional(),base:o.string().startsWith("/",{message:"Base must start with /"}).optional(),lang:o.string().regex(/^[a-z]{2}(-[A-Z]{2})?$/,{message:"Invalid language code"}).optional(),head:o.array(e).optional()}),a=o.union([o.string(),o.object({dir:o.string().optional(),sidebar:o.boolean().optional(),toc:o.boolean().optional(),rss:o.boolean().optional(),list:o.boolean().optional()}).passthrough()]),n=o.record(o.string(),a),i=o.object({text:o.string().min(1,{message:"Nav item text is required"}),link:o.string().min(1,{message:"Nav item link is required"})}),s=o.object({text:o.string().min(1,{message:"Sidebar item text is required"}),link:o.string().min(1,{message:"Sidebar item link is required"})}),r=o.record(o.string(),o.union([o.array(s),o.object({autoGenerate:o.boolean()})])),l=o.object({navbar:o.array(i).optional(),sidebar:r.optional()}).passthrough(),p=o.object({name:o.string().regex(/^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,{message:"Invalid theme name"}).refine(o=>!o.includes(".."),{message:"Theme name cannot contain path traversal"}).optional(),designSystem:o.enum(["vitepress","docusaurus","rspress"]).optional(),options:l.optional()}),g=o.object({lineNumbers:o.boolean().optional(),theme:o.object({light:o.string().optional(),dark:o.string().optional()}).optional(),markoTags:o.object({enabled:o.boolean().optional(),tagsDir:o.string().optional()}).optional()}),m=o.object({useCatchAllRoutes:o.boolean().optional(),outDir:o.string().optional(),assetsDir:o.string().optional(),sourcemap:o.boolean().optional(),minify:o.boolean().optional(),clean:o.boolean().optional()}).passthrough(),c=o.union([o.string(),o.tuple([o.string(),o.record(o.string(),o.unknown()).optional()]),o.object({name:o.string().min(1,{message:"Plugin name is required"}),options:o.record(o.string(),o.unknown()).optional()})]),u=o.object({hostname:o.string().optional(),exclude:o.array(o.string()).optional(),transformItems:o.any().optional()}).passthrough(),b=o.object({sitemap:u.optional()}).passthrough().optional();export const MarkoPressConfigSchema=o.object({site:t,contentDir:o.string().optional(),content:n.optional(),theme:p.optional(),markdown:g.optional(),build:m.optional(),search:o.object({enabled:o.boolean().optional()}).passthrough().optional(),seo:b,plugins:o.array(c).optional()});export function validateConfig(o){return MarkoPressConfigSchema.parse(o)}export function validateConfigSafe(o){const e=MarkoPressConfigSchema.safeParse(o);return e.success?{success:!0,data:e.data}:{success:!1,errors:e.error.issues.map(o=>({path:o.path.join("."),message:o.message}))}}
1
+ import{z as o}from"zod";const t=o.object({type:o.enum(["meta","link","script","base"])}).passthrough(),e=o.object({title:o.string().min(1,{message:"Site title is required"}).max(100,{message:"Site title too long"}),description:o.string().max(500,{message:"Description too long"}).optional(),base:o.string().startsWith("/",{message:"Base must start with /"}).optional(),lang:o.string().regex(/^[a-z]{2}(-[A-Z]{2})?$/,{message:"Invalid language code"}).optional(),head:o.array(t).optional()}),a=o.union([o.string(),o.object({dir:o.string().optional(),sidebar:o.boolean().optional(),toc:o.boolean().optional(),rss:o.boolean().optional(),list:o.boolean().optional()}).passthrough()]),n=o.record(o.string(),a),i=o.object({text:o.string().min(1,{message:"Nav item text is required"}),link:o.string().min(1,{message:"Nav item link is required"})}),s=o.object({text:o.string().min(1,{message:"Sidebar item text is required"}),link:o.string().min(1,{message:"Sidebar item link is required"})}),r=o.record(o.string(),o.union([o.array(s),o.object({autoGenerate:o.boolean()})])),l=o.object({navbar:o.array(i).optional(),sidebar:r.optional()}).passthrough(),p=o.object({name:o.string().regex(/^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,{message:"Invalid theme name"}).refine(o=>!o.includes(".."),{message:"Theme name cannot contain path traversal"}).optional(),designSystem:o.enum(["vitepress","docusaurus","rspress"]).optional(),options:l.optional()}),g=o.object({lineNumbers:o.boolean().optional(),theme:o.object({light:o.string().optional(),dark:o.string().optional()}).optional(),markoTags:o.object({enabled:o.boolean().optional(),tagsDir:o.string().optional()}).optional()}),m=o.object({useCatchAllRoutes:o.boolean().optional(),outDir:o.string().optional(),assetsDir:o.string().optional(),sourcemap:o.boolean().optional(),minify:o.boolean().optional(),clean:o.boolean().optional()}).passthrough(),c=o.union([o.string(),o.tuple([o.string(),o.record(o.string(),o.unknown()).optional()]),o.object({name:o.string().min(1,{message:"Plugin name is required"}),options:o.record(o.string(),o.unknown()).optional()})]),u=o.object({hostname:o.string().optional(),exclude:o.array(o.string()).optional(),transformItems:o.any().optional()}).passthrough(),b=o.object({userAgent:o.union([o.string(),o.array(o.string())]).optional(),allow:o.array(o.string()).optional(),disallow:o.array(o.string()).optional(),crawlDelay:o.number().nonnegative().optional(),sitemap:o.string().optional()}).passthrough(),d=o.object({sitemap:u.optional(),robots:b.optional()}).passthrough().optional();export const MarkoPressConfigSchema=o.object({site:e,contentDir:o.string().optional(),content:n.optional(),theme:p.optional(),markdown:g.optional(),build:m.optional(),search:o.object({enabled:o.boolean().optional()}).passthrough().optional(),seo:d,plugins:o.array(c).optional()});export function validateConfig(o){return MarkoPressConfigSchema.parse(o)}export function validateConfigSafe(o){const t=MarkoPressConfigSchema.safeParse(o);return t.success?{success:!0,data:t.data}:{success:!1,errors:t.error.issues.map(o=>({path:o.path.join("."),message:o.message}))}}
@@ -1,7 +1,7 @@
1
1
  import type { MarkoPressPlugin } from '../../plugin/types.js';
2
2
  import type { SeoPluginFactoryOptions } from './types.js';
3
3
  /**
4
- * SEO Plugin - Generates sitemap.xml for SEO
4
+ * SEO Plugin - Generates sitemap.xml and robots.txt
5
5
  *
6
6
  * @example
7
7
  * // In markopress config
@@ -1 +1 @@
1
- import{generateSitemap as o}from"./sitemap.js";export function seoPlugin(e){return{name:"seo",async postBuild(e){const{config:i}=e,s=i.seo;s?.sitemap?await o(e,s.sitemap):console.log("[seo] Sitemap not configured, skipping")}}}export default seoPlugin;
1
+ import{generateSitemap as o}from"./sitemap.js";import{generateRobots as s}from"./robots.js";export function seoPlugin(t){return{name:"seo",async postBuild(e){const{config:i}=e,a=t||i.seo||{},r=i.seo;a?.sitemap||r?.sitemap||a?.robots||r?.robots?((a?.sitemap||r?.sitemap)&&await o(e,a.sitemap||r.sitemap),(a?.robots||r?.robots)&&await s(e,a.robots||r.robots,a.sitemap||r?.sitemap)):console.log("[seo] No SEO generation configured, skipping")}}}export default seoPlugin;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Robots.txt generation for SEO plugin
3
+ */
4
+ import type { ResolvedConfig } from '../../config/types.js';
5
+ import type { SitemapOptions, RobotsOptions } from './types.js';
6
+ /**
7
+ * Post-build context for robots generation
8
+ */
9
+ interface PostBuildContext {
10
+ config: ResolvedConfig;
11
+ outDir: string;
12
+ routes: Record<string, unknown>;
13
+ assets: unknown[];
14
+ allContent: unknown;
15
+ }
16
+ /**
17
+ * Generate robots.txt from seo robots options
18
+ */
19
+ export declare function generateRobots(ctx: PostBuildContext, options?: RobotsOptions, sitemapOptions?: SitemapOptions): Promise<void>;
20
+ export {};
@@ -0,0 +1 @@
1
+ import{promises as t}from"fs";import{join as e}from"path";function r(t,e){if(e?.hostname)return e.hostname;const r=t.site;if(r.url)return r.url;throw Error("Robots hostname is required. Set site.url in config or provide hostname in sitemap/robots options.")}function o(t){return t&&0!==t.length?[...new Set(t.map(t=>t.trim()).filter(Boolean))]:[]}export async function generateRobots(s,n={},i){const{config:a,outDir:l}=s;try{const s=e(l,"public");await t.mkdir(s,{recursive:!0});const p=(c=n.userAgent)?Array.isArray(c)?c.filter(Boolean):[c]:["*"],u=o(n.allow),f=o(n.disallow),h=[];for(const t of p){h.push("User-agent: "+t);for(const t of u)h.push("Allow: "+t);for(const t of f)h.push("Disallow: "+t);"number"==typeof n.crawlDelay&&h.push("Crawl-delay: "+n.crawlDelay),h.push("")}const m=function(t,e,o){if(e?.sitemap){const s=(t.site?.base||"/").replace(/\/$/,""),n=e.sitemap.trim();if(n.startsWith("http://")||n.startsWith("https://"))return n;const i=n.startsWith("/")?n:"/"+n;let a;try{a=r(t,o)}catch{return s&&"/"!==s?`${s}${i}`:i}return s&&"/"!==s?`${a}${s}${i}`:`${a}${i}`}if(!o)return;const s=r(t,o).replace(/\/$/,""),n=(t.site?.base||"/").replace(/\/$/,""),i="/sitemap.xml";return`${s}${n&&"/"!==n?`${n}${i}`:i}`}(a,n,i);for(m&&h.push("Sitemap: "+m);h.length>0&&""===h[h.length-1];)h.pop();const $=e(s,"robots.txt"),g=h.length>0?h.join("\n")+"\n":"User-agent: *\n";await t.writeFile($,g,"utf8"),console.log("[seo] Generated robots.txt")}catch(t){const e=t instanceof Error?t.message:t+"";console.error("[seo] Failed to generate robots.txt: "+e)}var c}
@@ -33,15 +33,41 @@ export interface SitemapOptions {
33
33
  lastmodDateOnly?: boolean;
34
34
  };
35
35
  }
36
+ export interface RobotsOptions {
37
+ /**
38
+ * User agent(s) to apply rules to
39
+ * @default ['*']
40
+ */
41
+ userAgent?: string | string[];
42
+ /**
43
+ * Allowed paths for matching user agents
44
+ */
45
+ allow?: string[];
46
+ /**
47
+ * Disallowed paths for matching user agents
48
+ */
49
+ disallow?: string[];
50
+ /**
51
+ * Optional crawl delay in seconds
52
+ */
53
+ crawlDelay?: number;
54
+ /**
55
+ * Explicit sitemap URL to reference in robots.txt
56
+ * If not provided, generated from site.url / sitemap config when available
57
+ */
58
+ sitemap?: string;
59
+ }
36
60
  /**
37
61
  * SEO plugin configuration
38
62
  */
39
63
  export interface SeoPluginConfig {
40
64
  sitemap?: SitemapOptions;
65
+ robots?: RobotsOptions;
41
66
  }
42
67
  /**
43
68
  * Plugin factory options
44
69
  */
45
70
  export interface SeoPluginFactoryOptions {
46
71
  sitemap?: SitemapOptions;
72
+ robots?: RobotsOptions;
47
73
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markopress",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "description": "A fast, modern static site generator built on Marko.js v6 - drop-in alternative to VitePress and Docusaurus with full content compatibility",
5
5
  "keywords": [
6
6
  "static-site-generator",