@ibalzam/codejitsu-core 0.2.0 → 0.2.1

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.
@@ -11,7 +11,7 @@
11
11
  */
12
12
  import fs from 'fs';
13
13
  import path from 'path';
14
- import { loadConfig, isModuleEnabled } from '../../modules/config/src/load.js';
14
+ import { loadConfig, isModuleEnabled } from '../../modules/config/src/load.mjs';
15
15
 
16
16
  const cwd = process.cwd();
17
17
  const distDir = path.join(cwd, 'dist');
@@ -163,7 +163,9 @@ const webpSet = new Set();
163
163
  }
164
164
  })(distDir);
165
165
 
166
- const PLACEHOLDER_RE = /\b(lorem ipsum|TODO|FIXME|XXX:|placeholder)\b/i;
166
+ // Matches actual placeholder *content*, not CSS ::placeholder or HTML
167
+ // placeholder="..." attributes (both legitimate).
168
+ const PLACEHOLDER_RE = /\b(lorem ipsum|TODO:|FIXME:|XXX:)\b/i;
167
169
 
168
170
  for (const file of htmlFiles) {
169
171
  const rel = path.relative(distDir, file);
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Identity helper that types your `codejitsu.config.ts` export.
3
+ *
4
+ * @example
5
+ * // codejitsu.config.ts
6
+ * import { defineConfig } from '@ibalzam/codejitsu-core/config';
7
+ * export default defineConfig({ site: { url: '...', name: '...' } });
8
+ *
9
+ * @param {import('./types.js').CodejitsuConfig} config
10
+ * @returns {import('./types.js').CodejitsuConfig}
11
+ */
12
+ export function defineConfig(config) {
13
+ return config;
14
+ }
@@ -1,3 +1,5 @@
1
- export * from './types.js';
2
- export { defineConfig } from './define.js';
3
- export { loadConfig, isModuleEnabled } from './load.js';
1
+ export type * from './types.js';
2
+ // @ts-expect-error - .mjs runtime resolves at use time
3
+ export { defineConfig } from './define.mjs';
4
+ // @ts-expect-error - .mjs runtime resolves at use time
5
+ export { loadConfig, isModuleEnabled } from './load.mjs';
@@ -1,7 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { pathToFileURL } from 'url';
4
- import type { CodejitsuConfig } from './types.js';
5
4
 
6
5
  const CANDIDATES = [
7
6
  'codejitsu.config.ts',
@@ -12,43 +11,41 @@ const CANDIDATES = [
12
11
  ];
13
12
 
14
13
  /**
15
- * Loads the Codejitsu config from the current working directory (or `cwd`).
14
+ * Loads the Codejitsu config from the current working directory.
16
15
  *
17
16
  * Search order:
18
17
  * 1. `codejitsu.config.{ts,mts,mjs,js,json}` at cwd root.
19
18
  * 2. `codejitsu` key in `package.json`.
20
19
  *
21
- * `.ts` and `.mts` files are loaded via `jiti` (peer-installable). If `jiti`
22
- * isn't available, the loader skips `.ts` candidates and warns once.
20
+ * `.ts` and `.mts` files load via `jiti`. If `jiti` isn't installed, the
21
+ * loader warns once and falls through to other candidates.
23
22
  *
24
- * Throws if no config is found.
23
+ * @param {string} [cwd=process.cwd()]
24
+ * @returns {Promise<import('./types.js').CodejitsuConfig>}
25
25
  */
26
- export async function loadConfig(cwd: string = process.cwd()): Promise<CodejitsuConfig> {
26
+ export async function loadConfig(cwd = process.cwd()) {
27
27
  for (const name of CANDIDATES) {
28
28
  const filePath = path.join(cwd, name);
29
29
  if (!fs.existsSync(filePath)) continue;
30
30
 
31
31
  if (name.endsWith('.json')) {
32
- return JSON.parse(fs.readFileSync(filePath, 'utf8')) as CodejitsuConfig;
32
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
33
33
  }
34
34
 
35
35
  if (name.endsWith('.ts') || name.endsWith('.mts')) {
36
36
  const config = await loadWithJiti(filePath);
37
37
  if (config) return config;
38
- // jiti unavailable; fall through to other candidates.
39
38
  continue;
40
39
  }
41
40
 
42
- // .mjs / .js — Node can load these directly.
43
41
  const mod = await import(pathToFileURL(filePath).href);
44
- return (mod.default ?? mod) as CodejitsuConfig;
42
+ return mod.default ?? mod;
45
43
  }
46
44
 
47
- // Fallback: package.json `codejitsu` key.
48
45
  const pkgPath = path.join(cwd, 'package.json');
49
46
  if (fs.existsSync(pkgPath)) {
50
47
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
51
- if (pkg.codejitsu) return pkg.codejitsu as CodejitsuConfig;
48
+ if (pkg.codejitsu) return pkg.codejitsu;
52
49
  }
53
50
 
54
51
  throw new Error(
@@ -58,16 +55,16 @@ export async function loadConfig(cwd: string = process.cwd()): Promise<Codejitsu
58
55
  }
59
56
 
60
57
  let jitiWarned = false;
61
- async function loadWithJiti(filePath: string): Promise<CodejitsuConfig | null> {
58
+ async function loadWithJiti(filePath) {
62
59
  try {
63
60
  const jitiMod = await import('jiti');
64
- const jitiFactory = (jitiMod as any).default ?? (jitiMod as any).createJiti ?? jitiMod;
65
- const jiti = typeof jitiFactory === 'function' ? jitiFactory(process.cwd(), { interopDefault: true }) : null;
66
- if (!jiti) {
61
+ const factory = jitiMod.createJiti ?? jitiMod.default ?? jitiMod;
62
+ if (typeof factory !== 'function') {
67
63
  throw new Error('Unexpected jiti API shape.');
68
64
  }
65
+ const jiti = factory(process.cwd(), { interopDefault: true });
69
66
  const mod = await jiti.import(filePath, { default: true });
70
- return (mod as any) as CodejitsuConfig;
67
+ return mod;
71
68
  } catch (err) {
72
69
  if (!jitiWarned) {
73
70
  const reason = err instanceof Error ? err.message : String(err);
@@ -83,14 +80,13 @@ async function loadWithJiti(filePath: string): Promise<CodejitsuConfig | null> {
83
80
 
84
81
  /**
85
82
  * Returns true if the named module is enabled in the config.
86
- * A module is enabled if its key is present and not `false` and not `enabled: false`.
83
+ * @param {import('./types.js').CodejitsuConfig} config
84
+ * @param {'blog'|'seo'|'images'|'llms'|'deploy'} module
85
+ * @returns {boolean}
87
86
  */
88
- export function isModuleEnabled(
89
- config: CodejitsuConfig,
90
- module: 'blog' | 'seo' | 'images' | 'llms' | 'deploy'
91
- ): boolean {
87
+ export function isModuleEnabled(config, module) {
92
88
  const value = config[module];
93
89
  if (value === undefined || value === false) return false;
94
- if (typeof value === 'object' && value !== null && (value as { enabled?: boolean }).enabled === false) return false;
90
+ if (typeof value === 'object' && value !== null && value.enabled === false) return false;
95
91
  return true;
96
92
  }
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import path from 'path';
3
- import { loadConfig, isModuleEnabled } from '../../config/src/load.js';
3
+ import { loadConfig, isModuleEnabled } from '../../config/src/load.mjs';
4
4
  import { optimizeImages } from '../src/optimize.mjs';
5
5
  import { autoBlogImages } from '../src/auto-blog.mjs';
6
6
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import path from 'path';
3
- import { loadConfig, isModuleEnabled } from '../../config/src/load.js';
3
+ import { loadConfig, isModuleEnabled } from '../../config/src/load.mjs';
4
4
  import { generateLlms } from '../src/generate.mjs';
5
5
 
6
6
  const cwd = process.cwd();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ibalzam/codejitsu-core",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "description": "Shared core for Codejitsu Astro sites — reusable code and Claude-facing instructions for blog, SEO, images, deploy, and llms.txt.",
6
6
  "keywords": [
@@ -1,18 +0,0 @@
1
- import type { CodejitsuConfig } from './types.js';
2
-
3
- /**
4
- * Identity helper that types your `codejitsu.config.ts` export.
5
- *
6
- * @example
7
- * // codejitsu.config.ts
8
- * import { defineConfig } from '@ibalzam/codejitsu-core/config';
9
- *
10
- * export default defineConfig({
11
- * site: { url: 'https://example.com', name: 'Example' },
12
- * blog: { mode: 'collection', dateField: 'pubDate', draftField: 'draft' },
13
- * // ...
14
- * });
15
- */
16
- export function defineConfig(config: CodejitsuConfig): CodejitsuConfig {
17
- return config;
18
- }