aem-eds-kit 0.4.1 → 0.4.4
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/CHANGELOG.md +35 -1
- package/README.md +8 -0
- package/dist/bin/eds.js +179 -80
- package/dist/bin/eds.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,37 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.4] - 2026-10-07
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **`eds scaffold ci`** - generate a GitHub Actions workflow (`.github/workflows/eds.yml`)
|
|
13
|
+
that runs the project's own `lint`/`build` (if present) plus the eds audits
|
|
14
|
+
(`doctor`, `audit loading`, `audit security`) as a PR gatekeeper. Also offered
|
|
15
|
+
in the interactive `eds scaffold` picker. Deterministic, no agent.
|
|
16
|
+
|
|
17
|
+
## [0.4.3] - 2026-10-06
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- CLI: a blinking accent caret now trails the animated logo line at the
|
|
21
|
+
interactive entry points, matching the landing terminal.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- Landing hero headline no longer wraps "Design frame in." onto three lines
|
|
25
|
+
(tightened the clamp + tracking so each clause stays on one line).
|
|
26
|
+
|
|
27
|
+
## [0.4.2] - 2026-10-06
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- README banner now uses an absolute `raw.githubusercontent.com` URL so it
|
|
31
|
+
renders everywhere - npmjs rewrites relative links, but the GitHub Packages
|
|
32
|
+
page does not, so the relative path showed a broken image there.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
- CI: the GitHub Packages publish step tolerates an already-published version
|
|
36
|
+
(409) instead of failing the whole workflow on re-runs.
|
|
37
|
+
- Added a dependency-free `.githooks/pre-commit` that auto-bumps the patch
|
|
38
|
+
version whenever `src/` changes are committed (wired via `core.hooksPath`).
|
|
39
|
+
|
|
9
40
|
## [0.4.1] - 2026-10-06
|
|
10
41
|
|
|
11
42
|
### Changed
|
|
@@ -101,7 +132,10 @@ harness, gradient ANSI logo. Not published (superseded by 0.3.0).
|
|
|
101
132
|
Initial CLI scaffold: `block create`, `block from-figma`, `block list`,
|
|
102
133
|
`figma setup`, `doctor`, `preview`, `publish`. Not published.
|
|
103
134
|
|
|
104
|
-
[Unreleased]: https://github.com/piotrgodycki/aem-eds-kit/compare/v0.4.
|
|
135
|
+
[Unreleased]: https://github.com/piotrgodycki/aem-eds-kit/compare/v0.4.4...HEAD
|
|
136
|
+
[0.4.4]: https://github.com/piotrgodycki/aem-eds-kit/releases/tag/v0.4.4
|
|
137
|
+
[0.4.3]: https://github.com/piotrgodycki/aem-eds-kit/releases/tag/v0.4.3
|
|
138
|
+
[0.4.2]: https://github.com/piotrgodycki/aem-eds-kit/releases/tag/v0.4.2
|
|
105
139
|
[0.4.1]: https://github.com/piotrgodycki/aem-eds-kit/releases/tag/v0.4.1
|
|
106
140
|
[0.4.0]: https://github.com/piotrgodycki/aem-eds-kit/releases/tag/v0.4.0
|
|
107
141
|
[0.3.0]: https://github.com/piotrgodycki/aem-eds-kit/releases/tag/v0.3.0
|
package/README.md
CHANGED
|
@@ -136,6 +136,14 @@ eds scaffold ue
|
|
|
136
136
|
eds scaffold blocks # all, or: eds scaffold blocks hero cards
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
+
### `eds scaffold ci`
|
|
140
|
+
|
|
141
|
+
Generate a GitHub Actions workflow (`.github/workflows/eds.yml`) that gatekeeps every PR and push to `main`: it installs deps, runs the project's own `lint`/`build` (if defined), then the eds audits - `doctor`, `audit loading`, `audit security` - which exit non-zero on problems. No agent, deterministic. Also offered in the interactive `eds scaffold` picker.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
eds scaffold ci
|
|
145
|
+
```
|
|
146
|
+
|
|
139
147
|
### `eds integrate [type]`
|
|
140
148
|
|
|
141
149
|
Add a third-party service to `scripts/delayed.js` (the EDS-correct place - delayed phase, after LCP, zero CWV impact). Chat widgets use the facade pattern.
|
package/dist/bin/eds.js
CHANGED
|
@@ -247,11 +247,16 @@ var init_logger = __esm({
|
|
|
247
247
|
${logoArt()}
|
|
248
248
|
|
|
249
249
|
`);
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
250
|
+
const caret = (on) => on ? brand.accent("\u258C") : " ";
|
|
251
|
+
const sweep = 14;
|
|
252
|
+
for (let step = 0; step < sweep; step++) {
|
|
253
|
+
out.write(`\r\x1B[K ${brandLine(dotsFrame(step), tagline)} ${caret(step % 2 === 0)}`);
|
|
253
254
|
await new Promise((r) => setTimeout(r, 70));
|
|
254
255
|
}
|
|
256
|
+
for (let b = 0; b < 4; b++) {
|
|
257
|
+
out.write(`\r\x1B[K ${brandLine(dotsStatic(), tagline)} ${caret(b % 2 === 0)}`);
|
|
258
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
259
|
+
}
|
|
255
260
|
out.write(`\r\x1B[K ${brandLine(dotsStatic(), tagline)}
|
|
256
261
|
`);
|
|
257
262
|
},
|
|
@@ -2277,6 +2282,70 @@ export default function decorate(block) {
|
|
|
2277
2282
|
}
|
|
2278
2283
|
});
|
|
2279
2284
|
|
|
2285
|
+
// src/lib/scaffold/ci.ts
|
|
2286
|
+
import { existsSync as existsSync10 } from "fs";
|
|
2287
|
+
import { mkdir as mkdir3, writeFile as writeFile4 } from "fs/promises";
|
|
2288
|
+
import path12 from "path";
|
|
2289
|
+
async function writeCiWorkflow(projectRoot) {
|
|
2290
|
+
const file = path12.join(projectRoot, ".github", "workflows", "eds.yml");
|
|
2291
|
+
if (existsSync10(file)) return { path: CI_WORKFLOW_PATH, created: false };
|
|
2292
|
+
await mkdir3(path12.dirname(file), { recursive: true });
|
|
2293
|
+
await writeFile4(file, CI_WORKFLOW);
|
|
2294
|
+
return { path: CI_WORKFLOW_PATH, created: true };
|
|
2295
|
+
}
|
|
2296
|
+
var CI_WORKFLOW_PATH, CI_WORKFLOW;
|
|
2297
|
+
var init_ci = __esm({
|
|
2298
|
+
"src/lib/scaffold/ci.ts"() {
|
|
2299
|
+
"use strict";
|
|
2300
|
+
init_esm_shims();
|
|
2301
|
+
CI_WORKFLOW_PATH = ".github/workflows/eds.yml";
|
|
2302
|
+
CI_WORKFLOW = `name: EDS checks
|
|
2303
|
+
|
|
2304
|
+
# Generated by aem-eds-kit (\`eds scaffold ci\`). Runs the project's own
|
|
2305
|
+
# lint/build plus the eds audits as a gatekeeper on every PR and push to main.
|
|
2306
|
+
on:
|
|
2307
|
+
pull_request:
|
|
2308
|
+
push:
|
|
2309
|
+
branches: [main]
|
|
2310
|
+
|
|
2311
|
+
jobs:
|
|
2312
|
+
checks:
|
|
2313
|
+
runs-on: ubuntu-latest
|
|
2314
|
+
steps:
|
|
2315
|
+
- uses: actions/checkout@v4
|
|
2316
|
+
- uses: actions/setup-node@v4
|
|
2317
|
+
with:
|
|
2318
|
+
node-version: 20
|
|
2319
|
+
|
|
2320
|
+
# Install project dependencies when the repo has them.
|
|
2321
|
+
- name: Install dependencies
|
|
2322
|
+
run: |
|
|
2323
|
+
if [ -f package-lock.json ]; then
|
|
2324
|
+
npm ci
|
|
2325
|
+
elif [ -f package.json ]; then
|
|
2326
|
+
npm install
|
|
2327
|
+
fi
|
|
2328
|
+
|
|
2329
|
+
# The project's own scripts, if defined (skipped otherwise).
|
|
2330
|
+
- name: Lint
|
|
2331
|
+
if: hashFiles('package.json') != ''
|
|
2332
|
+
run: npm run lint --if-present
|
|
2333
|
+
- name: Build
|
|
2334
|
+
if: hashFiles('package.json') != ''
|
|
2335
|
+
run: npm run build --if-present
|
|
2336
|
+
|
|
2337
|
+
# aem-eds-kit audits - run via npx, no install needed. Each exits
|
|
2338
|
+
# non-zero on failures, so a bad PR fails the check.
|
|
2339
|
+
- name: Project health (doctor)
|
|
2340
|
+
run: npx --yes aem-eds-kit@latest doctor
|
|
2341
|
+
- name: Loading & LCP budget
|
|
2342
|
+
run: npx --yes aem-eds-kit@latest audit loading
|
|
2343
|
+
- name: Security & exploit scan
|
|
2344
|
+
run: npx --yes aem-eds-kit@latest audit security
|
|
2345
|
+
`;
|
|
2346
|
+
}
|
|
2347
|
+
});
|
|
2348
|
+
|
|
2280
2349
|
// src/lib/scaffold/ue.ts
|
|
2281
2350
|
function fieldReferenceFields() {
|
|
2282
2351
|
return [
|
|
@@ -2538,14 +2607,15 @@ export default function decorate(block) {
|
|
|
2538
2607
|
var scaffold_exports = {};
|
|
2539
2608
|
__export(scaffold_exports, {
|
|
2540
2609
|
scaffoldBlocks: () => scaffoldBlocks,
|
|
2610
|
+
scaffoldCi: () => scaffoldCi,
|
|
2541
2611
|
scaffoldInteractive: () => scaffoldInteractive,
|
|
2542
2612
|
scaffoldUe: () => scaffoldUe
|
|
2543
2613
|
});
|
|
2544
|
-
import { existsSync as
|
|
2545
|
-
import { mkdir as
|
|
2546
|
-
import
|
|
2614
|
+
import { existsSync as existsSync11 } from "fs";
|
|
2615
|
+
import { mkdir as mkdir4, readFile as readFile8, writeFile as writeFile5 } from "fs/promises";
|
|
2616
|
+
import path13 from "path";
|
|
2547
2617
|
async function readJson(file) {
|
|
2548
|
-
if (!
|
|
2618
|
+
if (!existsSync11(file)) return null;
|
|
2549
2619
|
try {
|
|
2550
2620
|
return JSON.parse(await readFile8(file, "utf-8"));
|
|
2551
2621
|
} catch {
|
|
@@ -2553,7 +2623,7 @@ async function readJson(file) {
|
|
|
2553
2623
|
}
|
|
2554
2624
|
}
|
|
2555
2625
|
async function writeJson(file, data) {
|
|
2556
|
-
await
|
|
2626
|
+
await writeFile5(file, `${JSON.stringify(data, null, 2)}
|
|
2557
2627
|
`);
|
|
2558
2628
|
}
|
|
2559
2629
|
async function scaffoldUe() {
|
|
@@ -2565,15 +2635,15 @@ async function scaffoldUe() {
|
|
|
2565
2635
|
}
|
|
2566
2636
|
logger.logoOnce(logo("Scaffold - Universal Editor"));
|
|
2567
2637
|
const created = [];
|
|
2568
|
-
const blockDir =
|
|
2569
|
-
await
|
|
2570
|
-
await
|
|
2571
|
-
await
|
|
2572
|
-
await
|
|
2638
|
+
const blockDir = path13.join(projectRoot, "blocks", "field-reference");
|
|
2639
|
+
await mkdir4(blockDir, { recursive: true });
|
|
2640
|
+
await writeFile5(path13.join(blockDir, "field-reference.js"), FIELD_REFERENCE_JS);
|
|
2641
|
+
await writeFile5(path13.join(blockDir, "field-reference.css"), FIELD_REFERENCE_CSS);
|
|
2642
|
+
await writeFile5(path13.join(blockDir, "_field-reference.json"), fieldReferenceModelFile());
|
|
2573
2643
|
created.push("blocks/field-reference/ (all 17 fields + multifield)");
|
|
2574
|
-
const defFile =
|
|
2575
|
-
const modelsFile =
|
|
2576
|
-
const filtersFile =
|
|
2644
|
+
const defFile = path13.join(projectRoot, "component-definition.json");
|
|
2645
|
+
const modelsFile = path13.join(projectRoot, "component-models.json");
|
|
2646
|
+
const filtersFile = path13.join(projectRoot, "component-filters.json");
|
|
2577
2647
|
const blockDefs = [
|
|
2578
2648
|
{
|
|
2579
2649
|
title: "Field Reference",
|
|
@@ -2636,18 +2706,18 @@ async function scaffoldBlocks(names) {
|
|
|
2636
2706
|
const createdIds = [];
|
|
2637
2707
|
const skipped = [];
|
|
2638
2708
|
for (const b of selected) {
|
|
2639
|
-
const dir =
|
|
2640
|
-
if (
|
|
2709
|
+
const dir = path13.join(projectRoot, "blocks", b.id);
|
|
2710
|
+
if (existsSync11(dir)) {
|
|
2641
2711
|
skipped.push(b.id);
|
|
2642
2712
|
continue;
|
|
2643
2713
|
}
|
|
2644
|
-
await
|
|
2645
|
-
await
|
|
2646
|
-
await
|
|
2647
|
-
await
|
|
2714
|
+
await mkdir4(dir, { recursive: true });
|
|
2715
|
+
await writeFile5(path13.join(dir, `${b.id}.js`), b.js);
|
|
2716
|
+
await writeFile5(path13.join(dir, `${b.id}.css`), b.css);
|
|
2717
|
+
await writeFile5(path13.join(dir, `_${b.id}.json`), b.model);
|
|
2648
2718
|
createdIds.push(b.id);
|
|
2649
2719
|
}
|
|
2650
|
-
const filtersFile =
|
|
2720
|
+
const filtersFile = path13.join(projectRoot, "component-filters.json");
|
|
2651
2721
|
const filters = mergeSectionFilter(
|
|
2652
2722
|
await readJson(filtersFile),
|
|
2653
2723
|
selected.map((b) => b.id)
|
|
@@ -2660,6 +2730,28 @@ async function scaffoldBlocks(names) {
|
|
|
2660
2730
|
logger.info("");
|
|
2661
2731
|
logger.info(box([`${createdIds.length} block(s) scaffolded + registered`]));
|
|
2662
2732
|
}
|
|
2733
|
+
async function scaffoldCi() {
|
|
2734
|
+
const projectRoot = findProjectRoot();
|
|
2735
|
+
if (!projectRoot) {
|
|
2736
|
+
logger.error("Not inside an EDS project (no fstab.yaml found).");
|
|
2737
|
+
process.exitCode = 1;
|
|
2738
|
+
return;
|
|
2739
|
+
}
|
|
2740
|
+
logger.logoOnce(logo("Scaffold - CI workflow"));
|
|
2741
|
+
const res = await writeCiWorkflow(projectRoot);
|
|
2742
|
+
logger.info(heading("GitHub Actions"));
|
|
2743
|
+
if (res.created) {
|
|
2744
|
+
logger.info(accentLine(res.path, "doctor + audit loading + audit security + lint/build"));
|
|
2745
|
+
} else {
|
|
2746
|
+
logger.info(statusLine("warn", res.path, "already exists - skipped"));
|
|
2747
|
+
}
|
|
2748
|
+
logger.info("");
|
|
2749
|
+
logger.info(
|
|
2750
|
+
box([
|
|
2751
|
+
res.created ? "CI workflow scaffolded - commit it and it runs on every PR" : "CI workflow left untouched"
|
|
2752
|
+
])
|
|
2753
|
+
);
|
|
2754
|
+
}
|
|
2663
2755
|
async function scaffoldInteractive() {
|
|
2664
2756
|
const { select, checkbox } = await import("@inquirer/prompts");
|
|
2665
2757
|
logger.logoOnce(logo("Scaffold"));
|
|
@@ -2668,7 +2760,8 @@ async function scaffoldInteractive() {
|
|
|
2668
2760
|
choices: [
|
|
2669
2761
|
{ name: "Universal Editor config + field-reference (all 17 field types)", value: "ue" },
|
|
2670
2762
|
{ name: "Standard blocks (hero, cards, columns, accordion, embed)", value: "blocks" },
|
|
2671
|
-
{ name: "
|
|
2763
|
+
{ name: "GitHub Actions CI (doctor + audits + lint/build)", value: "ci" },
|
|
2764
|
+
{ name: "UE config + standard blocks", value: "both" }
|
|
2672
2765
|
]
|
|
2673
2766
|
});
|
|
2674
2767
|
if (what === "ue" || what === "both") await scaffoldUe();
|
|
@@ -2679,6 +2772,7 @@ async function scaffoldInteractive() {
|
|
|
2679
2772
|
});
|
|
2680
2773
|
await scaffoldBlocks(picked);
|
|
2681
2774
|
}
|
|
2775
|
+
if (what === "ci") await scaffoldCi();
|
|
2682
2776
|
}
|
|
2683
2777
|
var init_scaffold = __esm({
|
|
2684
2778
|
"src/commands/scaffold.ts"() {
|
|
@@ -2687,6 +2781,7 @@ var init_scaffold = __esm({
|
|
|
2687
2781
|
init_logger();
|
|
2688
2782
|
init_project();
|
|
2689
2783
|
init_blocks();
|
|
2784
|
+
init_ci();
|
|
2690
2785
|
init_ue();
|
|
2691
2786
|
init_ui();
|
|
2692
2787
|
}
|
|
@@ -2791,9 +2886,9 @@ var integrate_exports = {};
|
|
|
2791
2886
|
__export(integrate_exports, {
|
|
2792
2887
|
integrate: () => integrate
|
|
2793
2888
|
});
|
|
2794
|
-
import { existsSync as
|
|
2795
|
-
import { mkdir as
|
|
2796
|
-
import
|
|
2889
|
+
import { existsSync as existsSync12 } from "fs";
|
|
2890
|
+
import { mkdir as mkdir5, readFile as readFile9, writeFile as writeFile6 } from "fs/promises";
|
|
2891
|
+
import path14 from "path";
|
|
2797
2892
|
import chalk8 from "chalk";
|
|
2798
2893
|
async function integrate(type) {
|
|
2799
2894
|
const projectRoot = findProjectRoot();
|
|
@@ -2822,10 +2917,10 @@ async function integrate(type) {
|
|
|
2822
2917
|
values[f.name] = answer.trim();
|
|
2823
2918
|
}
|
|
2824
2919
|
const block2 = wrapBlock(integration.name, integration.code(values));
|
|
2825
|
-
const delayedPath =
|
|
2826
|
-
await
|
|
2827
|
-
const existing =
|
|
2828
|
-
await
|
|
2920
|
+
const delayedPath = path14.join(projectRoot, "scripts", "delayed.js");
|
|
2921
|
+
await mkdir5(path14.dirname(delayedPath), { recursive: true });
|
|
2922
|
+
const existing = existsSync12(delayedPath) ? await readFile9(delayedPath, "utf-8") : DELAYED_HEADER;
|
|
2923
|
+
await writeFile6(delayedPath, `${existing.replace(/\s*$/, "")}
|
|
2829
2924
|
${block2}`);
|
|
2830
2925
|
logger.info(heading("Added"));
|
|
2831
2926
|
logger.info(accentLine(integration.name, "\u2192 scripts/delayed.js"));
|
|
@@ -2866,8 +2961,8 @@ var setup_exports = {};
|
|
|
2866
2961
|
__export(setup_exports, {
|
|
2867
2962
|
figmaSetup: () => figmaSetup
|
|
2868
2963
|
});
|
|
2869
|
-
import { existsSync as
|
|
2870
|
-
import { mkdir as
|
|
2964
|
+
import { existsSync as existsSync13 } from "fs";
|
|
2965
|
+
import { mkdir as mkdir6, writeFile as writeFile7 } from "fs/promises";
|
|
2871
2966
|
import chalk9 from "chalk";
|
|
2872
2967
|
async function figmaSetup() {
|
|
2873
2968
|
const { select, confirm } = await import("@inquirer/prompts");
|
|
@@ -2947,14 +3042,14 @@ async function figmaSetup() {
|
|
|
2947
3042
|
});
|
|
2948
3043
|
if (shouldSave) {
|
|
2949
3044
|
const configDir = globalConfigDir();
|
|
2950
|
-
if (!
|
|
2951
|
-
await
|
|
3045
|
+
if (!existsSync13(configDir)) {
|
|
3046
|
+
await mkdir6(configDir, { recursive: true });
|
|
2952
3047
|
}
|
|
2953
3048
|
const config = {};
|
|
2954
3049
|
if (selectedAgent !== "none") {
|
|
2955
3050
|
config.agent = selectedAgent;
|
|
2956
3051
|
}
|
|
2957
|
-
await
|
|
3052
|
+
await writeFile7(globalConfigPath(), `${JSON.stringify(config, null, 2)}
|
|
2958
3053
|
`, {
|
|
2959
3054
|
mode: 384
|
|
2960
3055
|
});
|
|
@@ -2981,9 +3076,9 @@ var doctor_exports = {};
|
|
|
2981
3076
|
__export(doctor_exports, {
|
|
2982
3077
|
doctor: () => doctor
|
|
2983
3078
|
});
|
|
2984
|
-
import { existsSync as
|
|
3079
|
+
import { existsSync as existsSync14 } from "fs";
|
|
2985
3080
|
import { readFile as readFile10, readdir as readdir2 } from "fs/promises";
|
|
2986
|
-
import
|
|
3081
|
+
import path15 from "path";
|
|
2987
3082
|
import { parse as parseYaml } from "yaml";
|
|
2988
3083
|
async function doctor(options = {}) {
|
|
2989
3084
|
const projectRoot = findProjectRoot();
|
|
@@ -3005,7 +3100,7 @@ async function doctor(options = {}) {
|
|
|
3005
3100
|
});
|
|
3006
3101
|
if (project.hasFstab) {
|
|
3007
3102
|
try {
|
|
3008
|
-
const content = await readFile10(
|
|
3103
|
+
const content = await readFile10(path15.join(projectRoot, "fstab.yaml"), "utf-8");
|
|
3009
3104
|
parseYaml(content);
|
|
3010
3105
|
results.push({ name: "fstab.yaml valid YAML", status: "pass", message: "Valid" });
|
|
3011
3106
|
} catch {
|
|
@@ -3027,11 +3122,11 @@ async function doctor(options = {}) {
|
|
|
3027
3122
|
message: project.hasBlocks ? "Found" : "Missing \u2014 no blocks yet"
|
|
3028
3123
|
});
|
|
3029
3124
|
if (project.hasBlocks) {
|
|
3030
|
-
const blocksDir =
|
|
3125
|
+
const blocksDir = path15.join(projectRoot, "blocks");
|
|
3031
3126
|
const entries = await readdir2(blocksDir, { withFileTypes: true });
|
|
3032
3127
|
let aggregatedModels = "";
|
|
3033
|
-
const aggregatedPath =
|
|
3034
|
-
if (
|
|
3128
|
+
const aggregatedPath = path15.join(projectRoot, "component-models.json");
|
|
3129
|
+
if (existsSync14(aggregatedPath)) {
|
|
3035
3130
|
try {
|
|
3036
3131
|
aggregatedModels = await readFile10(aggregatedPath, "utf-8");
|
|
3037
3132
|
} catch {
|
|
@@ -3040,8 +3135,8 @@ async function doctor(options = {}) {
|
|
|
3040
3135
|
for (const entry of entries) {
|
|
3041
3136
|
if (!entry.isDirectory()) continue;
|
|
3042
3137
|
const blockName = entry.name;
|
|
3043
|
-
const jsFile =
|
|
3044
|
-
const hasJs =
|
|
3138
|
+
const jsFile = path15.join(blocksDir, blockName, `${blockName}.js`);
|
|
3139
|
+
const hasJs = existsSync14(jsFile);
|
|
3045
3140
|
results.push({
|
|
3046
3141
|
name: `blocks/${blockName} has JS`,
|
|
3047
3142
|
status: hasJs ? "pass" : "warn",
|
|
@@ -3057,15 +3152,15 @@ async function doctor(options = {}) {
|
|
|
3057
3152
|
});
|
|
3058
3153
|
}
|
|
3059
3154
|
}
|
|
3060
|
-
const hasPerBlockModel =
|
|
3155
|
+
const hasPerBlockModel = existsSync14(path15.join(blocksDir, blockName, `_${blockName}.json`));
|
|
3061
3156
|
const hasAggregatedModel = aggregatedModels.includes(`"${blockName}"`);
|
|
3062
3157
|
results.push({
|
|
3063
3158
|
name: `blocks/${blockName} UE model`,
|
|
3064
3159
|
status: hasPerBlockModel || hasAggregatedModel ? "pass" : "warn",
|
|
3065
3160
|
message: hasPerBlockModel || hasAggregatedModel ? hasPerBlockModel ? `_${blockName}.json` : "in component-models.json" : "no Universal Editor model \u2014 authors can't edit this block in UE"
|
|
3066
3161
|
});
|
|
3067
|
-
const metaFile =
|
|
3068
|
-
if (
|
|
3162
|
+
const metaFile = path15.join(blocksDir, blockName, ".eds-meta.json");
|
|
3163
|
+
if (existsSync14(metaFile)) {
|
|
3069
3164
|
try {
|
|
3070
3165
|
const meta = JSON.parse(await readFile10(metaFile, "utf-8"));
|
|
3071
3166
|
const syncDate = new Date(meta.lastSyncedAt);
|
|
@@ -3087,8 +3182,8 @@ async function doctor(options = {}) {
|
|
|
3087
3182
|
}
|
|
3088
3183
|
}
|
|
3089
3184
|
}
|
|
3090
|
-
const queryFile =
|
|
3091
|
-
if (
|
|
3185
|
+
const queryFile = path15.join(projectRoot, "helix-query.yaml");
|
|
3186
|
+
if (existsSync14(queryFile)) {
|
|
3092
3187
|
try {
|
|
3093
3188
|
const content = await readFile10(queryFile, "utf-8");
|
|
3094
3189
|
parseYaml(content);
|
|
@@ -3147,9 +3242,9 @@ var audit_loading_exports = {};
|
|
|
3147
3242
|
__export(audit_loading_exports, {
|
|
3148
3243
|
auditLoading: () => auditLoading
|
|
3149
3244
|
});
|
|
3150
|
-
import { existsSync as
|
|
3245
|
+
import { existsSync as existsSync15 } from "fs";
|
|
3151
3246
|
import { readFile as readFile11, readdir as readdir3, stat as stat3 } from "fs/promises";
|
|
3152
|
-
import
|
|
3247
|
+
import path16 from "path";
|
|
3153
3248
|
import chalk10 from "chalk";
|
|
3154
3249
|
async function auditLoading(options = {}) {
|
|
3155
3250
|
const projectRoot = findProjectRoot();
|
|
@@ -3183,8 +3278,8 @@ async function auditLoading(options = {}) {
|
|
|
3183
3278
|
printResults(results);
|
|
3184
3279
|
}
|
|
3185
3280
|
async function checkHeadHtml(root, results) {
|
|
3186
|
-
const filePath =
|
|
3187
|
-
if (!
|
|
3281
|
+
const filePath = path16.join(root, "head.html");
|
|
3282
|
+
if (!existsSync15(filePath)) {
|
|
3188
3283
|
results.push({
|
|
3189
3284
|
rule: "head.html exists",
|
|
3190
3285
|
status: "warn",
|
|
@@ -3264,8 +3359,8 @@ async function checkHeadHtml(root, results) {
|
|
|
3264
3359
|
}
|
|
3265
3360
|
}
|
|
3266
3361
|
async function checkScriptsJs(root, results) {
|
|
3267
|
-
const filePath =
|
|
3268
|
-
if (!
|
|
3362
|
+
const filePath = path16.join(root, "scripts", "scripts.js");
|
|
3363
|
+
if (!existsSync15(filePath)) {
|
|
3269
3364
|
results.push({
|
|
3270
3365
|
rule: "scripts/scripts.js exists",
|
|
3271
3366
|
status: "warn",
|
|
@@ -3351,8 +3446,8 @@ async function checkScriptsJs(root, results) {
|
|
|
3351
3446
|
}
|
|
3352
3447
|
}
|
|
3353
3448
|
async function checkStylesCss(root, results) {
|
|
3354
|
-
const filePath =
|
|
3355
|
-
if (!
|
|
3449
|
+
const filePath = path16.join(root, "styles", "styles.css");
|
|
3450
|
+
if (!existsSync15(filePath)) return;
|
|
3356
3451
|
const stats = await stat3(filePath);
|
|
3357
3452
|
const sizeKb = stats.size / 1024;
|
|
3358
3453
|
results.push({
|
|
@@ -3372,8 +3467,8 @@ async function checkStylesCss(root, results) {
|
|
|
3372
3467
|
}
|
|
3373
3468
|
}
|
|
3374
3469
|
async function checkDelayedJs(root, results) {
|
|
3375
|
-
const filePath =
|
|
3376
|
-
if (!
|
|
3470
|
+
const filePath = path16.join(root, "scripts", "delayed.js");
|
|
3471
|
+
if (!existsSync15(filePath)) {
|
|
3377
3472
|
results.push({
|
|
3378
3473
|
rule: "scripts/delayed.js exists",
|
|
3379
3474
|
status: "info",
|
|
@@ -3393,14 +3488,14 @@ async function checkDelayedJs(root, results) {
|
|
|
3393
3488
|
}
|
|
3394
3489
|
}
|
|
3395
3490
|
async function checkBlocks(root, results) {
|
|
3396
|
-
const blocksDir =
|
|
3397
|
-
if (!
|
|
3491
|
+
const blocksDir = path16.join(root, "blocks");
|
|
3492
|
+
if (!existsSync15(blocksDir)) return;
|
|
3398
3493
|
const entries = await readdir3(blocksDir, { withFileTypes: true });
|
|
3399
3494
|
for (const entry of entries) {
|
|
3400
3495
|
if (!entry.isDirectory()) continue;
|
|
3401
3496
|
const blockName = entry.name;
|
|
3402
|
-
const jsFile =
|
|
3403
|
-
if (!
|
|
3497
|
+
const jsFile = path16.join(blocksDir, blockName, `${blockName}.js`);
|
|
3498
|
+
if (!existsSync15(jsFile)) continue;
|
|
3404
3499
|
const content = await readFile11(jsFile, "utf-8");
|
|
3405
3500
|
const lines = content.split("\n");
|
|
3406
3501
|
const heavyLibs = [
|
|
@@ -3451,8 +3546,8 @@ async function checkBlocks(root, results) {
|
|
|
3451
3546
|
for (const entry of entries) {
|
|
3452
3547
|
if (!entry.isDirectory()) continue;
|
|
3453
3548
|
const blockName = entry.name;
|
|
3454
|
-
const cssFile =
|
|
3455
|
-
if (!
|
|
3549
|
+
const cssFile = path16.join(blocksDir, blockName, `${blockName}.css`);
|
|
3550
|
+
if (!existsSync15(cssFile)) continue;
|
|
3456
3551
|
const content = await readFile11(cssFile, "utf-8");
|
|
3457
3552
|
const selectorPattern = /^([a-z][a-z0-9-]*)\s*\{/gm;
|
|
3458
3553
|
for (const selectorMatch of content.matchAll(selectorPattern)) {
|
|
@@ -3469,8 +3564,8 @@ async function checkBlocks(root, results) {
|
|
|
3469
3564
|
}
|
|
3470
3565
|
}
|
|
3471
3566
|
async function checkAemJs(root, results) {
|
|
3472
|
-
const filePath =
|
|
3473
|
-
if (!
|
|
3567
|
+
const filePath = path16.join(root, "scripts", "aem.js");
|
|
3568
|
+
if (!existsSync15(filePath)) {
|
|
3474
3569
|
results.push({
|
|
3475
3570
|
rule: "scripts/aem.js exists",
|
|
3476
3571
|
status: "warn",
|
|
@@ -3542,14 +3637,14 @@ var audit_security_exports = {};
|
|
|
3542
3637
|
__export(audit_security_exports, {
|
|
3543
3638
|
auditSecurity: () => auditSecurity
|
|
3544
3639
|
});
|
|
3545
|
-
import { existsSync as
|
|
3640
|
+
import { existsSync as existsSync16 } from "fs";
|
|
3546
3641
|
import { readFile as readFile12, readdir as readdir4 } from "fs/promises";
|
|
3547
|
-
import
|
|
3642
|
+
import path17 from "path";
|
|
3548
3643
|
import chalk11 from "chalk";
|
|
3549
3644
|
async function* walk(dir) {
|
|
3550
3645
|
const entries = await readdir4(dir, { withFileTypes: true });
|
|
3551
3646
|
for (const entry of entries) {
|
|
3552
|
-
const full =
|
|
3647
|
+
const full = path17.join(dir, entry.name);
|
|
3553
3648
|
if (entry.isDirectory()) {
|
|
3554
3649
|
if (IGNORE_DIRS.has(entry.name)) continue;
|
|
3555
3650
|
yield* walk(full);
|
|
@@ -3583,11 +3678,11 @@ function scanContent(content, relFile, ext) {
|
|
|
3583
3678
|
return findings;
|
|
3584
3679
|
}
|
|
3585
3680
|
async function auditDependencies(root) {
|
|
3586
|
-
if (!
|
|
3681
|
+
if (!existsSync16(path17.join(root, "package.json"))) {
|
|
3587
3682
|
return { status: "skipped", note: "no package.json" };
|
|
3588
3683
|
}
|
|
3589
|
-
const hasLock =
|
|
3590
|
-
if (!hasLock && !
|
|
3684
|
+
const hasLock = existsSync16(path17.join(root, "package-lock.json")) || existsSync16(path17.join(root, "npm-shrinkwrap.json"));
|
|
3685
|
+
if (!hasLock && !existsSync16(path17.join(root, "node_modules"))) {
|
|
3591
3686
|
return { status: "skipped", note: "no package-lock.json / node_modules \u2014 run npm install" };
|
|
3592
3687
|
}
|
|
3593
3688
|
try {
|
|
@@ -3619,9 +3714,9 @@ async function auditSecurity(options = {}) {
|
|
|
3619
3714
|
}
|
|
3620
3715
|
const findings = [];
|
|
3621
3716
|
for await (const file of walk(projectRoot)) {
|
|
3622
|
-
const ext =
|
|
3717
|
+
const ext = path17.extname(file).slice(1).toLowerCase();
|
|
3623
3718
|
if (!SCAN_EXT.has(ext)) continue;
|
|
3624
|
-
const rel =
|
|
3719
|
+
const rel = path17.relative(projectRoot, file);
|
|
3625
3720
|
if (rel.endsWith("aem.js") || rel.endsWith("lib-franklin.js")) continue;
|
|
3626
3721
|
const content = await readFile12(file, "utf-8");
|
|
3627
3722
|
findings.push(...scanContent(content, rel, ext));
|
|
@@ -4041,12 +4136,12 @@ var menu_exports = {};
|
|
|
4041
4136
|
__export(menu_exports, {
|
|
4042
4137
|
mainMenu: () => mainMenu
|
|
4043
4138
|
});
|
|
4044
|
-
import { existsSync as
|
|
4139
|
+
import { existsSync as existsSync17 } from "fs";
|
|
4045
4140
|
import { readdir as readdir5 } from "fs/promises";
|
|
4046
|
-
import
|
|
4141
|
+
import path18 from "path";
|
|
4047
4142
|
async function listBlockNames(projectRoot) {
|
|
4048
|
-
const dir =
|
|
4049
|
-
if (!
|
|
4143
|
+
const dir = path18.join(projectRoot, "blocks");
|
|
4144
|
+
if (!existsSync17(dir)) return [];
|
|
4050
4145
|
const entries = await readdir5(dir, { withFileTypes: true });
|
|
4051
4146
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
4052
4147
|
}
|
|
@@ -4161,7 +4256,7 @@ import { Command } from "commander";
|
|
|
4161
4256
|
// package.json
|
|
4162
4257
|
var package_default = {
|
|
4163
4258
|
name: "aem-eds-kit",
|
|
4164
|
-
version: "0.4.
|
|
4259
|
+
version: "0.4.4",
|
|
4165
4260
|
description: "CLI for AEM Edge Delivery Services with Figma MCP integration",
|
|
4166
4261
|
type: "module",
|
|
4167
4262
|
engines: {
|
|
@@ -4270,6 +4365,10 @@ scaffold.command("blocks [names...]").description("Scaffold standard blocks (her
|
|
|
4270
4365
|
const { scaffoldBlocks: scaffoldBlocks2 } = await Promise.resolve().then(() => (init_scaffold(), scaffold_exports));
|
|
4271
4366
|
await scaffoldBlocks2(names);
|
|
4272
4367
|
});
|
|
4368
|
+
scaffold.command("ci").description("Scaffold a GitHub Actions workflow (doctor + audits + project lint/build)").action(async () => {
|
|
4369
|
+
const { scaffoldCi: scaffoldCi2 } = await Promise.resolve().then(() => (init_scaffold(), scaffold_exports));
|
|
4370
|
+
await scaffoldCi2();
|
|
4371
|
+
});
|
|
4273
4372
|
program.command("integrate [type]").description("Add a third-party service (GTM, GA4, chat, consent) to scripts/delayed.js").action(async (type) => {
|
|
4274
4373
|
const { integrate: integrate2 } = await Promise.resolve().then(() => (init_integrate(), integrate_exports));
|
|
4275
4374
|
await integrate2(type);
|