@decocms/eitri 7.20.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 +123 -0
- package/configs/tsconfig.json +17 -0
- package/package.json +38 -0
- package/src/cli.ts +77 -0
- package/src/index.ts +49 -0
- package/src/init.test.ts +71 -0
- package/src/init.ts +69 -0
- package/tsconfig.json +7 -0
- package/types/eitri-luminus.d.ts +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# `@decocms/eitri`
|
|
2
|
+
|
|
3
|
+
Deco binding for the **Eitri** mobile stack. Unlike `@decocms/nextjs` /
|
|
4
|
+
`@decocms/tanstack`, this package does **not** render anything — Eitri renders
|
|
5
|
+
sections natively on its own mobile runtime. `@decocms/eitri` only *produces a
|
|
6
|
+
well-filled `.deco`* so Studio can author content against your Eitri sections:
|
|
7
|
+
|
|
8
|
+
- a **self-contained** `.deco/meta.gen.json` (section schemas **plus** the
|
|
9
|
+
framework block types — Page, matchers, `Resolvable`, the section picker —
|
|
10
|
+
baked in, so an FS-based Studio reads it verbatim with no runtime), and
|
|
11
|
+
- the bundled `.deco/blocks.gen.json` decofile snapshot the Eitri runtime
|
|
12
|
+
consumes.
|
|
13
|
+
|
|
14
|
+
It is a thin, Eitri-flavored wrapper over `@decocms/blocks-cli`'s `generate`
|
|
15
|
+
orchestrator (`--platform eitri`). See
|
|
16
|
+
[`docs/eitri-stack-design.md`](../../docs/eitri-stack-design.md) for the full
|
|
17
|
+
design.
|
|
18
|
+
|
|
19
|
+
## What Eitri owns vs. what deco owns
|
|
20
|
+
|
|
21
|
+
| | Owner |
|
|
22
|
+
|---|---|
|
|
23
|
+
| Section `Props` → JSON Schema, decofile snapshot (`.deco`) | **`@decocms/eitri`** (this package) |
|
|
24
|
+
| Authoring content (forms, page composition) | Studio (reads `.deco`) |
|
|
25
|
+
| Fetching the decofile on-device + rendering sections | **Eitri platform / your app** |
|
|
26
|
+
|
|
27
|
+
There is intentionally **no runtime SDK** here.
|
|
28
|
+
|
|
29
|
+
## Sections
|
|
30
|
+
|
|
31
|
+
An Eitri section is exactly a deco section: a default-exported component in
|
|
32
|
+
`src/sections/**` with an exported `Props` interface documented with JSDoc.
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
// src/sections/Banners/Hero.tsx
|
|
36
|
+
import { Image, View } from "eitri-luminus";
|
|
37
|
+
|
|
38
|
+
export interface Props {
|
|
39
|
+
/** @title Hero image. */
|
|
40
|
+
image: string;
|
|
41
|
+
/** @title Alt text. */
|
|
42
|
+
alt?: string;
|
|
43
|
+
/** @title Publish date. @format datetime */
|
|
44
|
+
datetime?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default function HeroBanner({ image, alt }: Props) {
|
|
48
|
+
return <View><Image src={image} alt={alt} /></View>;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`@title`, `@format` (e.g. `textarea`, `datetime` → normalized to `date-time`),
|
|
53
|
+
and the other JSDoc widget tags drive the Studio form. Sections may be `.tsx`,
|
|
54
|
+
`.ts`, `.jsx`, or `.js`.
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# in your Eitri app (as a dev tool)
|
|
60
|
+
npm i -D @decocms/eitri
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Setup
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx deco-eitri init
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This scaffolds (never overwriting existing files):
|
|
70
|
+
|
|
71
|
+
- `tsconfig.json` extending `@decocms/eitri/tsconfig` — **required**;
|
|
72
|
+
`generate-schema` needs a tsconfig to parse your `Props` types.
|
|
73
|
+
- `src/eitri-env.d.ts` — ambient shims for `eitri-luminus` / `eitri-bifrost` so
|
|
74
|
+
your editor and `tsc` don't flag those imports. Purely ergonomic; generation
|
|
75
|
+
works without it. Delete it if you install the real `eitri-luminus` types.
|
|
76
|
+
|
|
77
|
+
If you prefer to wire it by hand, your `tsconfig.json` need only be:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{ "extends": "@decocms/eitri/tsconfig", "include": ["src"] }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Generate
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# from the app root
|
|
87
|
+
npx deco-eitri generate
|
|
88
|
+
|
|
89
|
+
# or, targeting a sub-app in a monorepo without cd:
|
|
90
|
+
npx deco-eitri generate --root eitri-shopping-monte-carlo-shared
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Add it as a script:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{ "scripts": { "deco:generate": "deco-eitri generate" } }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Output under `.deco/`:
|
|
100
|
+
|
|
101
|
+
- `meta.gen.json` — self-contained schema (`framework: "eitri"`).
|
|
102
|
+
- `blocks.gen.json` — decofile snapshot (starts as `{}` for a fresh app; Studio
|
|
103
|
+
fills it as content is authored).
|
|
104
|
+
- `generate.digests.json` — the incremental-generation cache (commit it).
|
|
105
|
+
|
|
106
|
+
The React-runtime artifacts (`sections.gen.ts`, `blocksManifest.gen.ts`,
|
|
107
|
+
`loaders.gen.ts`, `invoke.gen.ts`) are intentionally **not** produced — Eitri
|
|
108
|
+
doesn't use them.
|
|
109
|
+
|
|
110
|
+
## Programmatic API
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { generateEitri } from "@decocms/eitri";
|
|
114
|
+
|
|
115
|
+
const code = await generateEitri({ root: "path/to/app", force: true });
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Flags
|
|
119
|
+
|
|
120
|
+
`deco-eitri generate` forwards every `@decocms/blocks-cli` `generate` flag
|
|
121
|
+
(`--root`, `--force`, `--dry-run`, `--sections-dir`, `--namespace`, `--site`,
|
|
122
|
+
…). Run `npx deco-eitri generate --help` for the full list. `--platform eitri`
|
|
123
|
+
is always applied.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"//": "Base tsconfig for Eitri apps that generate a .deco with @decocms/eitri. Extend it from your app root: { \"extends\": \"@decocms/eitri/tsconfig\", \"include\": [\"src\"] }. generate-schema (ts-morph) reads this to parse section Props interfaces. allowJs + checkJs:false because Eitri apps are mostly plain JS with .tsx sections; skipLibCheck because eitri-luminus/eitri-bifrost types are shimmed, not installed.",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "ESNext",
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "Bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"checkJs": false,
|
|
10
|
+
"strict": false,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"resolveJsonModule": true
|
|
16
|
+
}
|
|
17
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@decocms/eitri",
|
|
3
|
+
"version": "7.20.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Deco binding for the Eitri mobile stack: produces a well-filled .deco (self-contained schema + decofile snapshot) so Studio can author content. No rendering — Eitri renders natively.",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/decocms/blocks.git",
|
|
9
|
+
"directory": "packages/eitri"
|
|
10
|
+
},
|
|
11
|
+
"main": "./src/index.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./src/index.ts",
|
|
14
|
+
"./tsconfig": "./configs/tsconfig.json",
|
|
15
|
+
"./types": "./types/eitri-luminus.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"deco-eitri": "./src/cli.ts"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"test": "vitest run --root ../.. packages/eitri/",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"lint:unused": "knip"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@decocms/blocks-cli": "7.20.0",
|
|
28
|
+
"tsx": "^4.22.5"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"typescript": "^5.9.0",
|
|
32
|
+
"knip": "^5.86.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"registry": "https://registry.npmjs.org",
|
|
36
|
+
"access": "public"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* `deco-eitri` — CLI for producing a Studio-ready `.deco` from an Eitri app.
|
|
4
|
+
*
|
|
5
|
+
* deco-eitri init [--root <dir>]
|
|
6
|
+
* Scaffold tsconfig.json (+ src/eitri-env.d.ts shim). Idempotent.
|
|
7
|
+
*
|
|
8
|
+
* deco-eitri generate [--root <dir>] [--force] [any generate flags]
|
|
9
|
+
* Run the blocks-cli orchestrator with --platform eitri: emits a
|
|
10
|
+
* self-contained .deco/meta.gen.json + the .deco/blocks.gen.json
|
|
11
|
+
* snapshot, skipping the React-runtime generators.
|
|
12
|
+
*
|
|
13
|
+
* `generate` forwards every flag through to @decocms/blocks-cli's `generate`
|
|
14
|
+
* (see `deco-eitri generate --help`), only ensuring --platform eitri is set.
|
|
15
|
+
*/
|
|
16
|
+
import { runGenerate } from "@decocms/blocks-cli/generate";
|
|
17
|
+
import { runEitriInit } from "./init";
|
|
18
|
+
|
|
19
|
+
const USAGE = `\
|
|
20
|
+
deco-eitri — produce a Studio-ready .deco for an Eitri app
|
|
21
|
+
|
|
22
|
+
Usage:
|
|
23
|
+
deco-eitri init [--root <dir>]
|
|
24
|
+
Scaffold tsconfig.json (extends @decocms/eitri/tsconfig) and a
|
|
25
|
+
src/eitri-env.d.ts shim. Never overwrites existing files.
|
|
26
|
+
|
|
27
|
+
deco-eitri generate [--root <dir>] [--force] [...generate flags]
|
|
28
|
+
Generate .deco (self-contained meta.gen.json + blocks.gen.json snapshot)
|
|
29
|
+
with --platform eitri. All @decocms/blocks-cli generate flags are
|
|
30
|
+
forwarded; run \`deco-eitri generate --help\` for the full list.
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
/** Pull `--root <dir>` out of an argv slice (used by init). */
|
|
34
|
+
function valueFlag(argv: string[], flag: string): string | undefined {
|
|
35
|
+
const i = argv.indexOf(flag);
|
|
36
|
+
return i !== -1 ? argv[i + 1] : undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function main(): Promise<number> {
|
|
40
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
41
|
+
|
|
42
|
+
if (!command || command === "--help" || command === "-h") {
|
|
43
|
+
console.log(USAGE);
|
|
44
|
+
return command ? 0 : 1;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (command === "init") {
|
|
48
|
+
const { created, skipped } = runEitriInit({ root: valueFlag(rest, "--root") });
|
|
49
|
+
for (const f of created) console.log(`[deco-eitri] created ${f}`);
|
|
50
|
+
for (const f of skipped) console.log(`[deco-eitri] skipped ${f} (already exists)`);
|
|
51
|
+
console.log(
|
|
52
|
+
created.length
|
|
53
|
+
? "[deco-eitri] init done — run `deco-eitri generate` to produce .deco"
|
|
54
|
+
: "[deco-eitri] init: nothing to do (already set up)",
|
|
55
|
+
);
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (command === "generate") {
|
|
60
|
+
// Forward everything to the orchestrator, guaranteeing --platform eitri.
|
|
61
|
+
const args = rest.includes("--platform") ? rest : ["--platform", "eitri", ...rest];
|
|
62
|
+
return runGenerate(args);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.error(`[deco-eitri] unknown command "${command}"\n`);
|
|
66
|
+
console.error(USAGE);
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
main()
|
|
71
|
+
.then((code) => {
|
|
72
|
+
process.exitCode = code;
|
|
73
|
+
})
|
|
74
|
+
.catch((err) => {
|
|
75
|
+
console.error(err);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @decocms/eitri — programmatic entry.
|
|
3
|
+
*
|
|
4
|
+
* Deco does not render Eitri apps (Eitri renders natively on its mobile
|
|
5
|
+
* runtime); this package only *produces* a well-filled `.deco` so Studio can
|
|
6
|
+
* author content. It is a thin, Eitri-flavored wrapper over
|
|
7
|
+
* `@decocms/blocks-cli`'s `generate` orchestrator: `--platform eitri` selects
|
|
8
|
+
* the schema + blocks generators only and emits a SELF-CONTAINED
|
|
9
|
+
* `meta.gen.json` (Page, matchers, Resolvable baked in via composeMeta), plus
|
|
10
|
+
* the bundled `blocks.gen.json` snapshot the Eitri runtime consumes.
|
|
11
|
+
*
|
|
12
|
+
* The CLI (`deco-eitri`) is the usual entry; this function is for scripting.
|
|
13
|
+
*/
|
|
14
|
+
import { runGenerate } from "@decocms/blocks-cli/generate";
|
|
15
|
+
|
|
16
|
+
export interface GenerateEitriOptions {
|
|
17
|
+
/** App folder to generate for (input dirs + `.deco/` resolve against it). */
|
|
18
|
+
root?: string;
|
|
19
|
+
/** Site name written into the schema (default: blocks-cli's default). */
|
|
20
|
+
site?: string;
|
|
21
|
+
/** Section namespace (default: "site"). */
|
|
22
|
+
namespace?: string;
|
|
23
|
+
/** Ignore the incremental cache and regenerate. */
|
|
24
|
+
force?: boolean;
|
|
25
|
+
/** Extra raw flags forwarded verbatim to the orchestrator. */
|
|
26
|
+
extraArgs?: string[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Build the orchestrator argv for an Eitri generation run. */
|
|
30
|
+
export function eitriGenerateArgs(opts: GenerateEitriOptions = {}): string[] {
|
|
31
|
+
const args = ["--platform", "eitri"];
|
|
32
|
+
if (opts.root) args.push("--root", opts.root);
|
|
33
|
+
if (opts.site) args.push("--site", opts.site);
|
|
34
|
+
if (opts.namespace) args.push("--namespace", opts.namespace);
|
|
35
|
+
if (opts.force) args.push("--force");
|
|
36
|
+
if (opts.extraArgs?.length) args.push(...opts.extraArgs);
|
|
37
|
+
return args;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Generate the `.deco` for an Eitri app. Resolves to the process exit code
|
|
42
|
+
* (0 = success), mirroring the CLI.
|
|
43
|
+
*/
|
|
44
|
+
export function generateEitri(opts: GenerateEitriOptions = {}): Promise<number> {
|
|
45
|
+
return runGenerate(eitriGenerateArgs(opts));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { runEitriInit } from "./init";
|
|
49
|
+
export type { EitriInitOptions, EitriInitResult } from "./init";
|
package/src/init.test.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
5
|
+
import { eitriGenerateArgs } from "./index";
|
|
6
|
+
import { runEitriInit } from "./init";
|
|
7
|
+
|
|
8
|
+
describe("eitriGenerateArgs", () => {
|
|
9
|
+
it("always applies --platform eitri", () => {
|
|
10
|
+
expect(eitriGenerateArgs()).toEqual(["--platform", "eitri"]);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("maps options onto orchestrator flags", () => {
|
|
14
|
+
expect(
|
|
15
|
+
eitriGenerateArgs({ root: "apps/foo", site: "monte", namespace: "site", force: true }),
|
|
16
|
+
).toEqual([
|
|
17
|
+
"--platform",
|
|
18
|
+
"eitri",
|
|
19
|
+
"--root",
|
|
20
|
+
"apps/foo",
|
|
21
|
+
"--site",
|
|
22
|
+
"monte",
|
|
23
|
+
"--namespace",
|
|
24
|
+
"site",
|
|
25
|
+
"--force",
|
|
26
|
+
]);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("appends extra raw flags verbatim", () => {
|
|
30
|
+
expect(eitriGenerateArgs({ extraArgs: ["--dry-run"] })).toEqual([
|
|
31
|
+
"--platform",
|
|
32
|
+
"eitri",
|
|
33
|
+
"--dry-run",
|
|
34
|
+
]);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe("runEitriInit", () => {
|
|
39
|
+
let dir: string;
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
dir = fs.mkdtempSync(path.join(os.tmpdir(), "eitri-init-"));
|
|
42
|
+
});
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("scaffolds tsconfig.json + src/eitri-env.d.ts on a fresh app", () => {
|
|
48
|
+
const res = runEitriInit({ root: dir });
|
|
49
|
+
expect(res.created).toEqual(["tsconfig.json", path.join("src", "eitri-env.d.ts")]);
|
|
50
|
+
expect(res.skipped).toEqual([]);
|
|
51
|
+
|
|
52
|
+
const tsconfig = JSON.parse(fs.readFileSync(path.join(dir, "tsconfig.json"), "utf-8"));
|
|
53
|
+
expect(tsconfig.extends).toBe("@decocms/eitri/tsconfig");
|
|
54
|
+
expect(tsconfig.include).toEqual(["src"]);
|
|
55
|
+
|
|
56
|
+
const shim = fs.readFileSync(path.join(dir, "src", "eitri-env.d.ts"), "utf-8");
|
|
57
|
+
expect(shim).toContain('declare module "eitri-luminus"');
|
|
58
|
+
expect(shim).toContain('declare module "eitri-bifrost"');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("is idempotent — never overwrites existing files", () => {
|
|
62
|
+
fs.writeFileSync(path.join(dir, "tsconfig.json"), '{"custom":true}\n');
|
|
63
|
+
const res = runEitriInit({ root: dir });
|
|
64
|
+
expect(res.skipped).toContain("tsconfig.json");
|
|
65
|
+
expect(res.created).toEqual([path.join("src", "eitri-env.d.ts")]);
|
|
66
|
+
// The pre-existing tsconfig is left untouched.
|
|
67
|
+
expect(JSON.parse(fs.readFileSync(path.join(dir, "tsconfig.json"), "utf-8"))).toEqual({
|
|
68
|
+
custom: true,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
package/src/init.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `deco-eitri init` — scaffold the two files an Eitri app needs to generate a
|
|
3
|
+
* `.deco`, without touching anything that already exists (idempotent):
|
|
4
|
+
*
|
|
5
|
+
* 1. `tsconfig.json` extending `@decocms/eitri/tsconfig` — required by
|
|
6
|
+
* generate-schema (ts-morph needs a tsconfig to build the program).
|
|
7
|
+
* 2. `src/eitri-env.d.ts` — a copy of the eitri-luminus/bifrost ambient
|
|
8
|
+
* shims, dropped inside `src/` so the app's `include: ["src"]` picks it up
|
|
9
|
+
* with no node_modules path gymnastics. Purely editor/tsc ergonomics —
|
|
10
|
+
* generation works without it.
|
|
11
|
+
*
|
|
12
|
+
* Never overwrites an existing file, so it's safe to re-run.
|
|
13
|
+
*/
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
|
|
18
|
+
export interface EitriInitOptions {
|
|
19
|
+
/** App root to scaffold into. Defaults to process.cwd(). */
|
|
20
|
+
root?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface EitriInitResult {
|
|
24
|
+
/** Files created this run (relative to root). */
|
|
25
|
+
created: string[];
|
|
26
|
+
/** Files that already existed and were left untouched (relative to root). */
|
|
27
|
+
skipped: string[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const APP_TSCONFIG = `${JSON.stringify(
|
|
31
|
+
{
|
|
32
|
+
extends: "@decocms/eitri/tsconfig",
|
|
33
|
+
include: ["src"],
|
|
34
|
+
},
|
|
35
|
+
null,
|
|
36
|
+
2,
|
|
37
|
+
)}\n`;
|
|
38
|
+
|
|
39
|
+
/** Absolute path to the packaged ambient shim (../types/eitri-luminus.d.ts). */
|
|
40
|
+
function packagedShimPath(): string {
|
|
41
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
42
|
+
return path.resolve(here, "..", "types", "eitri-luminus.d.ts");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function runEitriInit(opts: EitriInitOptions = {}): EitriInitResult {
|
|
46
|
+
const root = path.resolve(opts.root ?? process.cwd());
|
|
47
|
+
const created: string[] = [];
|
|
48
|
+
const skipped: string[] = [];
|
|
49
|
+
|
|
50
|
+
const write = (rel: string, contents: string) => {
|
|
51
|
+
const abs = path.join(root, rel);
|
|
52
|
+
if (fs.existsSync(abs)) {
|
|
53
|
+
skipped.push(rel);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
57
|
+
fs.writeFileSync(abs, contents);
|
|
58
|
+
created.push(rel);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
write("tsconfig.json", APP_TSCONFIG);
|
|
62
|
+
|
|
63
|
+
// Copy the shim content (not a reference) so the app file is self-contained
|
|
64
|
+
// and immune to node_modules path resolution quirks.
|
|
65
|
+
const shim = fs.readFileSync(packagedShimPath(), "utf-8");
|
|
66
|
+
write(path.join("src", "eitri-env.d.ts"), shim);
|
|
67
|
+
|
|
68
|
+
return { created, skipped };
|
|
69
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient shims for the Eitri runtime libraries.
|
|
3
|
+
*
|
|
4
|
+
* Eitri apps import UI primitives from `eitri-luminus` and the native SDK from
|
|
5
|
+
* `eitri-bifrost`/`eitri-commons`, but those packages are resolved by the
|
|
6
|
+
* external `eitri-cli` toolchain, not installed in the app's node_modules. When
|
|
7
|
+
* generating a `.deco` we only need the section `Props` interfaces (which use
|
|
8
|
+
* plain primitives), so these shims exist purely to keep an author's editor and
|
|
9
|
+
* `tsc` from erroring on the imports — they are intentionally loose (`any`).
|
|
10
|
+
*
|
|
11
|
+
* `deco-eitri init` copies this file into your app's `src/` (as
|
|
12
|
+
* `eitri-env.d.ts`) so it is picked up by `include: ["src"]` with no path
|
|
13
|
+
* gymnastics. If you install the real `eitri-luminus` types, delete the copy.
|
|
14
|
+
*/
|
|
15
|
+
declare module "eitri-luminus" {
|
|
16
|
+
// Every luminus component (View, Text, Image, Page, Button, ...) is exposed
|
|
17
|
+
// as a permissive component type. Named + default imports both resolve.
|
|
18
|
+
const luminus: Record<string, any>;
|
|
19
|
+
export = luminus;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare module "eitri-bifrost" {
|
|
23
|
+
const Eitri: any;
|
|
24
|
+
export default Eitri;
|
|
25
|
+
export = Eitri;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare module "eitri-commons" {
|
|
29
|
+
const commons: any;
|
|
30
|
+
export = commons;
|
|
31
|
+
}
|