cayo 1.3.3 → 1.5.0

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.
package/README.md CHANGED
@@ -143,20 +143,23 @@ The Template file is required, and used to render all of your pages. The output
143
143
 
144
144
  This file is a Svelte component, so you can also import other Svelte components or add rendering logic. For example, you could render different markup wrapping your pages depending on the environment mode like `'development'` or `'production'` (see [config example](docs//config-reference.md#conditional-config)).
145
145
 
146
+ > **Template Placeholder Syntax**<br>
147
+ > Cayo uses HTML comment placeholders: `<!--[cayo-css]-->` for template injection. The `%cayo.*%` syntax is deprecated. See [placeholder syntax guide](#template-placeholder-syntax) below.
148
+
146
149
  > **Note**<br>
147
- > Despite being a Svelte component, the Template file does not support the `<slot>` element, because it itself is prerendered _before_ it is used to prerender page components. The placeholder `%cayo.body%` replaces the basic usage for `<slot>`.
150
+ > Despite being a Svelte component, the Template file does not support the `<slot>` element, because it itself is prerendered _before_ it is used to prerender page components. The placeholder `<!--[cayo-body]-->` replaces the basic usage for `<slot>`.
148
151
 
149
152
  Template files support the following placeholders:
150
153
 
151
- - `%cayo.body%` – the content of a page. Think of this as the `<slot>` of the Template Svelte component
154
+ - `<!--[cayo-body]-->` – the content of a page. Think of this as the `<slot>` of the Template Svelte component
152
155
 
153
- - `%cayo.script%` – where your [entry](#entries) for a page will be imported. This is needed if a page is to render a Cayo Component, but is otherwise optional
156
+ - `<!--[cayo-script]-->` – where your [entry](#entries) for a page will be imported. This is needed if a page is to render a Cayo Component, but is otherwise optional
154
157
 
155
- - `%cayo.css%` – where CSS will be added (as `<link src="style.css">` or `<style>...</style>` depending on your [CSS config option](docs/config-reference.md#cssinternal))
158
+ - `<!--[cayo-css]-->` – where CSS will be added (as `<link src="style.css">` or `<style>...</style>` depending on your [CSS config option](docs/config-reference.md#cssinternal))
156
159
 
157
- - `%cayo.title%` – add a default title to the page only if one is not already set on a specific page (via [`<svelte:head>`](https://svelte.dev/docs#template-syntax-svelte-head) or other some other method). The default title will be generated using the page's filename (e.g., `page.svelte` will have the title `Page`). This placeholder is optional
160
+ - `<!--[cayo-title]-->` – add a default title to the page only if one is not already set on a specific page (via [`<svelte:head>`](https://svelte.dev/docs#template-syntax-svelte-head) or other some other method). The default title will be generated using the page's filename (e.g., `page.svelte` will have the title `Page`). This placeholder is optional
158
161
 
159
- - `%cayo.head%` – `<link>` and `<script>` elements needed by a page, plus any `<svelte:head>` content
162
+ - `<!--[cayo-head]-->` – `<link>` and `<script>` elements needed by a page, plus any `<svelte:head>` content
160
163
 
161
164
  #### Example
162
165
  Technically all of the placeholders are optional, and don't have to be in any particular place within your markup.
@@ -166,13 +169,13 @@ Technically all of the placeholders are optional, and don't have to be in any pa
166
169
  <!DOCTYPE html>
167
170
  <html>
168
171
  <head>
169
- %cayo.head%
170
- %cayo.title%
171
- %cayo.css%
172
+ <!--[cayo-head]-->
173
+ <!--[cayo-title]-->
174
+ <!--[cayo-css]-->
172
175
  </head>
173
176
  <body>
174
- %cayo.body%
175
- %cayo.script%
177
+ <!--[cayo-body]-->
178
+ <!--[cayo-script]-->
176
179
  </body>
177
180
  </html>
178
181
  ```
@@ -183,11 +186,35 @@ Your template doesn't even need to be a valid HTML document—you could be outpu
183
186
  <!-- src/__template.svelte -->
184
187
  <!-- No html, head, or body elements... and that's okay! -->
185
188
  <div>something I want on every page</div>
186
- %cayo.script%
189
+ <!--[cayo-script]-->
190
+ <!--[cayo-css]-->
191
+ <!--[cayo-body]-->
192
+ ```
193
+
194
+ #### Template Placeholder Syntax
195
+
196
+ Cayo supports the following placeholder syntaxes:
197
+
198
+ **Recommended syntax (HTML comments):**
199
+ ```html
200
+ <!--[cayo-title]-->
201
+ <!--[cayo-head]-->
202
+ <!--[cayo-css]-->
203
+ <!--[cayo-body]-->
204
+ <!--[cayo-script]-->
205
+ ```
206
+
207
+ **Deprecated syntax:**
208
+ ```html
209
+ %cayo.title%
210
+ %cayo.head%
187
211
  %cayo.css%
188
212
  %cayo.body%
213
+ %cayo.script%
189
214
  ```
190
215
 
216
+ The HTML comment syntax is reliable since Cayo configures Svelte to preserve comments during SSR compilation. The `%cayo.*%` syntax is deprecated but still supported for backward compatibility.
217
+
191
218
  ### .cayo
192
219
 
193
220
  Once you run your project, you'll see directory named `.cayo` in your project's root. This directory is used for Cayo's internal output. Its contents are served during `cayo dev`, and used to build your project during `cayo build`.
@@ -225,6 +252,39 @@ More on [Svelte options](docs/config-reference.md#svelte-options), [Vite options
225
252
  > **Warning**<br>
226
253
  > Vite plugins will be passed to Cayo, but it's possible that certain plugins may break Cayo if they deal with handling the input differently than vanilla Vite or generate additional output files. Cayo acts like a plugin itself, by handling your source files and transforming them into files that vanilla Vite expects (e.g., the built-in "file-based router" is similar to Vite multi-page plugins).
227
254
 
255
+ ### Cayo Preprocessors
256
+
257
+ To use the improved `component` prop syntax with Cayo components (instead of just string paths), you need to configure the `cayoPreprocess` preprocessors:
258
+
259
+ ```js
260
+ // cayo.config.js
261
+ import { cayoPreprocess } from 'cayo/build';
262
+
263
+ export default {
264
+ svelte: {
265
+ preprocess: [
266
+ cayoPreprocess(),
267
+ // ...other preprocessors
268
+ ]
269
+ }
270
+ }
271
+ ```
272
+
273
+ This preprocessor enhances Cayo's functionality by transforming imported component objects into the appropriate paths that Cayo can resolve. It enables the following syntax:
274
+
275
+ ```svelte
276
+ <!-- Before: String-based approach -->
277
+ <Cayo src="counter.cayo.svelte" />
278
+
279
+ <!-- After: Component-based approach (with preprocessor) -->
280
+ <script>
281
+ import Counter from '$components/counter.cayo.svelte';
282
+ </script>
283
+ <Cayo component={Counter} />
284
+ ```
285
+
286
+ The component preprocessor automatically handles alias resolution (like `$components/`) and provides better developer experience with IDE support, auto-completion, and build-time error checking. Additional preprocessors may be added in the future.
287
+
228
288
  ## Components
229
289
 
230
290
  By default, all components are prerendered. This means their lifecycle ends after they finish one run cycle, and the UI state after the first cycle is rendered to static HTML. This also means that any JS you use within the component's `<script>` element "compiles away" after it's used to render the component. These components are essentially "server side rendered", but are done so locally within Cayo processes rather than on a production server.
@@ -248,6 +308,25 @@ The `<Cayo>` component doesn't actually render your Cayos—instead it creates _
248
308
  ### Basic Usage
249
309
 
250
310
  Let's assume the component `components/counter.cayo.svelte` exists in your project, and has a prop `count`:
311
+
312
+ #### Component object syntax (recommended):
313
+ ```svelte
314
+ <!-- Register your Cayo with the imported component -->
315
+ <script>
316
+ import { Cayo } from 'cayo';
317
+ import Counter from '$components/counter.cayo.svelte';
318
+ </script>
319
+ <!-- Basic usage -->
320
+ <Cayo component={Counter} />
321
+ <!-- Any additional props will be used to hydrate the Cayo on the client -->
322
+ <Cayo component={Counter} count={1} />
323
+ ```
324
+
325
+ When using the `component` prop, you can import your Cayo components directly. This provides better developer experience with auto-completion and build-time error checking.
326
+
327
+ > **Note:** To use the `component` prop syntax, you must configure `cayoPreprocess` in your `cayo.config.js`. See [Cayo Preprocessors](#cayo-preprocessors) for setup instructions.
328
+
329
+ #### String path syntax (classic):
251
330
  ```svelte
252
331
  <!-- Register your Cayo with the <Cayo> component -->
253
332
  <script>
@@ -259,7 +338,7 @@ Let's assume the component `components/counter.cayo.svelte` exists in your proje
259
338
  <Cayo src="counter.cayo.svelte" count={1} />
260
339
  ```
261
340
 
262
- The `src` prop is the only required prop, and is used to identify which Cayo Component should be rendered later. The value of `src` needs to be the path of a Cayo, but must be relative to the components directory (e.g., `src/components` by default). For example, say your Cayo was `components/nested/counter.cayo.svelte`, your usage would need to change to `<Cayo src="nested/counter.cayo.svelte" />`.
341
+ The `src` prop is used to identify which Cayo Component should be rendered later. The value of `src` needs to be the path of a Cayo, but must be relative to the components directory (e.g., `src/components` by default). For example, say your Cayo was `components/nested/counter.cayo.svelte`, your usage would need to change to `<Cayo src="nested/counter.cayo.svelte" />`.
263
342
 
264
343
  The `<Cayo>` component can be rendered on a page or any other Svelte component except other Cayos.
265
344
 
@@ -292,11 +371,12 @@ And `page.svelte` registers that Cayo component, like so:
292
371
  <!-- src/pages/page.svelte -->
293
372
  <script>
294
373
  import { Cayo, Entry } from 'cayo';
374
+ import Counter from '../components/counter.cayo.svelte';
295
375
  </script>
296
376
  <!-- Say you want to start the count as 1 instead of 0, you can pass that value as a prop -->
297
- <Cayo src="counter.cayo.svelte" count={1} />
377
+ <Cayo component={Counter} count={1} />
298
378
  <!-- Declare the entry -->
299
- <Entry src="entry.js" />
379
+ <Entry />
300
380
  ```
301
381
 
302
382
  The resulting output will be a placeholder for the component. By default, this placeholder is used as the target for that Svelte component to mount to:
@@ -336,19 +416,37 @@ An entry serves two purposes:
336
416
 
337
417
  Since not every page will necessarily need Cayos, including an entry file at all is optional. You can define different entries per page, or even use the same file for all pages.
338
418
 
339
- Adding an entry to a page:
419
+ ### Default Entry File
420
+
421
+ By default, the `<Entry>` component looks for `entry.js` in your `src` directory:
422
+
423
+ ```svelte
424
+ <!-- src/pages/page.svelte -->
425
+ <script>
426
+ import { Entry } from 'cayo';
427
+ </script>
428
+ <!-- ...other page stuff -->
429
+ <Entry />
430
+ ```
431
+
432
+ This will use `src/entry.js` as the entry file for the page.
433
+
434
+ ### Custom Entry Files
435
+
436
+ You can specify a different entry file using the `src` prop:
437
+
340
438
  ```svelte
341
439
  <!-- src/pages/page.svelte -->
342
440
  <script>
343
441
  import { Entry } from 'cayo';
344
442
  </script>
345
443
  <!-- ...other page stuff -->
346
- <Entry src="entry.js" />
444
+ <Entry src="main.js" />
347
445
  ```
348
446
 
349
- Using the `<Entry>` component tells Cayo to use that file as the page's entry. The `src` attribute should point at JS file that is **relative to the [`src` directory](#source-directory)**, rather than relative to the page itself.
447
+ The `src` attribute should point at a JS file that is **relative to the [`src` directory](#source-directory)**, rather than relative to the page itself.
350
448
 
351
- Note: the name `entry.js` is used in the examples, but there are no limitations on the path or name, as long as it's in the `src` directory.
449
+ Note: You can use any filename and path structure you want within the `src` directory.
352
450
 
353
451
  ### Render Hook
354
452
 
@@ -419,7 +517,7 @@ Say you want to render something in a Cayo before it gets hydrated, like a "load
419
517
  <!-- This will render inside the placeholder because the <Cayo> component renders a <slot> -->
420
518
  Loading counter...
421
519
  </Cayo>
422
- <Entry src="entry.js" />
520
+ <Entry />
423
521
  ```
424
522
 
425
523
  ```js
@@ -489,9 +587,7 @@ Page:
489
587
  <!-- src/pages/page.svelte -->
490
588
 
491
589
  <!-- ...other page stuff -->
492
- <slot name="entry">
493
- <script src="entry.js" data-cayo-entry />
494
- </slot>
590
+ <Entry />
495
591
  ```
496
592
 
497
593
  ## Cayo & the Rest
@@ -41,10 +41,28 @@ function checkBadProps(warnings, src, keys) {
41
41
  /* src/cayo.svelte generated by Svelte v3.59.2 */
42
42
 
43
43
  const Cayo = create_ssr_component(($$result, $$props, $$bindings, slots) => {
44
- let $$restProps = compute_rest_props($$props, ["src","attributes"]);
45
- let { src } = $$props;
44
+ let $$restProps = compute_rest_props($$props, ["src","component","attributes"]);
45
+ let { src = undefined } = $$props;
46
+ let { component = undefined } = $$props;
46
47
  let { attributes } = $$props;
47
48
 
49
+ // Determine the actual source path
50
+ let actualSrc;
51
+
52
+ if (src) {
53
+ // Traditional string src prop
54
+ actualSrc = src;
55
+ } else if (component && component.__cayoPath) {
56
+ // Component object with extracted path
57
+ actualSrc = component.__cayoPath;
58
+ } else if (typeof component === 'string') {
59
+ // Component passed as string directly
60
+ actualSrc = component;
61
+ } else {
62
+ // Fallback error case
63
+ actualSrc = '';
64
+ }
65
+
48
66
  // Save unserializable prop keys (during stringification)
49
67
  // so we can report them later
50
68
  const badProps = [];
@@ -62,10 +80,10 @@ const Cayo = create_ssr_component(($$result, $$props, $$bindings, slots) => {
62
80
  // const props = toSource({...$$restProps})
63
81
  const props = JSON.stringify({ ...$$restProps }, replacer);
64
82
 
65
- const warnings = getWarnings(src, badProps);
83
+ const warnings = getWarnings(actualSrc, badProps);
66
84
 
67
85
  const cayoInstanceData = {
68
- 'data-cayo-src': !warnings.invalidSrc ? `${src}` : '',
86
+ 'data-cayo-src': !warnings.invalidSrc ? `${actualSrc}` : '',
69
87
  'data-cayo-id': '', // will get set during prerender process based on the src
70
88
 
71
89
  };
@@ -75,6 +93,7 @@ const Cayo = create_ssr_component(($$result, $$props, $$bindings, slots) => {
75
93
  }
76
94
 
77
95
  if ($$props.src === void 0 && $$bindings.src && src !== void 0) $$bindings.src(src);
96
+ if ($$props.component === void 0 && $$bindings.component && component !== void 0) $$bindings.component(component);
78
97
  if ($$props.attributes === void 0 && $$bindings.attributes && attributes !== void 0) $$bindings.attributes(attributes);
79
98
 
80
99
  return `<div${spread(
@@ -3,7 +3,7 @@ import { create_ssr_component, add_attribute } from 'svelte/internal';
3
3
  /* src/entry.svelte generated by Svelte v3.59.2 */
4
4
 
5
5
  const Entry = create_ssr_component(($$result, $$props, $$bindings, slots) => {
6
- let { src } = $$props;
6
+ let { src = "entry.js" } = $$props;
7
7
  if ($$props.src === void 0 && $$bindings.src && src !== void 0) $$bindings.src(src);
8
8
 
9
9
  return `${slots.default
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { default as Cayo } from './cayo.svelte.js';
2
2
  export { default as Entry } from './entry.svelte.js';
3
+ export { cayoPreprocess } from '../lib/preprocessors/index.js';
@@ -275,6 +275,39 @@ export default {
275
275
  ```
276
276
  ---
277
277
 
278
+ ### Enable Cayo Preprocessors
279
+ To use enhanced Cayo features like imported components instead of string paths in `<Cayo>` components, add the `cayoPreprocess` preprocessors:
280
+
281
+ ```js
282
+ // cayo.config.js
283
+ import { cayoPreprocess } from 'cayo/build';
284
+
285
+ export default {
286
+ svelte: {
287
+ preprocess: [
288
+ cayoPreprocess(),
289
+ // other preprocessors...
290
+ ],
291
+ }
292
+ }
293
+ ```
294
+
295
+ This enables the improved component syntax:
296
+ ```svelte
297
+ <!-- Instead of string paths -->
298
+ <Cayo src="counter.cayo.svelte" />
299
+
300
+ <!-- You can use imported components -->
301
+ <script>
302
+ import Counter from '$components/counter.cayo.svelte';
303
+ </script>
304
+ <Cayo component={Counter} />
305
+ ```
306
+
307
+ This preprocessor provides enhanced Cayo functionality. The component preprocessor provides better developer experience with IDE support, auto-completion, and build-time error checking.
308
+
309
+ ---
310
+
278
311
  ### Add `mdsvex`
279
312
  Adding other Svelte preprocessors works similar to how it would in any other Vite + Svelte project.
280
313
 
@@ -1,34 +1,63 @@
1
- import fs, { pathExists } from 'fs-extra';
1
+ import fs from 'fs-extra';
2
2
  import { rollup } from 'rollup';
3
3
  import svelte from 'rollup-plugin-svelte';
4
4
  import resolve from '@rollup/plugin-node-resolve';
5
+ import commonjs from '@rollup/plugin-commonjs';
5
6
  import css from 'rollup-plugin-import-css';
6
7
  import json from '@rollup/plugin-json';
7
8
 
8
9
  function inputOptions(input) {
9
10
  return {
10
11
  input,
11
- external: ['svelte/internal', 'svelte'],
12
+ external: (id) => id === 'svelte' || id.startsWith('svelte/'),
12
13
  onwarn: function ( message ) {
13
14
  if ( /external dependency/.test( message ) ) return;
14
15
  },
15
16
  };
16
17
  }
17
18
 
19
+ function resolvePluginDefaults(overrides = {}) {
20
+ return {
21
+ browser: false,
22
+ exportConditions: ['svelte'],
23
+ extensions: ['.svelte'],
24
+ dedupe: ['svelte'],
25
+ ...overrides,
26
+ }
27
+ }
28
+
29
+ function sveltePluginDefaults() {
30
+ return {
31
+ onwarn: (warning, handler) => {
32
+ console.log('Svelte processing:', warning.filename);
33
+ handler(warning);
34
+ }
35
+ }
36
+ }
37
+
18
38
  function defaultRollupPlugins() {
19
- return [css(), json()];
39
+ return [
40
+ commonjs({
41
+ include: /node_modules/,
42
+ }),
43
+ css(),
44
+ json()
45
+ ];
20
46
  }
21
47
 
22
48
  function userRollupPlugins(config) {
23
49
  return config.vite.rollupOptions.plugins;
24
50
  }
25
51
 
26
- export async function getDeps(input, config) {
27
- let bundle;
28
- // User-defined preprocessors
29
- let preprocessors = config.svelte.preprocess.length > 0
52
+ function getUserDefinedPreprocessors(config) {
53
+ return config.svelte.preprocess.length > 0
30
54
  ? config.svelte.preprocess
31
55
  : [config.svelte.preprocess];
56
+ }
57
+
58
+ export async function getDeps(input, config) {
59
+ let bundle;
60
+ let preprocessors = getUserDefinedPreprocessors(config);
32
61
 
33
62
  const options = {
34
63
  ...inputOptions(input),
@@ -37,11 +66,10 @@ export async function getDeps(input, config) {
37
66
  preprocess: [
38
67
  ...preprocessors,
39
68
  ],
69
+ ...sveltePluginDefaults(),
40
70
  }),
41
71
  resolve({
42
- browser: true,
43
- exportConditions: ['svelte'],
44
- extensions: ['.svelte'],
72
+ ...resolvePluginDefaults(),
45
73
  }),
46
74
  ...defaultRollupPlugins(),
47
75
  ...userRollupPlugins(config),
@@ -77,15 +105,26 @@ export async function getDeps(input, config) {
77
105
  }
78
106
 
79
107
  export async function build(input, config, type = 'page') {
80
- const template = (type === 'page' || type === 'template');
108
+ const ssr = (type === 'page' || type === 'template');
109
+ const isCayo = (type === 'cayo');
81
110
  const requiredCompilerOptions = {
82
- generate: template ? 'ssr' : 'dom',
83
- hydratable: template ? false : true,
84
- preserveComments: template
85
- ? false
86
- : config.svelte.compilerOptions.preserveComments
87
- ? config.svelte.compilerOptions.preserveComments
88
- : true,
111
+ // Generic defaults for all builds
112
+ preserveWhitespace: true,
113
+ }
114
+
115
+ if (ssr) {
116
+ // Pages & Templates (SSR): server-side rendered
117
+ requiredCompilerOptions.generate = 'ssr';
118
+ requiredCompilerOptions.hydratable = false;
119
+
120
+ if (type === 'template') {
121
+ // Templates need comments preserved for Cayo placeholders
122
+ requiredCompilerOptions.preserveComments = true;
123
+ }
124
+ } else {
125
+ // Cayo Components (DOM): client-side hydration
126
+ requiredCompilerOptions.generate = 'dom';
127
+ requiredCompilerOptions.hydratable = true;
89
128
  }
90
129
 
91
130
  let bundle;
@@ -94,18 +133,17 @@ export async function build(input, config, type = 'page') {
94
133
  css: { code: '' },
95
134
  dependencies: [],
96
135
  };
97
- // User-defined preprocessors
98
- let preprocessors = config.svelte.preprocess.length > 0
99
- ? config.svelte.preprocess
100
- : [config.svelte.preprocess];
136
+ let preprocessors = getUserDefinedPreprocessors(config);
101
137
 
102
138
  const options = {
103
139
  ...inputOptions(input),
104
140
  plugins: [
141
+ ...defaultRollupPlugins(),
105
142
  svelte({
106
143
  preprocess: [
107
144
  ...preprocessors,
108
145
  ],
146
+ ...sveltePluginDefaults(),
109
147
  compilerOptions: {
110
148
  preserveWhitespace: true,
111
149
  ...config.svelte.compilerOptions,
@@ -113,7 +151,11 @@ export async function build(input, config, type = 'page') {
113
151
  },
114
152
  extensions: config.svelte.extensions,
115
153
  }),
116
- ...defaultRollupPlugins(),
154
+ resolve({
155
+ ...resolvePluginDefaults({
156
+ browser: isCayo,
157
+ }),
158
+ }),
117
159
  ...userRollupPlugins(config),
118
160
  ]
119
161
  }
@@ -123,7 +123,7 @@ export async function processPage(content, page, _cayo, logger) {
123
123
  } else {
124
124
  if (cayoAssetCssElements) {
125
125
  logger.log.info(
126
- chalk.yellow.bold('Warning') + chalk.yellow(': No %cayo.css% found in template, but there is CSS used in source files.'),
126
+ chalk.yellow.bold('Warning') + chalk.yellow(': No <template cayo="css"> found in template, but there is CSS used in source files.'),
127
127
  { timestamp: true, clear: false, }
128
128
  );
129
129
  }
@@ -1,3 +1,6 @@
1
+ import logger from '../logger.js';
2
+ import chalk from 'chalk';
3
+
1
4
  export class Renderer {
2
5
 
3
6
  constructor(template) {
@@ -35,17 +38,44 @@ export class Renderer {
35
38
  // Note: Q: why the `() => str` for 2nd replacement arg?
36
39
  // A: In case there's dollar signs in that there string
37
40
  // https://stackoverflow.com/questions/9423722/string-replace-weird-behavior-when-using-dollar-sign-as-replacement
41
+ // Check for deprecated %cayo.*% syntax and log deprecation warnings
42
+ // Use a more specific regex and avoid overlapping matches
43
+ const deprecatedPlaceholders = [];
44
+ const regex = /%cayo\.[a-zA-Z]+%/g;
45
+ let match;
46
+ while ((match = regex.exec(this.template.html)) !== null) {
47
+ deprecatedPlaceholders.push(match[0]);
48
+ }
49
+
50
+ if (deprecatedPlaceholders.length > 0 && !this._deprecationWarningLogged) {
51
+ this._deprecationWarningLogged = true;
52
+ const uniquePlaceholders = [...new Set(deprecatedPlaceholders)];
53
+
54
+
55
+ logger.log.info(
56
+ chalk.yellow.bold('Deprecation Warning') + chalk.yellow(` [Page: ${page.name}]: Found deprecated placeholder syntax: ${uniquePlaceholders.join(', ')}. Please migrate to <template cayo="..."> syntax. \nMore info: https://github.com/matthew-ia/cayo#template-placeholder-migration`),
57
+ { timestamp: true, clear: false }
58
+ );
59
+ }
60
+
61
+ const finalHtml = this.template.html
62
+ // Strip placeholders wrapped in HTML comments
63
+ .replace(/<!--[\s\S]?%cayo\.\w+%[\s\S]*?(-->)/g, '')
64
+ // Inject markup in HTML comment placeholders
65
+ .replace(/<!--\s*\[cayo-css\]\s*-->/g, () => cssElements)
66
+ .replace(/<!--\s*\[cayo-head\]\s*-->/g, () => head)
67
+ .replace(/<!--\s*\[cayo-body\]\s*-->/g, () => html)
68
+ .replace(/<!--\s*\[cayo-title\]\s*-->/g, () => !head.includes('<title>') ? title() : '')
69
+ .replace(/<!--\s*\[cayo-script\]\s*-->/g, () => `<script type="module" src="./index.js"></script>`)
70
+ // Support deprecated %cayo.*% syntax for backward compatibility
71
+ .replace(/%cayo\.title%/g, () => !head.includes('<title>') ? title() : '')
72
+ .replace(/%cayo\.head%/g, () => head)
73
+ .replace(/%cayo\.body%/g, () => html)
74
+ .replace(/%cayo\.css%/g, () => cssElements)
75
+ .replace(/%cayo\.script%/g, () => `<script type="module" src="./index.js"></script>`);
76
+
38
77
  return {
39
- html: this.template.html
40
- // Strip placeholders wrapped in HTML comments
41
- .replace(/<!--[\s\S]?%cayo\.\w+%[\s\S]*?(-->)/g, '')
42
- // Inject markup in the cayo placeholders
43
- .replace('%cayo.title%', () => !head.includes('<title>') ? title() : '')
44
- .replace('%cayo.head%', () => head)
45
- .replace('%cayo.body%', () => html)
46
- .replace('%cayo.css%', () => cssElements)
47
- // Vite needs the entry file in this format
48
- .replace('%cayo.script%', () => `<script type="module" src="./index.js"></script>`),
78
+ html: finalHtml,
49
79
  css,
50
80
  }
51
81
  }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Svelte preprocessor that transforms Cayo component imports
3
+ * from object references to string paths
4
+ */
5
+ export function cayoComponentPreprocessor() {
6
+ return {
7
+ script({ content, attributes }) {
8
+ // Only process if the script contains .cayo.svelte imports
9
+ if (!content.includes('.cayo.svelte')) return;
10
+
11
+ // Transform: import Component from '$components/Component.cayo.svelte' or './components/Component.cayo.svelte'
12
+ // Into: import Component from '...'; Component.__cayoPath = 'Component.cayo.svelte';
13
+ const transformedContent = content.replace(
14
+ /import\s+(\w+)\s+from\s+['"]([^'"]*\/)?([^\/'"]+\.cayo\.svelte)['"]\s*;/g,
15
+ (match, varName, pathPrefix, filename) => {
16
+ return `${match}\n if (${varName}) ${varName}.__cayoPath = '${filename}';`;
17
+ }
18
+ );
19
+
20
+ return transformedContent !== content ? { code: transformedContent } : null;
21
+ }
22
+ };
23
+ }
@@ -0,0 +1,10 @@
1
+ import { cayoComponentPreprocessor } from './cayo-component.js';
2
+
3
+ /**
4
+ * Cayo preprocessor for Svelte
5
+ * Currently includes component import transformation
6
+ * Future preprocessors and config options can be added here
7
+ */
8
+ export function cayoPreprocess(options = {}) {
9
+ return cayoComponentPreprocessor();
10
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cayo",
3
- "version": "1.3.3",
3
+ "version": "1.5.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "start": "node cayo dev --projectRoot test",
@@ -30,6 +30,7 @@
30
30
  },
31
31
  "homepage": "https://github.com/matthew-ia/cayo#readme",
32
32
  "dependencies": {
33
+ "@rollup/plugin-commonjs": "^29.0.0",
33
34
  "@rollup/plugin-json": "^4.1.0",
34
35
  "@rollup/plugin-node-resolve": "^16.0.0",
35
36
  "chalk": "^2.4.2",
package/scripts/build.js CHANGED
@@ -36,6 +36,8 @@ function generateIndex(modules) {
36
36
  for (const m of modules) {
37
37
  js += `export { default as ${m[0]} } from '${m[1]}';\n`;
38
38
  }
39
+ // Add preprocessor exports
40
+ js += `export { cayoPreprocess } from '../lib/preprocessors/index.js';\n`;
39
41
  return { code: js };
40
42
  }
41
43
 
package/src/cayo.svelte CHANGED
@@ -1,8 +1,25 @@
1
1
  <script>
2
2
  import { getWarnings } from './cayo-warnings.js';
3
- export let src;
3
+ export let src = undefined;
4
+ export let component = undefined; // New prop for component objects
4
5
  export let attributes;
5
6
 
7
+ // Determine the actual source path
8
+ let actualSrc;
9
+ if (src) {
10
+ // Traditional string src prop
11
+ actualSrc = src;
12
+ } else if (component && component.__cayoPath) {
13
+ // Component object with extracted path
14
+ actualSrc = component.__cayoPath;
15
+ } else if (typeof component === 'string') {
16
+ // Component passed as string directly
17
+ actualSrc = component;
18
+ } else {
19
+ // Fallback error case
20
+ actualSrc = '';
21
+ }
22
+
6
23
  // Save unserializable prop keys (during stringification)
7
24
  // so we can report them later
8
25
  const badProps = [];
@@ -21,9 +38,9 @@
21
38
 
22
39
  // const props = toSource({...$$restProps})
23
40
  const props = JSON.stringify({...$$restProps}, replacer);
24
- const warnings = getWarnings(src, badProps);
41
+ const warnings = getWarnings(actualSrc, badProps);
25
42
  const cayoInstanceData = {
26
- 'data-cayo-src': !warnings.invalidSrc ? `${src}` : '',
43
+ 'data-cayo-src': !warnings.invalidSrc ? `${actualSrc}` : '',
27
44
  'data-cayo-id': '', // will get set during prerender process based on the src
28
45
  };
29
46
  if (warnings) {
package/src/entry.svelte CHANGED
@@ -1,5 +1,5 @@
1
1
  <script>
2
- export let src;
2
+ export let src = "entry.js";
3
3
  </script>
4
4
  <slot>
5
5
  <script src="{src}" data-cayo-entry />
@@ -1,3 +1,11 @@
1
+ import { cayoPreprocess } from 'cayo/build';
2
+
1
3
  export default {
2
- // options...
4
+ svelte: {
5
+ preprocess: [
6
+ cayoPreprocess(),
7
+ // Add other preprocessors here as needed
8
+ ]
9
+ }
10
+ // Add other options as needed...
3
11
  }
@@ -3,12 +3,12 @@
3
3
  <meta charset="UTF-8" />
4
4
  <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏝</text></svg>">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- %cayo.title%
7
- %cayo.css%
8
- %cayo.head%
6
+ <template cayo="title"></template>
7
+ <template cayo="css"></template>
8
+ <template cayo="head"></template>
9
9
  </head>
10
10
  <body>
11
- %cayo.body%
12
- %cayo.script%
11
+ <template cayo="body"></template>
12
+ <template cayo="script"></template>
13
13
  </body>
14
14
  </html>
@@ -1,15 +1,28 @@
1
1
  <script>
2
2
  import { Cayo, Entry } from 'cayo';
3
+ import Counter from '../components/counter.cayo.svelte';
3
4
  const heading = '🏝 Cayo';
4
5
  </script>
5
6
 
6
7
  <h1>{heading}</h1>
8
+
9
+ <p>Example with component import (recommended):</p>
10
+ <Cayo component={Counter} />
11
+
12
+ <p>Example with string path (classic):</p>
7
13
  <Cayo src="counter.cayo.svelte" />
8
- <Entry src="index.js" />
14
+
15
+ <Entry />
9
16
 
10
17
  <style>
11
18
  h1 {
12
19
  text-align: center;
13
20
  font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
14
21
  }
22
+ p {
23
+ text-align: center;
24
+ color: #888;
25
+ font-size: 0.9rem;
26
+ margin: 1rem 0 0.5rem 0;
27
+ }
15
28
  </style>