fimo 0.14.0 → 0.15.0-staging.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.
- package/README.md +1 -0
- package/assets/astro/components/Boolean.astro +14 -0
- package/assets/astro/components/Date.astro +23 -0
- package/assets/astro/components/Image.astro +79 -0
- package/assets/astro/components/Json.astro +14 -0
- package/assets/astro/components/RichText.astro +17 -0
- package/assets/astro/components/StaticImage.astro +66 -0
- package/assets/astro/components/Text.astro +23 -0
- package/assets/astro/components/Video.astro +47 -0
- package/assets/astro/components/index.d.ts +8 -0
- package/assets/astro/components/index.js +8 -0
- package/assets/content-templates/shared/server.eta +56 -0
- package/assets/content-templates/sveltekit/content.eta +86 -0
- package/assets/skills/fimo/SKILL.md +2 -0
- package/assets/skills/fimo-cli/SKILL.md +0 -1
- package/assets/skills/fimo-cli/references/branches.md +14 -13
- package/assets/skills/fimo-cli/references/deploy.md +4 -3
- package/assets/skills/fimo-cli/references/describe.md +1 -1
- package/assets/skills/fimo-cli/references/init.md +11 -11
- package/assets/skills/fimo-cli/references/labels.md +3 -3
- package/assets/skills/fimo-cli/references/locales.md +1 -1
- package/assets/skills/fimo-cli/references/project-vars-and-secrets.md +1 -1
- package/assets/skills/fimo-code/SKILL.md +11 -3
- package/assets/skills/fimo-code/references/assets.md +2 -2
- package/assets/skills/fimo-code/references/content/clients.md +5 -1
- package/assets/skills/fimo-code/references/content.md +3 -1
- package/assets/skills/fimo-code/references/frameworks/astro.md +127 -0
- package/assets/skills/fimo-code/references/frameworks/compatibility.md +19 -0
- package/assets/skills/fimo-code/references/frameworks/hosting.md +15 -3
- package/assets/skills/fimo-code/references/frameworks/react-router.md +37 -209
- package/assets/skills/fimo-code/references/frameworks/sveltekit.md +110 -0
- package/assets/skills/fimo-code/references/frameworks/vite-react.md +35 -166
- package/assets/skills/fimo-code/references/labels.md +16 -6
- package/assets/skills/fimo-code/references/locales.md +3 -1
- package/assets/skills/fimo-code/references/ui.md +19 -15
- package/assets/starters/fimo-site/template/.fimo/agents/content-guide/capabilities.yaml +0 -1
- package/assets/starters/fimo-site/template/.fimo/agents/site-review/capabilities.yaml +0 -1
- package/assets/sveltekit/components/Boolean.svelte +19 -0
- package/assets/sveltekit/components/Date.svelte +33 -0
- package/assets/sveltekit/components/FimoProvider.svelte +35 -0
- package/assets/sveltekit/components/Image.svelte +80 -0
- package/assets/sveltekit/components/Json.svelte +18 -0
- package/assets/sveltekit/components/Label.svelte +16 -0
- package/assets/sveltekit/components/Number.svelte +21 -0
- package/assets/sveltekit/components/RichText.svelte +19 -0
- package/assets/sveltekit/components/Text.svelte +30 -0
- package/assets/sveltekit/components/Video.svelte +37 -0
- package/assets/sveltekit/components/index.d.ts +10 -0
- package/assets/sveltekit/components/index.js +10 -0
- package/dist/build/astro/config.d.ts +4 -0
- package/dist/build/astro/config.js +45 -0
- package/dist/build/next/config.js +16 -0
- package/dist/build/sveltekit/config.d.ts +6 -0
- package/dist/build/sveltekit/config.js +8 -0
- package/dist/build/sveltekit/data-id.d.ts +3 -0
- package/dist/build/sveltekit/data-id.js +171 -0
- package/dist/build/sveltekit/vite.d.ts +13 -0
- package/dist/build/sveltekit/vite.js +15 -0
- package/dist/build/vite/index.js +2 -0
- package/dist/build/vite/plugins/data-id.d.ts +9 -0
- package/dist/build/vite/plugins/data-id.js +6 -1
- package/dist/build/vite/plugins/runtime-env.d.ts +21 -0
- package/dist/build/vite/plugins/runtime-env.js +68 -0
- package/dist/cli/bundle.json +1 -1
- package/dist/cli/index.js +100 -99
- package/dist/runtime/app/FimoProviders.d.ts +1 -1
- package/dist/runtime/app/FimoProviders.js +11 -5
- package/dist/runtime/astro/internal.d.ts +6 -0
- package/dist/runtime/astro/internal.js +16 -0
- package/dist/runtime/astro/preview.d.ts +14 -0
- package/dist/runtime/astro/preview.js +103 -0
- package/dist/runtime/astro/render-rich-text.d.ts +2 -0
- package/dist/runtime/astro/render-rich-text.js +1 -0
- package/dist/runtime/astro/server-runtime.d.ts +3 -0
- package/dist/runtime/astro/server-runtime.js +20 -0
- package/dist/runtime/astro/server.d.ts +15 -0
- package/dist/runtime/astro/server.js +14 -0
- package/dist/runtime/content/client/collection-core.d.ts +2 -17
- package/dist/runtime/content/client/collection-core.js +15 -8
- package/dist/runtime/content/client/core-types.d.ts +96 -0
- package/dist/runtime/content/client/core-types.js +1 -0
- package/dist/runtime/content/client/internal.d.ts +4 -4
- package/dist/runtime/content/client/internal.js +4 -3
- package/dist/runtime/content/client/runtime.d.ts +1 -1
- package/dist/runtime/content/client/server-content-client.d.ts +3 -3
- package/dist/runtime/content/client/server-content-client.js +2 -29
- package/dist/runtime/content/client/singleton-core.d.ts +2 -9
- package/dist/runtime/content/client/singleton-core.js +9 -4
- package/dist/runtime/content/client/types.d.ts +5 -115
- package/dist/runtime/content/index.d.ts +3 -3
- package/dist/runtime/labels/fetch.js +5 -3
- package/dist/runtime/next/client.d.ts +2 -1
- package/dist/runtime/next/facade.d.ts +1 -1
- package/dist/runtime/next/provider.js +1 -1
- package/dist/runtime/next/server-runtime.js +1 -1
- package/dist/runtime/next/server.d.ts +5 -4
- package/dist/runtime/paths/get-fimo-paths.js +8 -3
- package/dist/runtime/preview/bridge.d.ts +8 -0
- package/dist/runtime/preview/bridge.js +20 -0
- package/dist/runtime/preview/location.d.ts +23 -0
- package/dist/runtime/preview/location.js +93 -0
- package/dist/runtime/preview/routes.d.ts +10 -0
- package/dist/runtime/preview/routes.js +29 -0
- package/dist/runtime/primitives/index.d.ts +4 -1
- package/dist/runtime/primitives/index.js +1 -0
- package/dist/runtime/primitives/lib/image-optimization.d.ts +27 -2
- package/dist/runtime/primitives/lib/image-optimization.js +40 -0
- package/dist/runtime/primitives/lib/index.d.ts +1 -1
- package/dist/runtime/primitives/lib/primitives.d.ts +0 -54
- package/dist/runtime/primitives/lib/primitives.js +6 -0
- package/dist/runtime/primitives/lib/render-rich-text.d.ts +3 -0
- package/dist/runtime/primitives/lib/render-rich-text.js +112 -0
- package/dist/runtime/react/primitives/contracts.d.ts +40 -2
- package/dist/runtime/react/primitives/renderers/ImageRenderer.js +15 -34
- package/dist/runtime/react/primitives/renderers/RichTextRenderer.d.ts +2 -1
- package/dist/runtime/react/primitives/renderers/StaticImage.js +13 -30
- package/dist/runtime/routing/AppRoutesProvider.js +20 -8
- package/dist/runtime/shared/env-identity.d.ts +43 -0
- package/dist/runtime/shared/env-identity.js +88 -0
- package/dist/runtime/shared/local-runtime-env.d.ts +65 -0
- package/dist/runtime/shared/local-runtime-env.js +169 -0
- package/dist/runtime/{react-router → shared}/preview-location.d.ts +7 -13
- package/dist/runtime/{react-router → shared}/preview-location.js +26 -27
- package/dist/runtime/sveltekit/content.d.ts +25 -0
- package/dist/runtime/sveltekit/content.js +33 -0
- package/dist/runtime/sveltekit/context-contract.d.ts +5 -0
- package/dist/runtime/sveltekit/context-contract.js +2 -0
- package/dist/runtime/sveltekit/context.d.ts +8 -0
- package/dist/runtime/sveltekit/context.js +25 -0
- package/dist/runtime/sveltekit/index.d.ts +7 -0
- package/dist/runtime/sveltekit/index.js +4 -0
- package/dist/runtime/sveltekit/internal.d.ts +6 -0
- package/dist/runtime/sveltekit/internal.js +12 -0
- package/dist/runtime/sveltekit/labels.d.ts +16 -0
- package/dist/runtime/sveltekit/labels.js +13 -0
- package/dist/runtime/sveltekit/preview.d.ts +19 -0
- package/dist/runtime/sveltekit/preview.js +77 -0
- package/dist/runtime/sveltekit/runtime.d.ts +8 -0
- package/dist/runtime/sveltekit/runtime.js +17 -0
- package/dist/runtime/templates.d.ts +1 -1
- package/dist/runtime/templates.js +1 -1
- package/dist/runtime/vite/Label.d.ts +13 -0
- package/dist/runtime/vite/Label.js +16 -0
- package/dist/scripts/extract-translations.js +103 -43
- package/dist/scripts/sync-forms.js +1 -1
- package/dist/scripts/sync-schemas.js +83 -16
- package/package.json +56 -2
- package/release.json +2 -2
- package/templates/nextjs/_gitignore +1 -0
- package/templates/react-router/package.json +1 -1
- package/templates/sveltekit/.fimo/config.json +15 -0
- package/templates/sveltekit/AGENTS.md +16 -0
- package/templates/sveltekit/CLAUDE.md +5 -0
- package/templates/sveltekit/_gitignore +16 -0
- package/templates/sveltekit/package.json +28 -0
- package/templates/sveltekit/pnpm-workspace.yaml +4 -0
- package/templates/sveltekit/src/app.html +11 -0
- package/templates/sveltekit/src/routes/+layout.server.ts +8 -0
- package/templates/sveltekit/src/routes/+layout.svelte +12 -0
- package/templates/sveltekit/src/routes/+page.svelte +48 -0
- package/templates/sveltekit/svelte.config.js +5 -0
- package/templates/sveltekit/tsconfig.json +14 -0
- package/templates/sveltekit/vite.config.ts +5 -0
- /package/assets/content-templates/{form-template.eta → forms/react.eta} +0 -0
- /package/assets/content-templates/{next-client-template.eta → next/client.eta} +0 -0
- /package/assets/content-templates/{next-server-template.eta → next/server.eta} +0 -0
- /package/assets/content-templates/{hooks-template.eta → react/client.eta} +0 -0
- /package/assets/content-templates/{types-template.eta → shared/types.eta} +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Extract label keys from
|
|
2
|
+
* Extract label keys from application source.
|
|
3
3
|
*
|
|
4
|
-
* Labels are DB-owned. This scanner reports literal `t("key")`
|
|
5
|
-
* `fimo validate` can verify
|
|
6
|
-
*
|
|
4
|
+
* Labels are DB-owned. This scanner reports literal `t("key")` calls and
|
|
5
|
+
* literal `<Label value="key">` elements so `fimo validate` can verify that
|
|
6
|
+
* the tenant DB contains visible values. It never writes label values.
|
|
7
7
|
*/
|
|
8
8
|
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
9
9
|
import { join } from 'node:path';
|
|
10
10
|
import { parseSync } from 'oxc-parser';
|
|
11
|
-
function
|
|
11
|
+
function findSourceFiles(dir, files = []) {
|
|
12
12
|
if (!existsSync(dir)) {
|
|
13
13
|
return files;
|
|
14
14
|
}
|
|
@@ -20,67 +20,127 @@ function findReactFiles(dir, files = []) {
|
|
|
20
20
|
if (entry === 'ui' || entry === 'node_modules') {
|
|
21
21
|
continue;
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
findSourceFiles(fullPath, files);
|
|
24
24
|
}
|
|
25
|
-
else if (/\.(ts|tsx|js|jsx)$/.test(entry)) {
|
|
25
|
+
else if (/\.(ts|tsx|js|jsx|svelte)$/.test(entry)) {
|
|
26
26
|
files.push(fullPath);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
return files;
|
|
30
30
|
}
|
|
31
|
-
function
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
|
|
31
|
+
function importedNames(body, source, importedName) {
|
|
32
|
+
const names = new Set();
|
|
33
|
+
for (const statement of body) {
|
|
34
|
+
if (statement.type !== 'ImportDeclaration' || statement.source.value !== source) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
for (const specifier of statement.specifiers) {
|
|
38
|
+
if (specifier.type === 'ImportSpecifier' &&
|
|
39
|
+
specifier.imported.type === 'Identifier' &&
|
|
40
|
+
specifier.imported.name === importedName) {
|
|
41
|
+
names.add(specifier.local.name);
|
|
40
42
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return names;
|
|
46
|
+
}
|
|
47
|
+
function extractFromModule(filePath, code, parsePath = filePath) {
|
|
48
|
+
const declarations = [];
|
|
49
|
+
const result = parseSync(parsePath, code);
|
|
50
|
+
const ast = result.program;
|
|
51
|
+
const fimoLabelNames = importedNames(ast.body, 'fimo/ui', 'Label');
|
|
52
|
+
function visit(node) {
|
|
53
|
+
if (!node || typeof node !== 'object') {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (node.type === 'CallExpression') {
|
|
57
|
+
const callee = node.callee;
|
|
58
|
+
const isTranslationCall = (callee?.type === 'Identifier' && callee.name === 't') ||
|
|
59
|
+
(callee?.type === 'MemberExpression' &&
|
|
60
|
+
callee.computed === false &&
|
|
61
|
+
callee.object?.type === 'Identifier' &&
|
|
62
|
+
callee.object.name === 'labels' &&
|
|
63
|
+
callee.property?.type === 'Identifier' &&
|
|
64
|
+
callee.property.name === 't');
|
|
65
|
+
if (isTranslationCall) {
|
|
66
|
+
const args = node.arguments || [];
|
|
67
|
+
const firstArg = args[0];
|
|
68
|
+
if (firstArg?.type === 'Literal' && typeof firstArg.value === 'string') {
|
|
69
|
+
declarations.push({ key: firstArg.value, file: filePath });
|
|
57
70
|
}
|
|
58
71
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
72
|
+
}
|
|
73
|
+
if (node.type === 'JSXOpeningElement' &&
|
|
74
|
+
node.name?.type === 'JSXIdentifier' &&
|
|
75
|
+
fimoLabelNames.has(node.name.name)) {
|
|
76
|
+
for (const attribute of node.attributes ?? []) {
|
|
77
|
+
if (attribute?.type === 'JSXAttribute' &&
|
|
78
|
+
attribute.name?.type === 'JSXIdentifier' &&
|
|
79
|
+
attribute.name.name === 'value' &&
|
|
80
|
+
attribute.value?.type === 'Literal' &&
|
|
81
|
+
typeof attribute.value.value === 'string') {
|
|
82
|
+
declarations.push({ key: attribute.value.value, file: filePath });
|
|
65
83
|
}
|
|
66
|
-
|
|
67
|
-
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for (const key of Object.keys(node)) {
|
|
87
|
+
const child = node[key];
|
|
88
|
+
if (Array.isArray(child)) {
|
|
89
|
+
for (const item of child) {
|
|
90
|
+
visit(item);
|
|
68
91
|
}
|
|
69
92
|
}
|
|
93
|
+
else if (typeof child === 'object' && child !== null) {
|
|
94
|
+
visit(child);
|
|
95
|
+
}
|
|
70
96
|
}
|
|
71
|
-
|
|
97
|
+
}
|
|
98
|
+
visit(ast);
|
|
99
|
+
return declarations;
|
|
100
|
+
}
|
|
101
|
+
const SVELTE_SCRIPT = /<script\b[^>]*>([\s\S]*?)<\/script>/gi;
|
|
102
|
+
const SVELTE_COMMENT = /<!--[\s\S]*?-->/g;
|
|
103
|
+
const SVELTE_T_CALL_KEY = /(?:\blabels\.t|(?<![\w$.])t)\(\s*(['"])([^'"]*)\1/g;
|
|
104
|
+
function extractFromSvelte(filePath, code) {
|
|
105
|
+
const declarations = [];
|
|
106
|
+
const labelNames = new Set();
|
|
107
|
+
const markup = code
|
|
108
|
+
.replace(SVELTE_SCRIPT, (_script, contents) => {
|
|
109
|
+
const ast = parseSync(`${filePath}.ts`, contents).program;
|
|
110
|
+
for (const name of importedNames(ast.body, 'fimo/sveltekit/components', 'Label')) {
|
|
111
|
+
labelNames.add(name);
|
|
112
|
+
}
|
|
113
|
+
declarations.push(...extractFromModule(filePath, contents, `${filePath}.ts`));
|
|
114
|
+
return '';
|
|
115
|
+
})
|
|
116
|
+
.replace(SVELTE_COMMENT, '');
|
|
117
|
+
for (const name of labelNames) {
|
|
118
|
+
const labelKey = new RegExp(`<${name}\\b[^>]*?\\svalue=(?:"([^"]*)"|'([^']*)')`, 'g');
|
|
119
|
+
for (const match of markup.matchAll(labelKey)) {
|
|
120
|
+
declarations.push({ key: (match[1] ?? match[2]), file: filePath });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
for (const match of markup.matchAll(SVELTE_T_CALL_KEY)) {
|
|
124
|
+
declarations.push({ key: match[2], file: filePath });
|
|
125
|
+
}
|
|
126
|
+
return declarations;
|
|
127
|
+
}
|
|
128
|
+
function extractFromFile(filePath) {
|
|
129
|
+
try {
|
|
130
|
+
const code = readFileSync(filePath, 'utf-8');
|
|
131
|
+
return filePath.endsWith('.svelte') ? extractFromSvelte(filePath, code) : extractFromModule(filePath, code);
|
|
72
132
|
}
|
|
73
133
|
catch (error) {
|
|
74
134
|
console.error(`Failed to parse ${filePath}:`, error);
|
|
135
|
+
return [];
|
|
75
136
|
}
|
|
76
|
-
return declarations;
|
|
77
137
|
}
|
|
78
138
|
export function extractLabelKeys(options = {}) {
|
|
79
139
|
const cwd = options.cwd ?? process.cwd();
|
|
80
140
|
const srcDir = join(cwd, 'src');
|
|
81
141
|
const declarations = [];
|
|
82
142
|
const seen = new Set();
|
|
83
|
-
for (const file of
|
|
143
|
+
for (const file of findSourceFiles(srcDir)) {
|
|
84
144
|
for (const declaration of extractFromFile(file)) {
|
|
85
145
|
if (seen.has(declaration.key)) {
|
|
86
146
|
continue;
|
|
@@ -44,7 +44,7 @@ export function syncForms(options = {}) {
|
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
46
|
const formsDir = resolve(cwd, FORMS_REL);
|
|
47
|
-
const templatePath = assetPath('content-templates', '
|
|
47
|
+
const templatePath = assetPath('content-templates', 'forms', 'react.eta');
|
|
48
48
|
const templateSource = readFileSync(templatePath, 'utf-8');
|
|
49
49
|
const eta = new Eta({ views: undefined, useWith: true, varName: 'it', autoEscape: false });
|
|
50
50
|
const formFiles = getFormFiles(formsDir);
|
|
@@ -5,7 +5,7 @@ import { basename, dirname, join, resolve } from 'node:path';
|
|
|
5
5
|
* hook files generated from the hooks template.
|
|
6
6
|
*
|
|
7
7
|
* - Scans `<cwd>/src/schemas/*.json`.
|
|
8
|
-
* - Renders shared types plus
|
|
8
|
+
* - Renders shared types plus the framework's React, Next, Astro, or SvelteKit facade.
|
|
9
9
|
* - Creates/updates `<Pascal>.types.ts` and `<Pascal>.ts`, plus `<Pascal>.client.ts` for Next; deletes orphans.
|
|
10
10
|
*/
|
|
11
11
|
import { camelCase, pascalCase } from 'change-case';
|
|
@@ -25,6 +25,14 @@ const SCHEMA_DEFINITION_SCHEMA = z.object({
|
|
|
25
25
|
i18n: z.object({ enabled: z.boolean().optional() }).optional(),
|
|
26
26
|
fields: z.record(z.string(), z.unknown()).optional(),
|
|
27
27
|
});
|
|
28
|
+
const CONTENT_TEMPLATE_PATHS = {
|
|
29
|
+
types: { current: 'shared/types.eta', legacy: 'types-template.eta' },
|
|
30
|
+
sharedServer: { current: 'shared/server.eta' },
|
|
31
|
+
reactClient: { current: 'react/client.eta', legacy: 'hooks-template.eta' },
|
|
32
|
+
nextServer: { current: 'next/server.eta' },
|
|
33
|
+
nextClient: { current: 'next/client.eta' },
|
|
34
|
+
svelteKitContent: { current: 'sveltekit/content.eta' },
|
|
35
|
+
};
|
|
28
36
|
function getSchemaFiles(schemasDir) {
|
|
29
37
|
if (!existsSync(schemasDir)) {
|
|
30
38
|
return [];
|
|
@@ -101,58 +109,117 @@ function resolveProjectRuntime(cwd) {
|
|
|
101
109
|
packageRoot: dirname(packagePath),
|
|
102
110
|
version,
|
|
103
111
|
providesNextRuntime: packageExportsSubpath(packageJson, './next') && packageExportsSubpath(packageJson, './next/client'),
|
|
112
|
+
providesAstroRuntime: packageExportsSubpath(packageJson, './astro'),
|
|
113
|
+
providesSvelteKitRuntime: packageExportsSubpath(packageJson, './sveltekit'),
|
|
104
114
|
};
|
|
105
115
|
}
|
|
106
116
|
function contentRuntimeImportFor(framework) {
|
|
107
|
-
|
|
117
|
+
if (framework === 'nextjs') {
|
|
118
|
+
return 'fimo/next';
|
|
119
|
+
}
|
|
120
|
+
if (framework === 'astro') {
|
|
121
|
+
return 'fimo/astro';
|
|
122
|
+
}
|
|
123
|
+
// @vercel/frameworks reports SvelteKit as `sveltekit-1`, while Fimo's
|
|
124
|
+
// public runtime profile is `sveltekit`. Both describe the same codegen
|
|
125
|
+
// target; callers may supply either the detector evidence or the profile.
|
|
126
|
+
if (framework === 'sveltekit' || framework === 'sveltekit-1') {
|
|
127
|
+
return 'fimo/sveltekit';
|
|
128
|
+
}
|
|
129
|
+
return 'fimo/ui';
|
|
108
130
|
}
|
|
109
|
-
function templatePath(runtime,
|
|
131
|
+
function templatePath(runtime, templateName) {
|
|
132
|
+
const template = CONTENT_TEMPLATE_PATHS[templateName];
|
|
110
133
|
if (runtime && !isVersionAtLeast(runtime.version, MINIMUM_THIN_CONTENT_CLIENT_RUNTIME_VERSION)) {
|
|
111
|
-
|
|
134
|
+
const legacyPath = 'legacy' in template ? template.legacy : template.current;
|
|
135
|
+
return join(runtime.packageRoot, 'assets', 'content-templates', legacyPath);
|
|
112
136
|
}
|
|
113
|
-
return assetPath('content-templates',
|
|
137
|
+
return assetPath('content-templates', template.current);
|
|
114
138
|
}
|
|
115
139
|
function resolveSchemaGenerationTarget(runtimeImport, runtime) {
|
|
116
140
|
if (runtimeImport === 'fimo/ui') {
|
|
117
141
|
return 'react';
|
|
118
142
|
}
|
|
119
|
-
if (!runtime.providesNextRuntime) {
|
|
143
|
+
if (runtimeImport === 'fimo/next' && !runtime.providesNextRuntime) {
|
|
120
144
|
throw new Error(`Cannot generate schema clients because project-local fimo@${runtime.version} does not provide the ` +
|
|
121
145
|
'fimo/next and fimo/next/client exports required by this Next.js project. ' +
|
|
122
146
|
`Run \`${CONTENT_CLIENT_RUNTIME_UPGRADE_COMMAND}\` in the project, then run \`npx fimo@latest validate\` again. ` +
|
|
123
147
|
'No generated files were changed.');
|
|
124
148
|
}
|
|
125
|
-
|
|
149
|
+
if (runtimeImport === 'fimo/astro' && !runtime.providesAstroRuntime) {
|
|
150
|
+
throw new Error(`Cannot generate schema clients because project-local fimo@${runtime.version} does not provide the ` +
|
|
151
|
+
'fimo/astro export required by this Astro project. ' +
|
|
152
|
+
`Run \`${CONTENT_CLIENT_RUNTIME_UPGRADE_COMMAND}\` in the project, then run \`npx fimo@latest validate\` again. ` +
|
|
153
|
+
'No generated files were changed.');
|
|
154
|
+
}
|
|
155
|
+
if (runtimeImport === 'fimo/sveltekit' && !runtime.providesSvelteKitRuntime) {
|
|
156
|
+
throw new Error(`Cannot generate schema clients because project-local fimo@${runtime.version} does not provide the ` +
|
|
157
|
+
'fimo/sveltekit export required by this SvelteKit project. ' +
|
|
158
|
+
`Run \`${CONTENT_CLIENT_RUNTIME_UPGRADE_COMMAND}\` in the project, then run \`npx fimo@latest validate\` again. ` +
|
|
159
|
+
'No generated files were changed.');
|
|
160
|
+
}
|
|
161
|
+
if (runtimeImport === 'fimo/next') {
|
|
162
|
+
return 'next';
|
|
163
|
+
}
|
|
164
|
+
return runtimeImport === 'fimo/astro' ? 'astro' : 'sveltekit';
|
|
126
165
|
}
|
|
127
166
|
function templatesForTarget(target, runtime, runtimeImport) {
|
|
128
167
|
if (target === 'next') {
|
|
129
168
|
return [
|
|
130
169
|
{
|
|
131
170
|
suffix: '.types.ts',
|
|
132
|
-
path: templatePath(runtime, 'types
|
|
171
|
+
path: templatePath(runtime, 'types'),
|
|
133
172
|
runtimeImport: 'fimo/next',
|
|
134
173
|
},
|
|
135
174
|
{
|
|
136
175
|
suffix: '.ts',
|
|
137
|
-
path: templatePath(runtime, '
|
|
176
|
+
path: templatePath(runtime, 'nextServer'),
|
|
138
177
|
runtimeImport: 'fimo/next',
|
|
139
178
|
},
|
|
140
179
|
{
|
|
141
180
|
suffix: '.client.ts',
|
|
142
|
-
path: templatePath(runtime, '
|
|
181
|
+
path: templatePath(runtime, 'nextClient'),
|
|
143
182
|
runtimeImport: 'fimo/next/client',
|
|
144
183
|
},
|
|
145
184
|
];
|
|
146
185
|
}
|
|
186
|
+
if (target === 'astro') {
|
|
187
|
+
return [
|
|
188
|
+
{
|
|
189
|
+
suffix: '.types.ts',
|
|
190
|
+
path: templatePath(runtime, 'types'),
|
|
191
|
+
runtimeImport: 'fimo/astro',
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
suffix: '.ts',
|
|
195
|
+
path: templatePath(runtime, 'sharedServer'),
|
|
196
|
+
runtimeImport: 'fimo/astro',
|
|
197
|
+
},
|
|
198
|
+
];
|
|
199
|
+
}
|
|
200
|
+
if (target === 'sveltekit') {
|
|
201
|
+
return [
|
|
202
|
+
{
|
|
203
|
+
suffix: '.types.ts',
|
|
204
|
+
path: templatePath(runtime, 'types'),
|
|
205
|
+
runtimeImport: 'fimo/sveltekit',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
suffix: '.ts',
|
|
209
|
+
path: templatePath(runtime, 'svelteKitContent'),
|
|
210
|
+
runtimeImport: 'fimo/sveltekit',
|
|
211
|
+
},
|
|
212
|
+
];
|
|
213
|
+
}
|
|
147
214
|
return [
|
|
148
215
|
{
|
|
149
216
|
suffix: '.types.ts',
|
|
150
|
-
path: templatePath(runtime, 'types
|
|
217
|
+
path: templatePath(runtime, 'types'),
|
|
151
218
|
runtimeImport,
|
|
152
219
|
},
|
|
153
220
|
{
|
|
154
221
|
suffix: '.ts',
|
|
155
|
-
path: templatePath(runtime, '
|
|
222
|
+
path: templatePath(runtime, 'reactClient'),
|
|
156
223
|
runtimeImport,
|
|
157
224
|
},
|
|
158
225
|
];
|
|
@@ -219,7 +286,7 @@ function renderContentRegistry(schemas) {
|
|
|
219
286
|
const imports = schemas.map(({ pascal }) => `import * as ${pascal} from "./${pascal}";`).join('\n');
|
|
220
287
|
const entries = schemas.map(({ pascal, registryKey }) => ` ${registryKey}: ${pascal},`).join('\n');
|
|
221
288
|
return `${GENERATED_REGISTRY_MARKER}
|
|
222
|
-
//
|
|
289
|
+
// Generated content registry for framework facades and project integrations.
|
|
223
290
|
|
|
224
291
|
${imports}
|
|
225
292
|
|
|
@@ -306,10 +373,10 @@ export function syncSchemas(options) {
|
|
|
306
373
|
const runtime = schemas.length > 0 || generatedFilesOnDisk.length > 0 ? resolveProjectRuntime(cwd) : null;
|
|
307
374
|
const runtimeImport = contentRuntimeImportFor(options.framework);
|
|
308
375
|
const generationTarget = runtime ? resolveSchemaGenerationTarget(runtimeImport, runtime) : null;
|
|
309
|
-
const
|
|
376
|
+
const needsContentRegistry = (generationTarget === 'next' || generationTarget === 'sveltekit') && schemas.length > 0;
|
|
310
377
|
const ownsExistingRegistry = existsSync(registryPath) && readFileSync(registryPath, 'utf-8').startsWith(GENERATED_REGISTRY_MARKER);
|
|
311
|
-
const shouldGenerateRegistry =
|
|
312
|
-
if (
|
|
378
|
+
const shouldGenerateRegistry = needsContentRegistry && (!existsSync(registryPath) || ownsExistingRegistry);
|
|
379
|
+
if (needsContentRegistry && !shouldGenerateRegistry) {
|
|
313
380
|
log(`Kept project-owned schema barrel: ${registryPath}`);
|
|
314
381
|
}
|
|
315
382
|
const templates = generationTarget && runtime ? templatesForTarget(generationTarget, runtime, runtimeImport) : [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fimo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0-staging.1",
|
|
4
4
|
"description": "Fimo CLI - create, deploy, and manage Fimo projects",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fimo": "dist/cli/index.js"
|
|
@@ -26,6 +26,22 @@
|
|
|
26
26
|
"types": "./dist/runtime/content/index.d.ts",
|
|
27
27
|
"import": "./dist/runtime/content/index.js"
|
|
28
28
|
},
|
|
29
|
+
"./astro": {
|
|
30
|
+
"types": "./dist/runtime/astro/server.d.ts",
|
|
31
|
+
"import": "./dist/runtime/astro/server.js"
|
|
32
|
+
},
|
|
33
|
+
"./astro/components": {
|
|
34
|
+
"types": "./assets/astro/components/index.d.ts",
|
|
35
|
+
"import": "./assets/astro/components/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./astro/config": {
|
|
38
|
+
"types": "./dist/build/astro/config.d.ts",
|
|
39
|
+
"import": "./dist/build/astro/config.js"
|
|
40
|
+
},
|
|
41
|
+
"./astro/internal": {
|
|
42
|
+
"types": "./dist/runtime/astro/internal.d.ts",
|
|
43
|
+
"import": "./dist/runtime/astro/internal.js"
|
|
44
|
+
},
|
|
29
45
|
"./next": {
|
|
30
46
|
"types": "./dist/runtime/next/server.d.ts",
|
|
31
47
|
"import": "./dist/runtime/next/server.js"
|
|
@@ -51,6 +67,27 @@
|
|
|
51
67
|
"types": "./dist/runtime/react-router/preset.d.ts",
|
|
52
68
|
"import": "./dist/runtime/react-router/preset.js"
|
|
53
69
|
},
|
|
70
|
+
"./sveltekit": {
|
|
71
|
+
"types": "./dist/runtime/sveltekit/index.d.ts",
|
|
72
|
+
"import": "./dist/runtime/sveltekit/index.js"
|
|
73
|
+
},
|
|
74
|
+
"./sveltekit/components": {
|
|
75
|
+
"types": "./assets/sveltekit/components/index.d.ts",
|
|
76
|
+
"svelte": "./assets/sveltekit/components/index.js",
|
|
77
|
+
"import": "./assets/sveltekit/components/index.js"
|
|
78
|
+
},
|
|
79
|
+
"./sveltekit/config": {
|
|
80
|
+
"types": "./dist/build/sveltekit/config.d.ts",
|
|
81
|
+
"import": "./dist/build/sveltekit/config.js"
|
|
82
|
+
},
|
|
83
|
+
"./sveltekit/internal": {
|
|
84
|
+
"types": "./dist/runtime/sveltekit/internal.d.ts",
|
|
85
|
+
"import": "./dist/runtime/sveltekit/internal.js"
|
|
86
|
+
},
|
|
87
|
+
"./sveltekit/vite": {
|
|
88
|
+
"types": "./dist/build/sveltekit/vite.d.ts",
|
|
89
|
+
"import": "./dist/build/sveltekit/vite.js"
|
|
90
|
+
},
|
|
54
91
|
"./paths": {
|
|
55
92
|
"types": "./dist/runtime/paths/index.d.ts",
|
|
56
93
|
"import": "./dist/runtime/paths/index.js"
|
|
@@ -84,12 +121,17 @@
|
|
|
84
121
|
"publish:dry-run": "npm publish --dry-run",
|
|
85
122
|
"postinstall": "node scripts/postinstall.mjs",
|
|
86
123
|
"test": "vitest run",
|
|
87
|
-
"test:integration:
|
|
124
|
+
"test:integration:astro": "vitest run --config vitest.integration.config.ts test/integration/astro-runtime.test.ts",
|
|
125
|
+
"test:integration:frameworks": "vitest run --config vitest.integration.config.ts",
|
|
126
|
+
"test:integration:next": "vitest run --config vitest.integration.config.ts test/integration/next-runtime.test.ts",
|
|
127
|
+
"test:integration:sveltekit": "vitest run --config vitest.integration.config.ts test/integration/sveltekit-runtime.test.ts",
|
|
88
128
|
"test:watch": "vitest",
|
|
89
129
|
"clean": "rm -rf dist *.tsbuildinfo"
|
|
90
130
|
},
|
|
91
131
|
"dependencies": {
|
|
132
|
+
"@astrojs/vercel": "11.0.4",
|
|
92
133
|
"@rollup/pluginutils": "^5.1.0",
|
|
134
|
+
"@sveltejs/adapter-vercel": "6.3.4",
|
|
93
135
|
"change-case": "^5.4.4",
|
|
94
136
|
"eta": "^3.5.0",
|
|
95
137
|
"oxc-parser": "^0.118.0",
|
|
@@ -127,16 +169,25 @@
|
|
|
127
169
|
"yaml": "2.8.2"
|
|
128
170
|
},
|
|
129
171
|
"peerDependencies": {
|
|
172
|
+
"@sveltejs/kit": "^2.0.0",
|
|
130
173
|
"@tanstack/react-query": "^5.80.6",
|
|
174
|
+
"astro": "^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
131
175
|
"react": "^18.2.0 || ^19.0.0",
|
|
132
176
|
"react-dom": "^18.2.0 || ^19.0.0",
|
|
133
177
|
"react-router": "^7.0.0 || ^8.0.0",
|
|
178
|
+
"svelte": "^5.0.0",
|
|
134
179
|
"vite": "^7.0.0 || ^8.0.0"
|
|
135
180
|
},
|
|
136
181
|
"peerDependenciesMeta": {
|
|
137
182
|
"@tanstack/react-query": {
|
|
138
183
|
"optional": true
|
|
139
184
|
},
|
|
185
|
+
"@sveltejs/kit": {
|
|
186
|
+
"optional": true
|
|
187
|
+
},
|
|
188
|
+
"astro": {
|
|
189
|
+
"optional": true
|
|
190
|
+
},
|
|
140
191
|
"react": {
|
|
141
192
|
"optional": true
|
|
142
193
|
},
|
|
@@ -146,6 +197,9 @@
|
|
|
146
197
|
"react-router": {
|
|
147
198
|
"optional": true
|
|
148
199
|
},
|
|
200
|
+
"svelte": {
|
|
201
|
+
"optional": true
|
|
202
|
+
},
|
|
149
203
|
"vite": {
|
|
150
204
|
"optional": true
|
|
151
205
|
}
|
package/release.json
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Fimo project
|
|
2
|
+
|
|
3
|
+
This SvelteKit application is connected to Fimo for content, editing, environments, and hosting.
|
|
4
|
+
|
|
5
|
+
## Load Fimo guidance before changing Fimo code
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm exec fimo skills get fimo-code
|
|
9
|
+
pnpm exec fimo skills get fimo-code --ref frameworks/sveltekit
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Load only the additional task reference you need. The SvelteKit reference owns the framework API and setup rules.
|
|
13
|
+
|
|
14
|
+
The scaffolded homepage is disposable. Replace it when building the requested site. The application owns routes, locale resolution, links, HTML language and direction, and SEO.
|
|
15
|
+
|
|
16
|
+
Never edit `.fimo/project.json`; it links this directory to its Fimo project. Keep secrets in Fimo, not committed environment files. Offer `fimo deploy` only when the developer wants a hosted preview or publication.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fimo-template",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite dev",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview",
|
|
10
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
11
|
+
"prepare": "svelte-kit sync"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"fimo": "latest"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@sveltejs/kit": "^2.70.2",
|
|
18
|
+
"@sveltejs/vite-plugin-svelte": "^7.2.0",
|
|
19
|
+
"@types/node": "^24.12.0",
|
|
20
|
+
"svelte": "^5.56.8",
|
|
21
|
+
"svelte-check": "^4.7.6",
|
|
22
|
+
"typescript": "^5.9.3",
|
|
23
|
+
"vite": "^8.2.0"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=22.22.0"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width" />
|
|
6
|
+
%sveltekit.head%
|
|
7
|
+
</head>
|
|
8
|
+
<body data-sveltekit-preload-data="hover">
|
|
9
|
+
<div style="display: contents">%sveltekit.body%</div>
|
|
10
|
+
</body>
|
|
11
|
+
</html>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { FimoProvider } from 'fimo/sveltekit/components';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
|
|
5
|
+
import type { LayoutData } from './$types';
|
|
6
|
+
|
|
7
|
+
let { data, children }: { data: LayoutData; children: Snippet } = $props();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<FimoProvider labels={data.labels}>
|
|
11
|
+
{@render children()}
|
|
12
|
+
</FimoProvider>
|