storybook-addon-dependency-previews 0.5.2 → 0.5.4-beta.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/dist/cli/sb-deps.cjs +25 -9
- package/dist/cli/sb-deps.cjs.map +1 -1
- package/dist/cli/sb-deps.mjs +25 -9
- package/dist/cli/sb-deps.mjs.map +1 -1
- package/dist/cli/scripts/depcruise.config.cjs +7 -4
- package/dist/cli/scripts/depcruise.config.cjs.map +1 -1
- package/dist/cli/scripts/depcruise.config.mjs +7 -4
- package/dist/cli/scripts/depcruise.config.mjs.map +1 -1
- package/dist/cli/scripts/postprocess.cjs +2 -4
- package/dist/cli/scripts/postprocess.cjs.map +1 -1
- package/dist/cli/scripts/postprocess.mjs +2 -4
- package/dist/cli/scripts/postprocess.mjs.map +1 -1
- package/dist/cli/setup/gitOrigin.cjs +231 -0
- package/dist/cli/setup/gitOrigin.cjs.map +1 -0
- package/dist/cli/setup/gitOrigin.mjs +228 -0
- package/dist/cli/setup/gitOrigin.mjs.map +1 -0
- package/dist/cli/setup/index.cjs +59 -11
- package/dist/cli/setup/index.cjs.map +1 -1
- package/dist/cli/setup/index.mjs +59 -11
- package/dist/cli/setup/index.mjs.map +1 -1
- package/dist/cli/setup/patchers/preview.cjs +21 -12
- package/dist/cli/setup/patchers/preview.cjs.map +1 -1
- package/dist/cli/setup/patchers/preview.d.cts +6 -0
- package/dist/cli/setup/patchers/preview.d.mts +6 -0
- package/dist/cli/setup/patchers/preview.mjs +21 -12
- package/dist/cli/setup/patchers/preview.mjs.map +1 -1
- package/dist/cli/setup/patchers/sbDepsConfig.cjs +66 -0
- package/dist/cli/setup/patchers/sbDepsConfig.cjs.map +1 -0
- package/dist/cli/setup/patchers/sbDepsConfig.mjs +63 -0
- package/dist/cli/setup/patchers/sbDepsConfig.mjs.map +1 -0
- package/dist/cli/setup/prompt.cjs +6 -0
- package/dist/cli/setup/prompt.cjs.map +1 -1
- package/dist/cli/setup/prompt.d.cts +7 -1
- package/dist/cli/setup/prompt.d.mts +7 -1
- package/dist/cli/setup/prompt.mjs +6 -1
- package/dist/cli/setup/prompt.mjs.map +1 -1
- package/dist/cli/setup/srcDir.cjs +114 -0
- package/dist/cli/setup/srcDir.cjs.map +1 -0
- package/dist/cli/setup/srcDir.mjs +111 -0
- package/dist/cli/setup/srcDir.mjs.map +1 -0
- package/dist/components/PrimaryPreview.cjs +11 -1
- package/dist/components/PrimaryPreview.cjs.map +1 -1
- package/dist/components/PrimaryPreview.mjs +12 -2
- package/dist/components/PrimaryPreview.mjs.map +1 -1
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +25 -16
- package/dist/config.d.mts +25 -16
- package/dist/config.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/sb-deps.cjs
CHANGED
|
@@ -105,14 +105,14 @@ function resolveDepCruiseBin() {
|
|
|
105
105
|
return (0, node_fs.existsSync)(bin) ? bin : null;
|
|
106
106
|
}
|
|
107
107
|
function runDepCruiseOnce() {
|
|
108
|
-
const
|
|
108
|
+
const includeOnly = SRC_DIR === "" ? "^(?!(?:[^/]*/)*node_modules/)" : `^${SRC_DIR.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/`;
|
|
109
109
|
const args = ["."];
|
|
110
110
|
if (configPath) {
|
|
111
111
|
args.push("--config", configPath);
|
|
112
112
|
} else {
|
|
113
113
|
args.push("--no-config");
|
|
114
114
|
}
|
|
115
|
-
args.push("--include-only",
|
|
115
|
+
args.push("--include-only", includeOnly, "--output-type", "json");
|
|
116
116
|
const depcruiseBin = resolveDepCruiseBin();
|
|
117
117
|
if (!depcruiseBin) {
|
|
118
118
|
throw new Error("Could not locate `dependency-cruiser` in node_modules/.bin. Run the setup wizard (`sb-deps setup`) or install `dependency-cruiser` as a dev dependency.");
|
|
@@ -126,7 +126,11 @@ function runDepCruiseOnce() {
|
|
|
126
126
|
"inherit"
|
|
127
127
|
],
|
|
128
128
|
encoding: "utf8",
|
|
129
|
-
shell: IS_WIN
|
|
129
|
+
shell: IS_WIN,
|
|
130
|
+
env: {
|
|
131
|
+
...process.env,
|
|
132
|
+
SB_DEPS_SRC_DIR: SRC_DIR
|
|
133
|
+
}
|
|
130
134
|
});
|
|
131
135
|
(0, node_fs.writeFileSync)(rawPath, stdout, "utf8");
|
|
132
136
|
info(`graph ✓ (${ms(Date.now() - start)})`);
|
|
@@ -198,6 +202,9 @@ function isEmptyOrWhitespace(absPath) {
|
|
|
198
202
|
* (`STORY_FILE_REGEX`) is applied separately in the individual helpers.
|
|
199
203
|
*/
|
|
200
204
|
function srcSubpathRegex(suffixPattern) {
|
|
205
|
+
if (SRC_DIR === "") {
|
|
206
|
+
return new RegExp(`.+${suffixPattern}`, "i");
|
|
207
|
+
}
|
|
201
208
|
const escapedSrcDir = SRC_DIR.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
202
209
|
return new RegExp(`(?:^|\\/)${escapedSrcDir}\\/.+${suffixPattern}`, "i");
|
|
203
210
|
}
|
|
@@ -660,11 +667,12 @@ function ensureStoryForAngularComponent(absCompPath) {
|
|
|
660
667
|
}
|
|
661
668
|
function startWatcher() {
|
|
662
669
|
const root = projectRoot;
|
|
670
|
+
const srcPrefix = SRC_DIR === "" ? "" : `${SRC_DIR}/`;
|
|
663
671
|
const includeGlobs = [
|
|
664
672
|
"**/*.stories.{ts,tsx,js,jsx,mdx,svelte}",
|
|
665
673
|
"**/*.story.{ts,tsx,js,jsx,mdx,svelte}",
|
|
666
|
-
`${
|
|
667
|
-
`${
|
|
674
|
+
`${srcPrefix}**/*.{ts,tsx,js,jsx,svelte}`,
|
|
675
|
+
`${srcPrefix}**/*.component.html`,
|
|
668
676
|
"depcruise.config.cjs",
|
|
669
677
|
".dependency-cruiser.{js,cjs}"
|
|
670
678
|
];
|
|
@@ -820,13 +828,21 @@ async function startStorybook() {
|
|
|
820
828
|
const cfg = await loadSbDepsConfig();
|
|
821
829
|
ANGULAR_SELECTOR_PREFIX = cfg.angularSelectorPrefix ?? "app-";
|
|
822
830
|
SCAFFOLD_CONFIG = cfg.scaffold ?? {};
|
|
823
|
-
const rawSrcDir = (cfg.srcDir ?? "src").replace(/[\\/]+$/, "").trim();
|
|
824
831
|
const SAFE_SRCDIR_PATTERN = /^[A-Za-z0-9._-]+$/;
|
|
825
|
-
|
|
826
|
-
|
|
832
|
+
const userSrcDir = cfg.srcDir;
|
|
833
|
+
if (userSrcDir === undefined) {
|
|
827
834
|
SRC_DIR = "src";
|
|
835
|
+
} else if (userSrcDir === "") {
|
|
836
|
+
SRC_DIR = "";
|
|
828
837
|
} else {
|
|
829
|
-
|
|
838
|
+
const trimmed = userSrcDir.replace(/[\\/]+$/, "").trim();
|
|
839
|
+
const isSpecialSegment = trimmed === "." || trimmed === "..";
|
|
840
|
+
if (trimmed !== "" && !isSpecialSegment && SAFE_SRCDIR_PATTERN.test(trimmed)) {
|
|
841
|
+
SRC_DIR = trimmed;
|
|
842
|
+
} else {
|
|
843
|
+
error(`srcDir "${userSrcDir}" is invalid — must be either exactly the empty string (project root) or a single directory name containing only alphanumerics, ".", "_", or "-" (e.g. "src", "app", "my-source"). "." and ".." are not allowed. Falling back to "src".`);
|
|
844
|
+
SRC_DIR = "src";
|
|
845
|
+
}
|
|
830
846
|
}
|
|
831
847
|
banner("sb-deps");
|
|
832
848
|
info(`outDir: ${rel(outDir)}`);
|
package/dist/cli/sb-deps.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sb-deps.cjs","names":["__filename","__dirname","SCAFFOLD_CONFIG: SbDepsConfig['scaffold']","args: Array<string>","best: null | { val: string; idx: number }","sep","posix","unitSize: number","unitChar: string","knownMappings: Array<[number, number]>","htmlContent: string | null","timer: NodeJS.Timeout | null","watcherParcel","sbChild: ChildProcess | null","cmd: string","args: string[]","shellMode: boolean","runSetup","watcher: watcherParcel.AsyncSubscription | null"],"sources":["../../cli/sb-deps.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/* eslint-disable no-console */\nimport watcherParcel from '@parcel/watcher'\nimport micromatch from 'micromatch'\nimport { execFileSync, spawn, type ChildProcess } from 'node:child_process'\nimport {\n\texistsSync,\n\tmkdirSync,\n\treadFileSync,\n\tstatSync,\n\twriteFileSync,\n} from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { basename, dirname, join, posix, resolve, sep } from 'node:path'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport type { SbDepsConfig } from '../src/config.js'\nimport { runSetup } from './setup/index.js'\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Args\n// ───────────────────────────────────────────────────────────────────────────────\nconst argv = process.argv.slice(2)\nconst SUBCOMMAND = argv[0] && !argv[0].startsWith('--') ? argv[0] : null\nconst WATCH = argv.includes('--watch')\nconst RUN_SB_IDX = argv.indexOf('--run-storybook')\nconst RUN_SB = RUN_SB_IDX !== -1\nconst _RUN_SB_NEXT = RUN_SB ? argv[RUN_SB_IDX + 1] : undefined\nconst SB_CUSTOM_CMD =\n\t_RUN_SB_NEXT && !_RUN_SB_NEXT.startsWith('--') ? _RUN_SB_NEXT : undefined\nconst PORT_ARGI = argv.indexOf('--sb-port')\nconst SB_PORT =\n\tPORT_ARGI !== -1 && argv[PORT_ARGI + 1]\n\t\t? Number(argv[PORT_ARGI + 1]) || 6006\n\t\t: 6006\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Paths\n// ───────────────────────────────────────────────────────────────────────────────\nconst projectRoot = process.cwd()\nconst outDir = resolve(projectRoot, '.storybook')\nconst rawPath = join(outDir, 'dependency-previews.raw.json')\nconst cookedPath = join(outDir, 'dependency-previews.json')\n\n// Don't auto-create `.storybook/` for the setup subcommand — the wizard needs to\n// detect whether Storybook has been initialised so it can guide the user. The\n// regular build/watch path still needs the directory to exist for its JSON output.\nif (SUBCOMMAND !== 'setup' && !existsSync(outDir))\n\tmkdirSync(outDir, { recursive: true })\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\n// Resolve depcruise config: prefer project overrides, else bundled default\nconst pkgDefault = resolve(__dirname, 'scripts', 'depcruise.config.cjs')\nconst overrideCandidates = [\n\tresolve(projectRoot, 'depcruise.config.cjs'),\n\tresolve(projectRoot, '.dependency-cruiser.js'),\n\tresolve(projectRoot, '.dependency-cruiser.cjs'),\n]\nconst configPath =\n\toverrideCandidates.find((p) => existsSync(p)) ||\n\t(existsSync(pkgDefault) ? pkgDefault : null)\n\n// Path to postprocess helper (built as ESM)\nconst post = resolve(__dirname, 'scripts', 'postprocess.mjs')\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Config\n// ───────────────────────────────────────────────────────────────────────────────\nfunction checkIsProjectEsm(): boolean {\n\ttry {\n\t\tconst pkg = JSON.parse(\n\t\t\treadFileSync(resolve(projectRoot, 'package.json'), 'utf8'),\n\t\t)\n\t\treturn pkg.type === 'module'\n\t} catch {\n\t\treturn false\n\t}\n}\n\nasync function loadSbDepsConfig(): Promise<SbDepsConfig> {\n\tconst candidates = [\n\t\t{\n\t\t\tpath: resolve(projectRoot, 'sb-deps.config.js'),\n\t\t\tisEsm: checkIsProjectEsm(),\n\t\t},\n\t\t{ path: resolve(projectRoot, 'sb-deps.config.mjs'), isEsm: true },\n\t\t{ path: resolve(projectRoot, 'sb-deps.config.cjs'), isEsm: false },\n\t]\n\tfor (const { path: cfgPath, isEsm } of candidates) {\n\t\tif (!existsSync(cfgPath)) continue\n\t\ttry {\n\t\t\tif (isEsm) {\n\t\t\t\tconst mod = await import(pathToFileURL(cfgPath).href)\n\t\t\t\treturn (mod.default ?? mod) as SbDepsConfig\n\t\t\t} else {\n\t\t\t\tconst req = createRequire(import.meta.url)\n\t\t\t\tconst mod = req(cfgPath)\n\t\t\t\treturn (mod?.default ?? mod) as SbDepsConfig\n\t\t\t}\n\t\t} catch (e) {\n\t\t\terror(`failed to load sb-deps config: ${e}`)\n\t\t}\n\t}\n\treturn {}\n}\n\nlet ANGULAR_SELECTOR_PREFIX = 'app-'\nlet SCAFFOLD_CONFIG: SbDepsConfig['scaffold'] = {}\nlet SRC_DIR = 'src'\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Runners\n// ───────────────────────────────────────────────────────────────────────────────\nconst IS_WIN = process.platform === 'win32'\n\n/**\n * Locate the `dependency-cruiser` CLI binary in the user's `node_modules/.bin`.\n * Returns the absolute path with the right extension for the platform (`.cmd`\n * shim on Windows, bare name elsewhere). Falls back to `null` if it can't be\n * found — caller decides what to do.\n *\n * Going through the resolved binary lets us call `execFileSync` directly\n * (with `shell: false`) and pass each flag as its own array element — no\n * shell quoting, no `cmd.exe` metacharacter mangling (`^` is a `cmd.exe`\n * escape character, which would silently strip the `^` anchor from our\n * `--include-only` regex if we went through a shell). It also avoids spawning\n * `npx`, which on Windows is a `.cmd` shim that requires `shell: true` to\n * launch — which would reintroduce the very quoting problem we're trying to\n * avoid.\n */\nfunction resolveDepCruiseBin(): string | null {\n\tconst bin = join(\n\t\tprojectRoot,\n\t\t'node_modules',\n\t\t'.bin',\n\t\tIS_WIN ? 'depcruise.cmd' : 'depcruise',\n\t)\n\treturn existsSync(bin) ? bin : null\n}\n\nfunction runDepCruiseOnce() {\n\t// Pass --include-only at the CLI level so it overrides whatever the loaded\n\t// depcruise config has (depcruise CLI flags take precedence over config-file\n\t// options). That way SRC_DIR controls dep-cruiser's scan scope without\n\t// requiring users with non-`src` layouts to also override the bundled config.\n\t//\n\t// The regex must escape any regex metacharacters in SRC_DIR (a value like\n\t// `src.app` would otherwise broaden the scope unintentionally) and anchor\n\t// to a `/` so the directory boundary is respected — without the trailing\n\t// slash `^src` would also match `src2/`, `srcabc/`, etc.\n\tconst escapedSrcDir = SRC_DIR.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\tconst args: Array<string> = ['.']\n\tif (configPath) {\n\t\targs.push('--config', configPath)\n\t} else {\n\t\targs.push('--no-config')\n\t}\n\targs.push('--include-only', `^${escapedSrcDir}/`, '--output-type', 'json')\n\n\tconst depcruiseBin = resolveDepCruiseBin()\n\tif (!depcruiseBin) {\n\t\tthrow new Error(\n\t\t\t'Could not locate `dependency-cruiser` in node_modules/.bin. Run the setup wizard (`sb-deps setup`) or install `dependency-cruiser` as a dev dependency.',\n\t\t)\n\t}\n\n\tconst start = Date.now()\n\t// `.cmd` shims on Windows need `shell: true` to launch, BUT once shell is\n\t// on, cmd.exe re-interprets `^` as an escape character — which would strip\n\t// the anchor from our regex. Workaround: spawn the `.cmd` itself with\n\t// shell:true (cmd.exe wraps the call) and pre-escape `^` for cmd.exe by\n\t// doubling it. On Unix the binary is a real ELF/script (no shim), shell:false\n\t// is the default, args pass through unmolested.\n\tconst stdout = execFileSync(\n\t\tdepcruiseBin,\n\t\tIS_WIN ? args.map(escapeForCmdExe) : args,\n\t\t{\n\t\t\tcwd: projectRoot,\n\t\t\tstdio: ['ignore', 'pipe', 'inherit'],\n\t\t\tencoding: 'utf8',\n\t\t\tshell: IS_WIN,\n\t\t},\n\t)\n\twriteFileSync(rawPath, stdout, 'utf8')\n\tinfo(`graph ✓ (${ms(Date.now() - start)})`)\n}\n\nfunction postprocessOnce() {\n\tconst start = Date.now()\n\t// `node` is a real executable on every platform (no `.cmd` shim), so we\n\t// don't need shell:true here — args pass through directly with no quoting\n\t// or escape concerns.\n\texecFileSync('node', [post, rawPath, cookedPath, SRC_DIR], {\n\t\tcwd: projectRoot,\n\t\tstdio: 'inherit',\n\t})\n\tinfo(`compiled ✓ → ${rel(cookedPath)} (${ms(Date.now() - start)})`)\n}\n\n/**\n * Escape an argument so that it survives `cmd.exe` parsing when `execFileSync`\n * is invoked with `shell: true` on Windows. `^` is the cmd.exe escape character,\n * even inside double quotes — doubling it makes cmd.exe pass through a literal\n * `^`. Other shell metacharacters (`&`, `|`, `<`, `>`, `(`, `)`, `%`, `!`) are\n * already wrapped in double quotes by Node's internal arg-quoter when\n * `shell: true`, so we only need to handle `^` ourselves.\n */\nfunction escapeForCmdExe(arg: string): string {\n\treturn arg.replace(/\\^/g, '^^')\n}\n\nfunction buildOnce() {\n\ttry {\n\t\trunDepCruiseOnce()\n\t\tpostprocessOnce()\n\t} catch (e) {\n\t\terror('build failed')\n\t\tif (!WATCH) throw e\n\t}\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// String utils\n// ───────────────────────────────────────────────────────────────────────────────\nfunction toWords(input: string) {\n\treturn String(input)\n\t\t.replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n\t\t.replace(/[_\\-./]+/g, ' ')\n\t\t.trim()\n\t\t.split(/\\s+/)\n}\nfunction toTitleCase(words: Array<string>) {\n\treturn words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')\n}\nfunction toPascalCase(input: string) {\n\treturn toTitleCase(toWords(input)).replace(/\\s+/g, '')\n}\nfunction toKebabCase(input: string) {\n\treturn toWords(input)\n\t\t.map((w) => w.toLowerCase())\n\t\t.join('-')\n}\n\nfunction isEmptyOrWhitespace(absPath: string) {\n\ttry {\n\t\tconst s = statSync(absPath)\n\t\tif (s.size === 0) return true\n\t\tconst txt = readFileSync(absPath, 'utf8')\n\t\treturn !txt.trim()\n\t} catch {\n\t\treturn true\n\t}\n}\n\n/**\n * Build a regex that matches `<SRC_DIR>/...<suffix>` for the scaffolding-trigger\n * helpers below. `SRC_DIR` is interpolated at call time (these helpers run\n * inside the watcher event loop, after the boot block has loaded the config\n * and finalised `SRC_DIR`).\n *\n * Files don't have to live under a `components/` subfolder — same philosophy\n * as the postprocess filter: any source file under `srcDir` with the right\n * extension is a candidate. The framework-agnostic story-file exclusion\n * (`STORY_FILE_REGEX`) is applied separately in the individual helpers.\n */\nfunction srcSubpathRegex(suffixPattern: string): RegExp {\n\tconst escapedSrcDir = SRC_DIR.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\treturn new RegExp(`(?:^|\\\\/)${escapedSrcDir}\\\\/.+${suffixPattern}`, 'i')\n}\n\n/**\n * Matches story files in any framework: `.story.<ext>` or `.stories.<ext>`\n * where `<ext>` is any single-segment file extension (`.svelte`, `.ts`, `.tsx`,\n * `.js`, `.jsx`, `.mdx`, …). Used by the scaffolding-trigger helpers to make\n * sure they don't try to auto-scaffold a story file for an existing story.\n */\nconst STORY_FILE_REGEX = /\\.stories?\\.\\w+$/i\n\n// <srcDir>/**/Thing.tsx ? (and not a story file)\nfunction isComponentsTsx(absPath: string) {\n\tconst norm = absPath.replace(/\\\\/g, '/')\n\treturn srcSubpathRegex('\\\\.tsx$').test(norm) && !STORY_FILE_REGEX.test(norm)\n}\n\n// <srcDir>/**/Thing.svelte ? (and not a story file)\nfunction isComponentsSvelte(absPath: string) {\n\tconst norm = absPath.replace(/\\\\/g, '/')\n\treturn (\n\t\tsrcSubpathRegex('\\\\.svelte$').test(norm) && !STORY_FILE_REGEX.test(norm)\n\t)\n}\n\n// <srcDir>/**/Thing.decorator.svelte ?\nfunction isDecoratorSvelte(absPath: string) {\n\tconst norm = absPath.replace(/\\\\/g, '/')\n\treturn srcSubpathRegex('\\\\.decorator\\\\.svelte$').test(norm)\n}\n\n// <srcDir>/**/Thing.component.ts ?\nfunction isComponentsAngularTs(absPath: string) {\n\tconst norm = absPath.replace(/\\\\/g, '/')\n\treturn srcSubpathRegex('\\\\.component\\\\.ts$').test(norm)\n}\n\n// <srcDir>/**/Thing.component.html ?\nfunction isComponentsAngularHtml(absPath: string) {\n\tconst norm = absPath.replace(/\\\\/g, '/')\n\treturn srcSubpathRegex('\\\\.component\\\\.html$').test(norm)\n}\n\nfunction componentBaseFromComponent(absCompPath: string) {\n\treturn basename(absCompPath, '.tsx')\n}\n\nfunction componentBaseFromSvelteComponent(absCompPath: string) {\n\treturn basename(absCompPath, '.svelte')\n}\n\nfunction componentBaseFromAngularComponent(absCompPath: string) {\n\treturn basename(absCompPath).replace(/\\.component\\.(ts|html)$/i, '')\n}\n\nfunction angularComponentTsPath(absPath: string) {\n\tconst base = componentBaseFromAngularComponent(absPath)\n\treturn join(dirname(absPath), `${base}.component.ts`)\n}\n\nfunction detectAtomicTag(absPath: string) {\n\tconst adaptedPath = absPath.toLowerCase().replace(/\\\\/g, '/')\n\tconst tokens = ['atom', 'molecule', 'organism', 'template', 'page', 'icon']\n\tlet best: null | { val: string; idx: number } = null\n\tfor (const t of tokens) {\n\t\tconst idx = adaptedPath.lastIndexOf(t)\n\t\tif (idx !== -1 && (best === null || idx > best.idx)) best = { val: t, idx }\n\t}\n\treturn best ? best.val : null\n}\n\nfunction storyPathForComponent(absCompPath: string) {\n\tconst dir = dirname(absCompPath)\n\tconst base = componentBaseFromComponent(absCompPath)\n\treturn join(dir, `${base}.stories.tsx`)\n}\n\nfunction storyPathForSvelteComponent(absCompPath: string) {\n\tconst dir = dirname(absCompPath)\n\tconst base = componentBaseFromSvelteComponent(absCompPath)\n\treturn join(dir, `${base}.stories.svelte`)\n}\n\nfunction makeTitleFromComponent(absCompPath: string) {\n\tconst srcRoot = join(projectRoot, SRC_DIR) + sep\n\tconst normAbs = absCompPath.replace(/\\\\/g, '/')\n\tconst relFromSrc = normAbs.startsWith(srcRoot.replace(/\\\\/g, '/'))\n\t\t? normAbs.slice(srcRoot.length)\n\t\t: absCompPath.replace(projectRoot + sep, '').replace(/\\\\/g, '/')\n\n\tconst dir = posix.dirname(relFromSrc)\n\tlet segments = dir.split('/').filter(Boolean)\n\tif (segments[0] && /^components?$/i.test(segments[0]))\n\t\tsegments = segments.slice(1)\n\n\tconst titledFolders = segments.map((s) => toTitleCase(toWords(s)))\n\tconst compName = componentBaseFromComponent(absCompPath)\n\tconst compTitle = toTitleCase(toWords(compName))\n\n\tconst fullStoryPath = [...titledFolders, compTitle].filter(Boolean)\n\n\t// remove duplicates (e.g. Folder/Thing/Thing => Folder/Thing)\n\tconst dedupedStoryPath = [...new Set(fullStoryPath)]\n\n\treturn dedupedStoryPath.join(' / ')\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Story & component scaffolding\n// ───────────────────────────────────────────────────────────────────────────────\nfunction scaffoldComponent(absCompPath: string) {\n\tconst base = componentBaseFromComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\tconst propsName = `PropsFor${componentName}`\n\n\tconst tpl =\n\t\tSCAFFOLD_CONFIG?.react?.component?.({ componentName, propsName }) ??\n\t\t`import type { ReactNode } from 'react'\n\nexport interface ${propsName} {\n children?: ReactNode\n}\n\nexport function ${componentName}({ children }: ${propsName}) {\n return (\n <div className=\"${componentName}\">\n <p>${componentName}</p>\n {children}\n </div>\n )\n}\n`\n\twriteFileSync(absCompPath, tpl, 'utf8')\n\tinfo(`scaffolded component → \\${rel(absCompPath)}`)\n}\n\nfunction scaffoldStoryForComponent(absCompPath: string) {\n\tconst base = componentBaseFromComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\tconst propsName = `PropsFor${componentName}`\n\tconst title = makeTitleFromComponent(absCompPath)\n\tconst atomic = detectAtomicTag(absCompPath)\n\tconst tags = ['autodocs']\n\tif (atomic) tags.push(atomic)\n\n\tconst storyTpl =\n\t\tSCAFFOLD_CONFIG?.react?.story?.({\n\t\t\tcomponentName,\n\t\t\tpropsName,\n\t\t\ttitle,\n\t\t\ttags,\n\t\t\tbase,\n\t\t}) ??\n\t\t`import type { Meta, StoryObj } from '@storybook/react-vite'\nimport type { StoryParameters } from 'storybook-addon-dependency-previews'\nimport { ${componentName}, type ${propsName} } from './${componentName}'\n\nconst meta: Meta<typeof ${componentName}> = {\n title: '${title}',\n component: ${componentName},\n tags: ${JSON.stringify(tags)},\n parameters: {\n layout: 'padded',\n } satisfies StoryParameters,\n}\n\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Primary: Story = {\n args: {} satisfies ${propsName},\n}\n`\n\tconst storyPath = storyPathForComponent(absCompPath)\n\twriteFileSync(storyPath, storyTpl, 'utf8')\n\tinfo(`scaffolded story → \\${rel(storyPath)}`)\n\treturn storyPath\n}\n\nfunction ensureStoryForComponent(absCompPath: string) {\n\tconst sPath = storyPathForComponent(absCompPath)\n\tif (existsSync(sPath)) return null\n\treturn scaffoldStoryForComponent(absCompPath)\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Svelte scaffolding\n// ───────────────────────────────────────────────────────────────────────────────\nfunction scaffoldSvelteComponent(absCompPath: string) {\n\tconst base = componentBaseFromSvelteComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\n\tconst tpl =\n\t\tSCAFFOLD_CONFIG?.svelte?.component?.({ componentName }) ??\n\t\t`<script lang=\"ts\">\n\timport type { Snippet } from 'svelte';\n\n\texport interface PropsFor${componentName} {\n\t\tchildren?: Snippet;\n\t}\n\n\tconst { children }: PropsFor${componentName} = $props();\n</script>\n\n<div class=\"${componentName}\">\n\t<p>${componentName}</p>\n\t{@render children?.()}\n</div>\n\n<style>\n\t.${componentName} {\n\t\t/* styles go here */\n\t}\n</style>\n`\n\twriteFileSync(absCompPath, tpl, 'utf8')\n\tinfo(`scaffolded svelte component → ${rel(absCompPath)}`)\n}\n\nfunction scaffoldSvelteDecorator(absDecoratorPath: string) {\n\tconst fullBase = componentBaseFromSvelteComponent(absDecoratorPath)\n\tconst wrappedBase = fullBase.split('.')[0] ?? fullBase\n\tconst componentName = toPascalCase(wrappedBase)\n\n\tconst tpl =\n\t\tSCAFFOLD_CONFIG?.svelte?.decorator?.({ componentName }) ??\n\t\t`<script lang=\"ts\">\n\timport ${componentName} from \"./${componentName}.svelte\";\n\n\tinterface DecoratorProps {\n\t}\n\n\tconst { }: DecoratorProps = $props();\n</script>\n\n<div class=\"decorator\">\n\t<${componentName} />\n</div>\n`\n\twriteFileSync(absDecoratorPath, tpl, 'utf8')\n\tinfo(`scaffolded svelte decorator → ${rel(absDecoratorPath)}`)\n}\n\nfunction makeTitleFromSvelteComponent(absCompPath: string) {\n\tconst srcRoot = join(projectRoot, SRC_DIR) + sep\n\tconst normAbs = absCompPath.replace(/\\\\/g, '/')\n\tconst relFromSrc = normAbs.startsWith(srcRoot.replace(/\\\\/g, '/'))\n\t\t? normAbs.slice(srcRoot.length)\n\t\t: absCompPath.replace(projectRoot + sep, '').replace(/\\\\/g, '/')\n\n\tconst dir = posix.dirname(relFromSrc)\n\tlet segments = dir.split('/').filter(Boolean)\n\tif (segments[0] && /^components?$/i.test(segments[0]))\n\t\tsegments = segments.slice(1)\n\n\tconst titledFolders = segments.map((s) => toTitleCase(toWords(s)))\n\tconst compName = componentBaseFromSvelteComponent(absCompPath)\n\tconst compTitle = toTitleCase(toWords(compName))\n\n\tconst fullStoryPath = [...titledFolders, compTitle].filter(Boolean)\n\n\t// remove duplicates (e.g. Folder/Thing/Thing => Folder/Thing)\n\tconst dedupedStoryPath = [...new Set(fullStoryPath)]\n\n\treturn dedupedStoryPath.join(' / ')\n}\n\nfunction scaffoldStoryForSvelteComponent(absCompPath: string) {\n\tconst base = componentBaseFromSvelteComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\tconst title = makeTitleFromSvelteComponent(absCompPath)\n\tconst atomic = detectAtomicTag(absCompPath)\n\tconst tags = ['autodocs']\n\tif (atomic) tags.push(atomic)\n\n\tconst storyTpl =\n\t\tSCAFFOLD_CONFIG?.svelte?.story?.({ componentName, title, tags }) ??\n\t\t`<script lang=\"ts\" module>\n\timport type { StoryParameters } from 'storybook-addon-dependency-previews'\n\timport ${componentName}, { type PropsFor${componentName} } from './${componentName}.svelte'\n\timport { defineMeta } from '@storybook/addon-svelte-csf';\n\n\tconst { Story } = defineMeta({\n\t\ttitle: '${title}',\n\t\tcomponent: ${componentName},\n\t\ttags: [${tags.map((t) => `'${t}'`).join(', ')}],\n\t\tparameters: {\n\t\t\tlayout: 'padded',\n\t\t} satisfies StoryParameters,\n\t})\n\ttype Args = Omit<PropsFor${componentName}, 'children'>;\n</script>\n\n<Story name=\"Primary\" args={{} satisfies Args}>\n\t<p>${title}</p>\n</Story>\n`\n\tconst storyPath = storyPathForSvelteComponent(absCompPath)\n\twriteFileSync(storyPath, storyTpl, 'utf8')\n\tinfo(`scaffolded svelte story → ${rel(storyPath)}`)\n\treturn storyPath\n}\n\nfunction ensureStoryForSvelteComponent(absCompPath: string) {\n\tconst sPath = storyPathForSvelteComponent(absCompPath)\n\tif (existsSync(sPath)) return null\n\treturn scaffoldStoryForSvelteComponent(absCompPath)\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Angular scaffolding\n// ───────────────────────────────────────────────────────────────────────────────\nfunction storyPathForAngularComponent(absCompPath: string) {\n\tconst dir = dirname(absCompPath)\n\tconst base = componentBaseFromAngularComponent(absCompPath)\n\treturn join(dir, `${base}.stories.ts`)\n}\n\nfunction makeTitleFromAngularComponent(absCompPath: string) {\n\tconst srcRoot = join(projectRoot, SRC_DIR) + sep\n\tconst normAbs = absCompPath.replace(/\\\\/g, '/')\n\tconst relFromSrc = normAbs.startsWith(srcRoot.replace(/\\\\/g, '/'))\n\t\t? normAbs.slice(srcRoot.length)\n\t\t: absCompPath.replace(projectRoot + sep, '').replace(/\\\\/g, '/')\n\n\tconst dir = posix.dirname(relFromSrc)\n\tlet segments = dir.split('/').filter(Boolean)\n\tif (segments[0] && /^components?$/i.test(segments[0]))\n\t\tsegments = segments.slice(1)\n\n\tconst titledFolders = segments.map((s) => toTitleCase(toWords(s)))\n\tconst compName = componentBaseFromAngularComponent(absCompPath)\n\tconst compTitle = toTitleCase(toWords(compName))\n\n\tconst fullStoryPath = [...titledFolders, compTitle].filter(Boolean)\n\n\t// remove duplicates (e.g. Folder/Thing/Thing => Folder/Thing)\n\tconst dedupedStoryPath = [...new Set(fullStoryPath)]\n\n\treturn dedupedStoryPath.join(' / ')\n}\n\nfunction gcd(a: number, b: number): number {\n\treturn b === 0 ? a : gcd(b, a % b)\n}\n\n/**\n * Re-indents extracted HTML so that each indent level is exactly one unit deep.\n * Detects whether the content uses tabs or spaces (and how many spaces per level)\n * and enforces that indentation only ever increases by one level at a time.\n */\nfunction normalizeHtmlIndentation(html: string): string {\n\tconst lines = html.split('\\n')\n\tconst indentedLines = lines.filter((l) => l.trim() && /^\\s/.test(l))\n\tif (indentedLines.length === 0) return html\n\n\tconst usesTabs = indentedLines.some((l) => l.startsWith('\\t'))\n\tlet unitSize: number\n\tlet unitChar: string\n\n\tif (usesTabs) {\n\t\tunitSize = 1\n\t\tunitChar = '\\t'\n\t} else {\n\t\tconst spaceCounts = indentedLines\n\t\t\t.map((l) => (l.match(/^ +/) ?? [''])[0].length)\n\t\t\t.filter((n) => n > 0)\n\t\tconst g = spaceCounts.reduce((a, b) => gcd(a, b), spaceCounts[0])\n\t\tunitSize = g\n\t\tunitChar = ' '.repeat(g)\n\t}\n\n\tconst rawLevels = lines.map((line) => {\n\t\tif (!line.trim()) return -1\n\t\tconst ws = line.match(/^(\\s*)/)?.[1] ?? ''\n\t\tif (usesTabs) return [...ws].filter((c) => c === '\\t').length\n\t\treturn Math.round(ws.length / unitSize)\n\t})\n\n\t// Normalize: enforce max +1 increase per step.\n\t// knownMappings stays sorted by rawLevel.\n\tconst knownMappings: Array<[number, number]> = [[0, 0]]\n\tlet prevRaw = 0\n\tlet prevNorm = 0\n\n\tconst normLevels = rawLevels.map((raw) => {\n\t\tif (raw === -1) return -1\n\t\tif (raw === prevRaw) return prevNorm\n\n\t\tif (raw > prevRaw) {\n\t\t\tconst existing = knownMappings.find(([r]) => r === raw)\n\t\t\tif (existing) {\n\t\t\t\t;[prevRaw, prevNorm] = [raw, existing[1]]\n\t\t\t\treturn prevNorm\n\t\t\t}\n\t\t\tprevNorm += 1\n\t\t\tprevRaw = raw\n\t\t\tconst insertIdx = knownMappings.findIndex(([r]) => r > raw)\n\t\t\tif (insertIdx === -1) knownMappings.push([raw, prevNorm])\n\t\t\telse knownMappings.splice(insertIdx, 0, [raw, prevNorm])\n\t\t\treturn prevNorm\n\t\t}\n\n\t\t// Decrease: find the largest known rawLevel <= current\n\t\tconst below = knownMappings.filter(([r]) => r <= raw)\n\t\tconst norm = below.length > 0 ? below[below.length - 1][1] : 0\n\t\t;[prevRaw, prevNorm] = [raw, norm]\n\t\treturn norm\n\t})\n\n\treturn lines\n\t\t.map((line, i) => {\n\t\t\tif (normLevels[i] === -1) return ''\n\t\t\treturn unitChar.repeat(normLevels[i]) + line.trimStart()\n\t\t})\n\t\t.join('\\n')\n}\n\nfunction defaultAngularHtmlTemplate(componentName: string) {\n\treturn (\n\t\tSCAFFOLD_CONFIG?.angular?.componentHtml?.({ componentName }) ??\n\t\t`<p>${componentName}</p>\n\t<ng-content />\n`\n\t)\n}\n\nfunction scaffoldAngularComponent(\n\tabsCompPath: string,\n\ttemplateLocation: 'internal' | 'external',\n) {\n\tconst base = componentBaseFromAngularComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\tconst className = `${componentName}Component`\n\tconst selector = ANGULAR_SELECTOR_PREFIX + toKebabCase(componentName)\n\tconst dir = dirname(absCompPath)\n\tconst tsPath = join(dir, `${base}.component.ts`)\n\tconst htmlPath = join(dir, `${base}.component.html`)\n\n\tif (!existsSync(tsPath) || isEmptyOrWhitespace(tsPath)) {\n\t\tconst defaultTsTpl =\n\t\t\ttemplateLocation === 'external'\n\t\t\t\t? `import { Component, input } from '@angular/core';\n\n@Component({\n\tselector: '${selector}',\n\thost: { '[class]': '[\"${componentName}\", class()].join(\" \")' },\n\ttemplateUrl: './${base}.component.html',\n\tstandalone: true,\n\timports: [],\n})\nexport class ${className} {\n class = input<string>('');\n}\n`\n\t\t\t\t: `import { Component, input } from '@angular/core';\n\n@Component({\n\tselector: '${selector}',\n\thost: { '[class]': '[\"${componentName}\", class()].join(\" \")' },\n\ttemplate: \\`\n\t\t<p>${componentName}</p>\n\t\t<ng-content />\n\t\\`,\n\tstandalone: true,\n\timports: [],\n})\nexport class ${className} {\n\tclass = input<string>('');\n}\n`\n\t\tconst tsTpl =\n\t\t\tSCAFFOLD_CONFIG?.angular?.component?.({\n\t\t\t\tcomponentName,\n\t\t\t\tclassName,\n\t\t\t\tselector,\n\t\t\t\tbase,\n\t\t\t\ttemplateLocation,\n\t\t\t}) ?? defaultTsTpl\n\t\twriteFileSync(tsPath, tsTpl, 'utf8')\n\t\tinfo(`scaffolded angular component → ${rel(tsPath)}`)\n\t}\n\n\t// Only scaffold the HTML file when using an external template\n\tif (\n\t\ttemplateLocation === 'external' &&\n\t\t(!existsSync(htmlPath) || isEmptyOrWhitespace(htmlPath))\n\t) {\n\t\twriteFileSync(htmlPath, defaultAngularHtmlTemplate(componentName), 'utf8')\n\t\tinfo(`scaffolded angular template → ${rel(htmlPath)}`)\n\t}\n}\n\nfunction scaffoldAngularHtmlFromTs(absHtmlPath: string, absTsPath: string) {\n\tconst base = componentBaseFromAngularComponent(absHtmlPath)\n\tconst componentName = toPascalCase(base)\n\n\tlet htmlContent: string | null = null\n\n\t// Try to extract inline template from the existing .ts file\n\tif (existsSync(absTsPath) && !isEmptyOrWhitespace(absTsPath)) {\n\t\tconst tsContent = readFileSync(absTsPath, 'utf8')\n\t\tconst match = tsContent.match(/template:\\s*`([\\s\\S]*?)`/)\n\t\tif (match) {\n\t\t\thtmlContent = normalizeHtmlIndentation(match[1].trim()) + '\\n'\n\t\t\t// Swap template: `...` → templateUrl in the .ts file\n\t\t\tconst updated = tsContent.replace(\n\t\t\t\t/template:\\s*`[\\s\\S]*?`/,\n\t\t\t\t`templateUrl: './${base}.component.html'`,\n\t\t\t)\n\t\t\twriteFileSync(absTsPath, updated, 'utf8')\n\t\t\tinfo(`updated angular component to use templateUrl → ${rel(absTsPath)}`)\n\t\t}\n\t}\n\n\t// Fall back to default scaffold\n\tif (htmlContent === null) {\n\t\thtmlContent = defaultAngularHtmlTemplate(componentName)\n\t}\n\n\twriteFileSync(absHtmlPath, htmlContent, 'utf8')\n\tinfo(`scaffolded angular template → ${rel(absHtmlPath)}`)\n}\n\nfunction scaffoldStoryForAngularComponent(absCompPath: string) {\n\tconst base = componentBaseFromAngularComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\tconst className = `${componentName}Component`\n\tconst title = makeTitleFromAngularComponent(absCompPath)\n\tconst atomic = detectAtomicTag(absCompPath)\n\tconst tags = ['autodocs']\n\tif (atomic) tags.push(atomic)\n\n\tconst storyTpl =\n\t\tSCAFFOLD_CONFIG?.angular?.story?.({\n\t\t\tcomponentName,\n\t\t\tclassName,\n\t\t\tbase,\n\t\t\ttitle,\n\t\t\ttags,\n\t\t}) ??\n\t\t`import type { Meta, StoryObj } from '@storybook/angular'\nimport type { StoryParameters } from 'storybook-addon-dependency-previews'\nimport { ${className} } from './${base}.component'\n\nconst meta: Meta<${className}> = {\n\ttitle: '${title}',\n\tcomponent: ${className},\n\ttags: ${JSON.stringify(tags)},\n\tparameters: {\n\t\tlayout: 'padded',\n\t} satisfies StoryParameters,\n}\n\nexport default meta\n\ntype Story = StoryObj<${className}>\n\nexport const Primary: Story = {\n\targs: {},\n}\n`\n\tconst storyPath = storyPathForAngularComponent(absCompPath)\n\twriteFileSync(storyPath, storyTpl, 'utf8')\n\tinfo(`scaffolded angular story → ${rel(storyPath)}`)\n\treturn storyPath\n}\n\nfunction ensureStoryForAngularComponent(absCompPath: string) {\n\tconst sPath = storyPathForAngularComponent(absCompPath)\n\tif (existsSync(sPath)) return null\n\treturn scaffoldStoryForAngularComponent(absCompPath)\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Watcher\n// ───────────────────────────────────────────────────────────────────────────────\nfunction startWatcher() {\n\tconst root = projectRoot\n\tconst includeGlobs = [\n\t\t'**/*.stories.{ts,tsx,js,jsx,mdx,svelte}',\n\t\t'**/*.story.{ts,tsx,js,jsx,mdx,svelte}',\n\t\t`${SRC_DIR}/**/*.{ts,tsx,js,jsx,svelte}`,\n\t\t`${SRC_DIR}/**/*.component.html`,\n\t\t'depcruise.config.cjs',\n\t\t'.dependency-cruiser.{js,cjs}',\n\t]\n\tconst ignoreGlobs = [\n\t\t'node_modules/**',\n\t\t'.git/**',\n\t\t'.storybook/**',\n\t\t'**/.cache/**',\n\t\t'**/dist/**',\n\t\t'**/build/**',\n\t]\n\n\tlet pending = false\n\tlet timer: NodeJS.Timeout | null = null\n\tlet isDeletingFile = false\n\n\tfunction kick(reason: string, absPath: string) {\n\t\tif (pending) return\n\t\tpending = true\n\t\tif (timer) clearTimeout(timer)\n\t\ttimer = setTimeout(() => {\n\t\t\tinfo(`${reason}: ${rel(absPath)}`)\n\t\t\tbuildOnce()\n\t\t\tpending = false\n\t\t}, 120)\n\t}\n\n\treturn watcherParcel\n\t\t.subscribe(\n\t\t\troot,\n\t\t\tasync (err, events) => {\n\t\t\t\tif (err) {\n\t\t\t\t\terror(`watch error ${err?.message || err}`)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tfor (const ev of events) {\n\t\t\t\t\tconst abs = ev.path\n\t\t\t\t\tconst relPath = rel(abs)\n\t\t\t\t\tif (!micromatch.isMatch(relPath, includeGlobs)) continue\n\n\t\t\t\t\tif (ev.type === 'delete') {\n\t\t\t\t\t\tconsole.log('Deleted:', relPath)\n\t\t\t\t\t\tisDeletingFile = true\n\t\t\t\t\t\tkick('unlink', abs)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// COMPONENT CREATE — scaffold if empty and ensure story\n\t\t\t\t\tif (isComponentsTsx(abs) && ev.type === 'create') {\n\t\t\t\t\t\tawait handleComponentCreation(abs, relPath)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// SVELTE COMPONENT CREATE — scaffold if empty and ensure story\n\t\t\t\t\tif (isComponentsSvelte(abs) && ev.type === 'create') {\n\t\t\t\t\t\tawait handleSvelteComponentCreation(abs, relPath)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// ANGULAR .component.ts CREATE — scaffold with inline template\n\t\t\t\t\tif (isComponentsAngularTs(abs) && ev.type === 'create') {\n\t\t\t\t\t\tawait handleAngularComponentCreation(abs, relPath, 'internal')\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// ANGULAR .component.html CREATE\n\t\t\t\t\tif (isComponentsAngularHtml(abs) && ev.type === 'create') {\n\t\t\t\t\t\tconst tsPath = angularComponentTsPath(abs)\n\t\t\t\t\t\tif (existsSync(tsPath) && !isEmptyOrWhitespace(tsPath)) {\n\t\t\t\t\t\t\t// .ts already exists — scaffold HTML from it (migrate inline template if present)\n\t\t\t\t\t\t\tif (isEmptyOrWhitespace(abs)) {\n\t\t\t\t\t\t\t\tscaffoldAngularHtmlFromTs(abs, tsPath)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconsole.log('Angular component creation detected:', rel(abs))\n\t\t\t\t\t\t\tconst createdStory = ensureStoryForAngularComponent(tsPath)\n\t\t\t\t\t\t\tif (createdStory) {\n\t\t\t\t\t\t\t\tkick('create:story', createdStory)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// .ts doesn't exist yet — existing behavior: scaffold both with external templateUrl\n\t\t\t\t\t\t\tawait handleAngularComponentCreation(\n\t\t\t\t\t\t\t\ttsPath,\n\t\t\t\t\t\t\t\trel(tsPath),\n\t\t\t\t\t\t\t\t'external',\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// normal rebuild\n\t\t\t\t\tkick(ev.type, abs)\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ ignore: ignoreGlobs },\n\t\t)\n\t\t.then((result) => {\n\t\t\tinfo('watching… (ready)')\n\t\t\treturn result\n\t\t})\n\t\t.catch((e) => error(`watch init failed ${e?.message || e}`))\n\n\tasync function handleComponentCreation(abs: string, relPath: string) {\n\t\tif (isEmptyOrWhitespace(abs)) {\n\t\t\tscaffoldComponent(abs)\n\t\t}\n\n\t\tconsole.log('Component creation detected:', relPath)\n\t\tconst createdStory = ensureStoryForComponent(abs)\n\t\tif (createdStory) {\n\t\t\tkick('create:story', createdStory)\n\t\t}\n\t}\n\n\tasync function handleSvelteComponentCreation(abs: string, relPath: string) {\n\t\tif (isDecoratorSvelte(abs)) {\n\t\t\tif (isEmptyOrWhitespace(abs)) {\n\t\t\t\tscaffoldSvelteDecorator(abs)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tif (isEmptyOrWhitespace(abs)) {\n\t\t\tscaffoldSvelteComponent(abs)\n\t\t}\n\n\t\tconst createdStory = ensureStoryForSvelteComponent(abs)\n\t\tif (createdStory) {\n\t\t\tkick('create:story', createdStory)\n\t\t}\n\t}\n\n\tasync function handleAngularComponentCreation(\n\t\tabs: string,\n\t\trelPath: string,\n\t\ttemplateStyle: 'internal' | 'external',\n\t) {\n\t\tif (isEmptyOrWhitespace(abs)) {\n\t\t\tscaffoldAngularComponent(abs, templateStyle)\n\t\t}\n\n\t\tconsole.log('Angular component creation detected:', relPath)\n\t\tconst createdStory = ensureStoryForAngularComponent(abs)\n\t\tif (createdStory) {\n\t\t\tkick('create:story', createdStory)\n\t\t}\n\t}\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Storybook child\n// ───────────────────────────────────────────────────────────────────────────────\nlet sbChild: ChildProcess | null = null\nasync function startStorybook() {\n\tconst isWin = process.platform === 'win32'\n\tlet cmd: string\n\tlet args: string[]\n\tlet shellMode: boolean\n\tif (SB_CUSTOM_CMD) {\n\t\tcmd = SB_CUSTOM_CMD\n\t\targs = []\n\t\tshellMode = true // shell:true handles quoted args and paths with spaces\n\t} else {\n\t\tcmd = 'npx'\n\t\targs = ['-y', 'storybook', 'dev', '-p', String(SB_PORT)]\n\t\tshellMode = isWin // ← critical to avoid EINVAL on Win + Git Bash\n\t}\n\n\tinfo(`[sb-deps] launching: ${cmd} ${args.join(' ')}`)\n\n\tsbChild = spawn(cmd, args, {\n\t\tcwd: projectRoot,\n\t\tstdio: 'inherit',\n\t\tshell: shellMode,\n\t\tenv: process.env,\n\t})\n\n\tsbChild.on('error', (err: any) => {\n\t\terror(`spawn failed: ${err?.message || err}`)\n\t})\n\n\tsbChild.on('exit', (code, sig) => {\n\t\tinfo(`storybook exited (${sig || code})`)\n\t\tsbChild = null\n\t})\n\n\tinfo(`storybook running on http://localhost:${SB_PORT}`)\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Boot\n// ───────────────────────────────────────────────────────────────────────────────\n;(async () => {\n\tif (SUBCOMMAND === 'setup') {\n\t\tawait runSetup(argv.slice(1))\n\t\treturn\n\t}\n\n\tconst cfg = await loadSbDepsConfig()\n\tANGULAR_SELECTOR_PREFIX = cfg.angularSelectorPrefix ?? 'app-'\n\tSCAFFOLD_CONFIG = cfg.scaffold ?? {}\n\t// `?? 'src'` only falls back on null/undefined, so an explicit `srcDir: ''`\n\t// in the user's config would slip through and produce overly-broad watcher\n\t// globs (`/**/*`) and an `--include-only \"^/\"` depcruise scan. Trim and\n\t// validate against a strict safe-character allow-list:\n\t//\n\t// - alphanumerics + `.`, `_`, `-` — covers every directory name people\n\t// conventionally use (`src`, `app`, `my-source`, `app.v2`, etc.)\n\t// - rejects glob metacharacters (`*`, `?`, `[`, `]`, `{`, `}`) that\n\t// would otherwise change watcher-glob matching when interpolated into\n\t// `${SRC_DIR}/**/*.{ts,...}`\n\t// - rejects path separators (`/`, `\\`) — srcDir must be a single segment\n\t// - rejects cmd.exe metacharacters including `%` (which triggers `%VAR%`\n\t// env expansion when the args go through a `cmd.exe`-invoked `.cmd`\n\t// shim on Windows) and `^` / `&` / `|` / `<` / `>` / `(` / `)` / `!`\n\t//\n\t// Bounding the input here means downstream interpolation sites (watcher\n\t// globs, dep-cruiser `--include-only` regex, scaffold-helper regexes) can\n\t// trust their `SRC_DIR` source and don't each need their own escape pass.\n\tconst rawSrcDir = (cfg.srcDir ?? 'src').replace(/[\\\\/]+$/, '').trim()\n\tconst SAFE_SRCDIR_PATTERN = /^[A-Za-z0-9._-]+$/\n\tif (!rawSrcDir || !SAFE_SRCDIR_PATTERN.test(rawSrcDir)) {\n\t\terror(\n\t\t\t`srcDir \"${cfg.srcDir ?? ''}\" is invalid — must be a single non-empty directory name containing only alphanumerics, \".\", \"_\", or \"-\" (e.g. \"src\", \"app\", \"my-source\"). Falling back to \"src\".`,\n\t\t)\n\t\tSRC_DIR = 'src'\n\t} else {\n\t\tSRC_DIR = rawSrcDir\n\t}\n\n\tbanner('sb-deps')\n\tinfo(`outDir: ${rel(outDir)}`)\n\tinfo(configPath ? `config: ${rel(configPath)}` : 'config: (none)')\n\tbuildOnce()\n\n\tlet watcher: watcherParcel.AsyncSubscription | null = null\n\tif (WATCH) startWatcher().then((w) => (watcher = w || null))\n\tif (RUN_SB) startStorybook()\n\n\tprocess.on('SIGINT', async () => {\n\t\tinfo('shutting down…')\n\t\tawait watcher?.unsubscribe()\n\t\tsbChild?.kill('SIGINT')\n\t\tprocess.exit(0)\n\t})\n})()\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Utils\n// ───────────────────────────────────────────────────────────────────────────────\nfunction rel(p: string) {\n\t// remove the projectRoot prefix and normalize slashes for logs\n\tconst prefix = resolve(projectRoot) + sep\n\treturn p.replace(prefix, '')\n}\nfunction ms(n: number) {\n\treturn `${Math.max(1, Math.round(n))}ms`\n}\nfunction info(msg: string) {\n\tconsole.log('[sb-deps]', msg)\n}\nfunction error(msg: string) {\n\tconsole.error('[sb-deps]', msg)\n}\nfunction banner(title: string) {\n\tconsole.log(`\\n${title} – dependency previews\\n`)\n}\nfunction wait(time = 500) {\n\treturn new Promise((r) => setTimeout(r, time))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sb-deps.cjs","names":["__filename","__dirname","SCAFFOLD_CONFIG: SbDepsConfig['scaffold']","args: Array<string>","best: null | { val: string; idx: number }","sep","posix","unitSize: number","unitChar: string","knownMappings: Array<[number, number]>","htmlContent: string | null","timer: NodeJS.Timeout | null","watcherParcel","sbChild: ChildProcess | null","cmd: string","args: string[]","shellMode: boolean","runSetup","watcher: watcherParcel.AsyncSubscription | null"],"sources":["../../cli/sb-deps.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/* eslint-disable no-console */\nimport watcherParcel from '@parcel/watcher'\nimport micromatch from 'micromatch'\nimport { execFileSync, spawn, type ChildProcess } from 'node:child_process'\nimport {\n\texistsSync,\n\tmkdirSync,\n\treadFileSync,\n\tstatSync,\n\twriteFileSync,\n} from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { basename, dirname, join, posix, resolve, sep } from 'node:path'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport type { SbDepsConfig } from '../src/config.js'\nimport { runSetup } from './setup/index.js'\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Args\n// ───────────────────────────────────────────────────────────────────────────────\nconst argv = process.argv.slice(2)\nconst SUBCOMMAND = argv[0] && !argv[0].startsWith('--') ? argv[0] : null\nconst WATCH = argv.includes('--watch')\nconst RUN_SB_IDX = argv.indexOf('--run-storybook')\nconst RUN_SB = RUN_SB_IDX !== -1\nconst _RUN_SB_NEXT = RUN_SB ? argv[RUN_SB_IDX + 1] : undefined\nconst SB_CUSTOM_CMD =\n\t_RUN_SB_NEXT && !_RUN_SB_NEXT.startsWith('--') ? _RUN_SB_NEXT : undefined\nconst PORT_ARGI = argv.indexOf('--sb-port')\nconst SB_PORT =\n\tPORT_ARGI !== -1 && argv[PORT_ARGI + 1]\n\t\t? Number(argv[PORT_ARGI + 1]) || 6006\n\t\t: 6006\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Paths\n// ───────────────────────────────────────────────────────────────────────────────\nconst projectRoot = process.cwd()\nconst outDir = resolve(projectRoot, '.storybook')\nconst rawPath = join(outDir, 'dependency-previews.raw.json')\nconst cookedPath = join(outDir, 'dependency-previews.json')\n\n// Don't auto-create `.storybook/` for the setup subcommand — the wizard needs to\n// detect whether Storybook has been initialised so it can guide the user. The\n// regular build/watch path still needs the directory to exist for its JSON output.\nif (SUBCOMMAND !== 'setup' && !existsSync(outDir))\n\tmkdirSync(outDir, { recursive: true })\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\n// Resolve depcruise config: prefer project overrides, else bundled default\nconst pkgDefault = resolve(__dirname, 'scripts', 'depcruise.config.cjs')\nconst overrideCandidates = [\n\tresolve(projectRoot, 'depcruise.config.cjs'),\n\tresolve(projectRoot, '.dependency-cruiser.js'),\n\tresolve(projectRoot, '.dependency-cruiser.cjs'),\n]\nconst configPath =\n\toverrideCandidates.find((p) => existsSync(p)) ||\n\t(existsSync(pkgDefault) ? pkgDefault : null)\n\n// Path to postprocess helper (built as ESM)\nconst post = resolve(__dirname, 'scripts', 'postprocess.mjs')\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Config\n// ───────────────────────────────────────────────────────────────────────────────\nfunction checkIsProjectEsm(): boolean {\n\ttry {\n\t\tconst pkg = JSON.parse(\n\t\t\treadFileSync(resolve(projectRoot, 'package.json'), 'utf8'),\n\t\t)\n\t\treturn pkg.type === 'module'\n\t} catch {\n\t\treturn false\n\t}\n}\n\nasync function loadSbDepsConfig(): Promise<SbDepsConfig> {\n\tconst candidates = [\n\t\t{\n\t\t\tpath: resolve(projectRoot, 'sb-deps.config.js'),\n\t\t\tisEsm: checkIsProjectEsm(),\n\t\t},\n\t\t{ path: resolve(projectRoot, 'sb-deps.config.mjs'), isEsm: true },\n\t\t{ path: resolve(projectRoot, 'sb-deps.config.cjs'), isEsm: false },\n\t]\n\tfor (const { path: cfgPath, isEsm } of candidates) {\n\t\tif (!existsSync(cfgPath)) continue\n\t\ttry {\n\t\t\tif (isEsm) {\n\t\t\t\tconst mod = await import(pathToFileURL(cfgPath).href)\n\t\t\t\treturn (mod.default ?? mod) as SbDepsConfig\n\t\t\t} else {\n\t\t\t\tconst req = createRequire(import.meta.url)\n\t\t\t\tconst mod = req(cfgPath)\n\t\t\t\treturn (mod?.default ?? mod) as SbDepsConfig\n\t\t\t}\n\t\t} catch (e) {\n\t\t\terror(`failed to load sb-deps config: ${e}`)\n\t\t}\n\t}\n\treturn {}\n}\n\nlet ANGULAR_SELECTOR_PREFIX = 'app-'\nlet SCAFFOLD_CONFIG: SbDepsConfig['scaffold'] = {}\nlet SRC_DIR = 'src'\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Runners\n// ───────────────────────────────────────────────────────────────────────────────\nconst IS_WIN = process.platform === 'win32'\n\n/**\n * Locate the `dependency-cruiser` CLI binary in the user's `node_modules/.bin`.\n * Returns the absolute path with the right extension for the platform (`.cmd`\n * shim on Windows, bare name elsewhere). Falls back to `null` if it can't be\n * found — caller decides what to do.\n *\n * Going through the resolved binary lets us call `execFileSync` directly\n * (with `shell: false`) and pass each flag as its own array element — no\n * shell quoting, no `cmd.exe` metacharacter mangling (`^` is a `cmd.exe`\n * escape character, which would silently strip the `^` anchor from our\n * `--include-only` regex if we went through a shell). It also avoids spawning\n * `npx`, which on Windows is a `.cmd` shim that requires `shell: true` to\n * launch — which would reintroduce the very quoting problem we're trying to\n * avoid.\n */\nfunction resolveDepCruiseBin(): string | null {\n\tconst bin = join(\n\t\tprojectRoot,\n\t\t'node_modules',\n\t\t'.bin',\n\t\tIS_WIN ? 'depcruise.cmd' : 'depcruise',\n\t)\n\treturn existsSync(bin) ? bin : null\n}\n\nfunction runDepCruiseOnce() {\n\t// Pass --include-only at the CLI level so it overrides whatever the loaded\n\t// depcruise config has (depcruise CLI flags take precedence over config-file\n\t// options). That way SRC_DIR controls dep-cruiser's scan scope without\n\t// requiring users with non-`src` layouts to also override the bundled config.\n\t//\n\t// The regex must escape any regex metacharacters in SRC_DIR (a value like\n\t// `src.app` would otherwise broaden the scope unintentionally) and anchor\n\t// to a `/` so the directory boundary is respected — without the trailing\n\t// slash `^src` would also match `src2/`, `srcabc/`, etc.\n\t//\n\t// The empty-srcDir case (project root *is* the source folder) needs a\n\t// different shape: anchoring on `^/` would still walk node_modules, so\n\t// switch to a node_modules denylist via negative lookahead that rejects\n\t// `node_modules` as any path segment — covers nested\n\t// `packages/foo/node_modules/...` paths in monorepos, not just the\n\t// top-level folder.\n\tconst includeOnly =\n\t\tSRC_DIR === ''\n\t\t\t? '^(?!(?:[^/]*/)*node_modules/)'\n\t\t\t: `^${SRC_DIR.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}/`\n\tconst args: Array<string> = ['.']\n\tif (configPath) {\n\t\targs.push('--config', configPath)\n\t} else {\n\t\targs.push('--no-config')\n\t}\n\targs.push('--include-only', includeOnly, '--output-type', 'json')\n\n\tconst depcruiseBin = resolveDepCruiseBin()\n\tif (!depcruiseBin) {\n\t\tthrow new Error(\n\t\t\t'Could not locate `dependency-cruiser` in node_modules/.bin. Run the setup wizard (`sb-deps setup`) or install `dependency-cruiser` as a dev dependency.',\n\t\t)\n\t}\n\n\tconst start = Date.now()\n\t// `.cmd` shims on Windows need `shell: true` to launch, BUT once shell is\n\t// on, cmd.exe re-interprets `^` as an escape character — which would strip\n\t// the anchor from our regex. Workaround: spawn the `.cmd` itself with\n\t// shell:true (cmd.exe wraps the call) and pre-escape `^` for cmd.exe by\n\t// doubling it. On Unix the binary is a real ELF/script (no shim), shell:false\n\t// is the default, args pass through unmolested.\n\tconst stdout = execFileSync(\n\t\tdepcruiseBin,\n\t\tIS_WIN ? args.map(escapeForCmdExe) : args,\n\t\t{\n\t\t\tcwd: projectRoot,\n\t\t\tstdio: ['ignore', 'pipe', 'inherit'],\n\t\t\tencoding: 'utf8',\n\t\t\tshell: IS_WIN,\n\t\t\t// Pass SRC_DIR through to the bundled `depcruise.config.ts` so its\n\t\t\t// `forbidden` rules' path matchers (currently anchored on `^src`)\n\t\t\t// rebuild from the configured srcDir at depcruise's module-load time.\n\t\t\t// User-provided depcruise configs that ignore this env still work —\n\t\t\t// they just won't track srcDir automatically.\n\t\t\tenv: { ...process.env, SB_DEPS_SRC_DIR: SRC_DIR },\n\t\t},\n\t)\n\twriteFileSync(rawPath, stdout, 'utf8')\n\tinfo(`graph ✓ (${ms(Date.now() - start)})`)\n}\n\nfunction postprocessOnce() {\n\tconst start = Date.now()\n\t// `node` is a real executable on every platform (no `.cmd` shim), so we\n\t// don't need shell:true here — args pass through directly with no quoting\n\t// or escape concerns.\n\texecFileSync('node', [post, rawPath, cookedPath, SRC_DIR], {\n\t\tcwd: projectRoot,\n\t\tstdio: 'inherit',\n\t})\n\tinfo(`compiled ✓ → ${rel(cookedPath)} (${ms(Date.now() - start)})`)\n}\n\n/**\n * Escape an argument so that it survives `cmd.exe` parsing when `execFileSync`\n * is invoked with `shell: true` on Windows. `^` is the cmd.exe escape character,\n * even inside double quotes — doubling it makes cmd.exe pass through a literal\n * `^`. Other shell metacharacters (`&`, `|`, `<`, `>`, `(`, `)`, `%`, `!`) are\n * already wrapped in double quotes by Node's internal arg-quoter when\n * `shell: true`, so we only need to handle `^` ourselves.\n */\nfunction escapeForCmdExe(arg: string): string {\n\treturn arg.replace(/\\^/g, '^^')\n}\n\nfunction buildOnce() {\n\ttry {\n\t\trunDepCruiseOnce()\n\t\tpostprocessOnce()\n\t} catch (e) {\n\t\terror('build failed')\n\t\tif (!WATCH) throw e\n\t}\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// String utils\n// ───────────────────────────────────────────────────────────────────────────────\nfunction toWords(input: string) {\n\treturn String(input)\n\t\t.replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n\t\t.replace(/[_\\-./]+/g, ' ')\n\t\t.trim()\n\t\t.split(/\\s+/)\n}\nfunction toTitleCase(words: Array<string>) {\n\treturn words.map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')\n}\nfunction toPascalCase(input: string) {\n\treturn toTitleCase(toWords(input)).replace(/\\s+/g, '')\n}\nfunction toKebabCase(input: string) {\n\treturn toWords(input)\n\t\t.map((w) => w.toLowerCase())\n\t\t.join('-')\n}\n\nfunction isEmptyOrWhitespace(absPath: string) {\n\ttry {\n\t\tconst s = statSync(absPath)\n\t\tif (s.size === 0) return true\n\t\tconst txt = readFileSync(absPath, 'utf8')\n\t\treturn !txt.trim()\n\t} catch {\n\t\treturn true\n\t}\n}\n\n/**\n * Build a regex that matches `<SRC_DIR>/...<suffix>` for the scaffolding-trigger\n * helpers below. `SRC_DIR` is interpolated at call time (these helpers run\n * inside the watcher event loop, after the boot block has loaded the config\n * and finalised `SRC_DIR`).\n *\n * Files don't have to live under a `components/` subfolder — same philosophy\n * as the postprocess filter: any source file under `srcDir` with the right\n * extension is a candidate. The framework-agnostic story-file exclusion\n * (`STORY_FILE_REGEX`) is applied separately in the individual helpers.\n */\nfunction srcSubpathRegex(suffixPattern: string): RegExp {\n\t// Empty SRC_DIR (project root *is* the source folder) means there is no\n\t// subfolder gate — match any path that ends with the given suffix. The\n\t// watcher's ignore list (node_modules, .git, dist, build) keeps the noise\n\t// out before paths ever reach here, so a permissive regex is fine.\n\tif (SRC_DIR === '') {\n\t\treturn new RegExp(`.+${suffixPattern}`, 'i')\n\t}\n\tconst escapedSrcDir = SRC_DIR.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\treturn new RegExp(`(?:^|\\\\/)${escapedSrcDir}\\\\/.+${suffixPattern}`, 'i')\n}\n\n/**\n * Matches story files in any framework: `.story.<ext>` or `.stories.<ext>`\n * where `<ext>` is any single-segment file extension (`.svelte`, `.ts`, `.tsx`,\n * `.js`, `.jsx`, `.mdx`, …). Used by the scaffolding-trigger helpers to make\n * sure they don't try to auto-scaffold a story file for an existing story.\n */\nconst STORY_FILE_REGEX = /\\.stories?\\.\\w+$/i\n\n// <srcDir>/**/Thing.tsx ? (and not a story file)\nfunction isComponentsTsx(absPath: string) {\n\tconst norm = absPath.replace(/\\\\/g, '/')\n\treturn srcSubpathRegex('\\\\.tsx$').test(norm) && !STORY_FILE_REGEX.test(norm)\n}\n\n// <srcDir>/**/Thing.svelte ? (and not a story file)\nfunction isComponentsSvelte(absPath: string) {\n\tconst norm = absPath.replace(/\\\\/g, '/')\n\treturn (\n\t\tsrcSubpathRegex('\\\\.svelte$').test(norm) && !STORY_FILE_REGEX.test(norm)\n\t)\n}\n\n// <srcDir>/**/Thing.decorator.svelte ?\nfunction isDecoratorSvelte(absPath: string) {\n\tconst norm = absPath.replace(/\\\\/g, '/')\n\treturn srcSubpathRegex('\\\\.decorator\\\\.svelte$').test(norm)\n}\n\n// <srcDir>/**/Thing.component.ts ?\nfunction isComponentsAngularTs(absPath: string) {\n\tconst norm = absPath.replace(/\\\\/g, '/')\n\treturn srcSubpathRegex('\\\\.component\\\\.ts$').test(norm)\n}\n\n// <srcDir>/**/Thing.component.html ?\nfunction isComponentsAngularHtml(absPath: string) {\n\tconst norm = absPath.replace(/\\\\/g, '/')\n\treturn srcSubpathRegex('\\\\.component\\\\.html$').test(norm)\n}\n\nfunction componentBaseFromComponent(absCompPath: string) {\n\treturn basename(absCompPath, '.tsx')\n}\n\nfunction componentBaseFromSvelteComponent(absCompPath: string) {\n\treturn basename(absCompPath, '.svelte')\n}\n\nfunction componentBaseFromAngularComponent(absCompPath: string) {\n\treturn basename(absCompPath).replace(/\\.component\\.(ts|html)$/i, '')\n}\n\nfunction angularComponentTsPath(absPath: string) {\n\tconst base = componentBaseFromAngularComponent(absPath)\n\treturn join(dirname(absPath), `${base}.component.ts`)\n}\n\nfunction detectAtomicTag(absPath: string) {\n\tconst adaptedPath = absPath.toLowerCase().replace(/\\\\/g, '/')\n\tconst tokens = ['atom', 'molecule', 'organism', 'template', 'page', 'icon']\n\tlet best: null | { val: string; idx: number } = null\n\tfor (const t of tokens) {\n\t\tconst idx = adaptedPath.lastIndexOf(t)\n\t\tif (idx !== -1 && (best === null || idx > best.idx)) best = { val: t, idx }\n\t}\n\treturn best ? best.val : null\n}\n\nfunction storyPathForComponent(absCompPath: string) {\n\tconst dir = dirname(absCompPath)\n\tconst base = componentBaseFromComponent(absCompPath)\n\treturn join(dir, `${base}.stories.tsx`)\n}\n\nfunction storyPathForSvelteComponent(absCompPath: string) {\n\tconst dir = dirname(absCompPath)\n\tconst base = componentBaseFromSvelteComponent(absCompPath)\n\treturn join(dir, `${base}.stories.svelte`)\n}\n\nfunction makeTitleFromComponent(absCompPath: string) {\n\tconst srcRoot = join(projectRoot, SRC_DIR) + sep\n\tconst normAbs = absCompPath.replace(/\\\\/g, '/')\n\tconst relFromSrc = normAbs.startsWith(srcRoot.replace(/\\\\/g, '/'))\n\t\t? normAbs.slice(srcRoot.length)\n\t\t: absCompPath.replace(projectRoot + sep, '').replace(/\\\\/g, '/')\n\n\tconst dir = posix.dirname(relFromSrc)\n\tlet segments = dir.split('/').filter(Boolean)\n\tif (segments[0] && /^components?$/i.test(segments[0]))\n\t\tsegments = segments.slice(1)\n\n\tconst titledFolders = segments.map((s) => toTitleCase(toWords(s)))\n\tconst compName = componentBaseFromComponent(absCompPath)\n\tconst compTitle = toTitleCase(toWords(compName))\n\n\tconst fullStoryPath = [...titledFolders, compTitle].filter(Boolean)\n\n\t// remove duplicates (e.g. Folder/Thing/Thing => Folder/Thing)\n\tconst dedupedStoryPath = [...new Set(fullStoryPath)]\n\n\treturn dedupedStoryPath.join(' / ')\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Story & component scaffolding\n// ───────────────────────────────────────────────────────────────────────────────\nfunction scaffoldComponent(absCompPath: string) {\n\tconst base = componentBaseFromComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\tconst propsName = `PropsFor${componentName}`\n\n\tconst tpl =\n\t\tSCAFFOLD_CONFIG?.react?.component?.({ componentName, propsName }) ??\n\t\t`import type { ReactNode } from 'react'\n\nexport interface ${propsName} {\n children?: ReactNode\n}\n\nexport function ${componentName}({ children }: ${propsName}) {\n return (\n <div className=\"${componentName}\">\n <p>${componentName}</p>\n {children}\n </div>\n )\n}\n`\n\twriteFileSync(absCompPath, tpl, 'utf8')\n\tinfo(`scaffolded component → \\${rel(absCompPath)}`)\n}\n\nfunction scaffoldStoryForComponent(absCompPath: string) {\n\tconst base = componentBaseFromComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\tconst propsName = `PropsFor${componentName}`\n\tconst title = makeTitleFromComponent(absCompPath)\n\tconst atomic = detectAtomicTag(absCompPath)\n\tconst tags = ['autodocs']\n\tif (atomic) tags.push(atomic)\n\n\tconst storyTpl =\n\t\tSCAFFOLD_CONFIG?.react?.story?.({\n\t\t\tcomponentName,\n\t\t\tpropsName,\n\t\t\ttitle,\n\t\t\ttags,\n\t\t\tbase,\n\t\t}) ??\n\t\t`import type { Meta, StoryObj } from '@storybook/react-vite'\nimport type { StoryParameters } from 'storybook-addon-dependency-previews'\nimport { ${componentName}, type ${propsName} } from './${componentName}'\n\nconst meta: Meta<typeof ${componentName}> = {\n title: '${title}',\n component: ${componentName},\n tags: ${JSON.stringify(tags)},\n parameters: {\n layout: 'padded',\n } satisfies StoryParameters,\n}\n\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const Primary: Story = {\n args: {} satisfies ${propsName},\n}\n`\n\tconst storyPath = storyPathForComponent(absCompPath)\n\twriteFileSync(storyPath, storyTpl, 'utf8')\n\tinfo(`scaffolded story → \\${rel(storyPath)}`)\n\treturn storyPath\n}\n\nfunction ensureStoryForComponent(absCompPath: string) {\n\tconst sPath = storyPathForComponent(absCompPath)\n\tif (existsSync(sPath)) return null\n\treturn scaffoldStoryForComponent(absCompPath)\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Svelte scaffolding\n// ───────────────────────────────────────────────────────────────────────────────\nfunction scaffoldSvelteComponent(absCompPath: string) {\n\tconst base = componentBaseFromSvelteComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\n\tconst tpl =\n\t\tSCAFFOLD_CONFIG?.svelte?.component?.({ componentName }) ??\n\t\t`<script lang=\"ts\">\n\timport type { Snippet } from 'svelte';\n\n\texport interface PropsFor${componentName} {\n\t\tchildren?: Snippet;\n\t}\n\n\tconst { children }: PropsFor${componentName} = $props();\n</script>\n\n<div class=\"${componentName}\">\n\t<p>${componentName}</p>\n\t{@render children?.()}\n</div>\n\n<style>\n\t.${componentName} {\n\t\t/* styles go here */\n\t}\n</style>\n`\n\twriteFileSync(absCompPath, tpl, 'utf8')\n\tinfo(`scaffolded svelte component → ${rel(absCompPath)}`)\n}\n\nfunction scaffoldSvelteDecorator(absDecoratorPath: string) {\n\tconst fullBase = componentBaseFromSvelteComponent(absDecoratorPath)\n\tconst wrappedBase = fullBase.split('.')[0] ?? fullBase\n\tconst componentName = toPascalCase(wrappedBase)\n\n\tconst tpl =\n\t\tSCAFFOLD_CONFIG?.svelte?.decorator?.({ componentName }) ??\n\t\t`<script lang=\"ts\">\n\timport ${componentName} from \"./${componentName}.svelte\";\n\n\tinterface DecoratorProps {\n\t}\n\n\tconst { }: DecoratorProps = $props();\n</script>\n\n<div class=\"decorator\">\n\t<${componentName} />\n</div>\n`\n\twriteFileSync(absDecoratorPath, tpl, 'utf8')\n\tinfo(`scaffolded svelte decorator → ${rel(absDecoratorPath)}`)\n}\n\nfunction makeTitleFromSvelteComponent(absCompPath: string) {\n\tconst srcRoot = join(projectRoot, SRC_DIR) + sep\n\tconst normAbs = absCompPath.replace(/\\\\/g, '/')\n\tconst relFromSrc = normAbs.startsWith(srcRoot.replace(/\\\\/g, '/'))\n\t\t? normAbs.slice(srcRoot.length)\n\t\t: absCompPath.replace(projectRoot + sep, '').replace(/\\\\/g, '/')\n\n\tconst dir = posix.dirname(relFromSrc)\n\tlet segments = dir.split('/').filter(Boolean)\n\tif (segments[0] && /^components?$/i.test(segments[0]))\n\t\tsegments = segments.slice(1)\n\n\tconst titledFolders = segments.map((s) => toTitleCase(toWords(s)))\n\tconst compName = componentBaseFromSvelteComponent(absCompPath)\n\tconst compTitle = toTitleCase(toWords(compName))\n\n\tconst fullStoryPath = [...titledFolders, compTitle].filter(Boolean)\n\n\t// remove duplicates (e.g. Folder/Thing/Thing => Folder/Thing)\n\tconst dedupedStoryPath = [...new Set(fullStoryPath)]\n\n\treturn dedupedStoryPath.join(' / ')\n}\n\nfunction scaffoldStoryForSvelteComponent(absCompPath: string) {\n\tconst base = componentBaseFromSvelteComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\tconst title = makeTitleFromSvelteComponent(absCompPath)\n\tconst atomic = detectAtomicTag(absCompPath)\n\tconst tags = ['autodocs']\n\tif (atomic) tags.push(atomic)\n\n\tconst storyTpl =\n\t\tSCAFFOLD_CONFIG?.svelte?.story?.({ componentName, title, tags }) ??\n\t\t`<script lang=\"ts\" module>\n\timport type { StoryParameters } from 'storybook-addon-dependency-previews'\n\timport ${componentName}, { type PropsFor${componentName} } from './${componentName}.svelte'\n\timport { defineMeta } from '@storybook/addon-svelte-csf';\n\n\tconst { Story } = defineMeta({\n\t\ttitle: '${title}',\n\t\tcomponent: ${componentName},\n\t\ttags: [${tags.map((t) => `'${t}'`).join(', ')}],\n\t\tparameters: {\n\t\t\tlayout: 'padded',\n\t\t} satisfies StoryParameters,\n\t})\n\ttype Args = Omit<PropsFor${componentName}, 'children'>;\n</script>\n\n<Story name=\"Primary\" args={{} satisfies Args}>\n\t<p>${title}</p>\n</Story>\n`\n\tconst storyPath = storyPathForSvelteComponent(absCompPath)\n\twriteFileSync(storyPath, storyTpl, 'utf8')\n\tinfo(`scaffolded svelte story → ${rel(storyPath)}`)\n\treturn storyPath\n}\n\nfunction ensureStoryForSvelteComponent(absCompPath: string) {\n\tconst sPath = storyPathForSvelteComponent(absCompPath)\n\tif (existsSync(sPath)) return null\n\treturn scaffoldStoryForSvelteComponent(absCompPath)\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Angular scaffolding\n// ───────────────────────────────────────────────────────────────────────────────\nfunction storyPathForAngularComponent(absCompPath: string) {\n\tconst dir = dirname(absCompPath)\n\tconst base = componentBaseFromAngularComponent(absCompPath)\n\treturn join(dir, `${base}.stories.ts`)\n}\n\nfunction makeTitleFromAngularComponent(absCompPath: string) {\n\tconst srcRoot = join(projectRoot, SRC_DIR) + sep\n\tconst normAbs = absCompPath.replace(/\\\\/g, '/')\n\tconst relFromSrc = normAbs.startsWith(srcRoot.replace(/\\\\/g, '/'))\n\t\t? normAbs.slice(srcRoot.length)\n\t\t: absCompPath.replace(projectRoot + sep, '').replace(/\\\\/g, '/')\n\n\tconst dir = posix.dirname(relFromSrc)\n\tlet segments = dir.split('/').filter(Boolean)\n\tif (segments[0] && /^components?$/i.test(segments[0]))\n\t\tsegments = segments.slice(1)\n\n\tconst titledFolders = segments.map((s) => toTitleCase(toWords(s)))\n\tconst compName = componentBaseFromAngularComponent(absCompPath)\n\tconst compTitle = toTitleCase(toWords(compName))\n\n\tconst fullStoryPath = [...titledFolders, compTitle].filter(Boolean)\n\n\t// remove duplicates (e.g. Folder/Thing/Thing => Folder/Thing)\n\tconst dedupedStoryPath = [...new Set(fullStoryPath)]\n\n\treturn dedupedStoryPath.join(' / ')\n}\n\nfunction gcd(a: number, b: number): number {\n\treturn b === 0 ? a : gcd(b, a % b)\n}\n\n/**\n * Re-indents extracted HTML so that each indent level is exactly one unit deep.\n * Detects whether the content uses tabs or spaces (and how many spaces per level)\n * and enforces that indentation only ever increases by one level at a time.\n */\nfunction normalizeHtmlIndentation(html: string): string {\n\tconst lines = html.split('\\n')\n\tconst indentedLines = lines.filter((l) => l.trim() && /^\\s/.test(l))\n\tif (indentedLines.length === 0) return html\n\n\tconst usesTabs = indentedLines.some((l) => l.startsWith('\\t'))\n\tlet unitSize: number\n\tlet unitChar: string\n\n\tif (usesTabs) {\n\t\tunitSize = 1\n\t\tunitChar = '\\t'\n\t} else {\n\t\tconst spaceCounts = indentedLines\n\t\t\t.map((l) => (l.match(/^ +/) ?? [''])[0].length)\n\t\t\t.filter((n) => n > 0)\n\t\tconst g = spaceCounts.reduce((a, b) => gcd(a, b), spaceCounts[0])\n\t\tunitSize = g\n\t\tunitChar = ' '.repeat(g)\n\t}\n\n\tconst rawLevels = lines.map((line) => {\n\t\tif (!line.trim()) return -1\n\t\tconst ws = line.match(/^(\\s*)/)?.[1] ?? ''\n\t\tif (usesTabs) return [...ws].filter((c) => c === '\\t').length\n\t\treturn Math.round(ws.length / unitSize)\n\t})\n\n\t// Normalize: enforce max +1 increase per step.\n\t// knownMappings stays sorted by rawLevel.\n\tconst knownMappings: Array<[number, number]> = [[0, 0]]\n\tlet prevRaw = 0\n\tlet prevNorm = 0\n\n\tconst normLevels = rawLevels.map((raw) => {\n\t\tif (raw === -1) return -1\n\t\tif (raw === prevRaw) return prevNorm\n\n\t\tif (raw > prevRaw) {\n\t\t\tconst existing = knownMappings.find(([r]) => r === raw)\n\t\t\tif (existing) {\n\t\t\t\t;[prevRaw, prevNorm] = [raw, existing[1]]\n\t\t\t\treturn prevNorm\n\t\t\t}\n\t\t\tprevNorm += 1\n\t\t\tprevRaw = raw\n\t\t\tconst insertIdx = knownMappings.findIndex(([r]) => r > raw)\n\t\t\tif (insertIdx === -1) knownMappings.push([raw, prevNorm])\n\t\t\telse knownMappings.splice(insertIdx, 0, [raw, prevNorm])\n\t\t\treturn prevNorm\n\t\t}\n\n\t\t// Decrease: find the largest known rawLevel <= current\n\t\tconst below = knownMappings.filter(([r]) => r <= raw)\n\t\tconst norm = below.length > 0 ? below[below.length - 1][1] : 0\n\t\t;[prevRaw, prevNorm] = [raw, norm]\n\t\treturn norm\n\t})\n\n\treturn lines\n\t\t.map((line, i) => {\n\t\t\tif (normLevels[i] === -1) return ''\n\t\t\treturn unitChar.repeat(normLevels[i]) + line.trimStart()\n\t\t})\n\t\t.join('\\n')\n}\n\nfunction defaultAngularHtmlTemplate(componentName: string) {\n\treturn (\n\t\tSCAFFOLD_CONFIG?.angular?.componentHtml?.({ componentName }) ??\n\t\t`<p>${componentName}</p>\n\t<ng-content />\n`\n\t)\n}\n\nfunction scaffoldAngularComponent(\n\tabsCompPath: string,\n\ttemplateLocation: 'internal' | 'external',\n) {\n\tconst base = componentBaseFromAngularComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\tconst className = `${componentName}Component`\n\tconst selector = ANGULAR_SELECTOR_PREFIX + toKebabCase(componentName)\n\tconst dir = dirname(absCompPath)\n\tconst tsPath = join(dir, `${base}.component.ts`)\n\tconst htmlPath = join(dir, `${base}.component.html`)\n\n\tif (!existsSync(tsPath) || isEmptyOrWhitespace(tsPath)) {\n\t\tconst defaultTsTpl =\n\t\t\ttemplateLocation === 'external'\n\t\t\t\t? `import { Component, input } from '@angular/core';\n\n@Component({\n\tselector: '${selector}',\n\thost: { '[class]': '[\"${componentName}\", class()].join(\" \")' },\n\ttemplateUrl: './${base}.component.html',\n\tstandalone: true,\n\timports: [],\n})\nexport class ${className} {\n class = input<string>('');\n}\n`\n\t\t\t\t: `import { Component, input } from '@angular/core';\n\n@Component({\n\tselector: '${selector}',\n\thost: { '[class]': '[\"${componentName}\", class()].join(\" \")' },\n\ttemplate: \\`\n\t\t<p>${componentName}</p>\n\t\t<ng-content />\n\t\\`,\n\tstandalone: true,\n\timports: [],\n})\nexport class ${className} {\n\tclass = input<string>('');\n}\n`\n\t\tconst tsTpl =\n\t\t\tSCAFFOLD_CONFIG?.angular?.component?.({\n\t\t\t\tcomponentName,\n\t\t\t\tclassName,\n\t\t\t\tselector,\n\t\t\t\tbase,\n\t\t\t\ttemplateLocation,\n\t\t\t}) ?? defaultTsTpl\n\t\twriteFileSync(tsPath, tsTpl, 'utf8')\n\t\tinfo(`scaffolded angular component → ${rel(tsPath)}`)\n\t}\n\n\t// Only scaffold the HTML file when using an external template\n\tif (\n\t\ttemplateLocation === 'external' &&\n\t\t(!existsSync(htmlPath) || isEmptyOrWhitespace(htmlPath))\n\t) {\n\t\twriteFileSync(htmlPath, defaultAngularHtmlTemplate(componentName), 'utf8')\n\t\tinfo(`scaffolded angular template → ${rel(htmlPath)}`)\n\t}\n}\n\nfunction scaffoldAngularHtmlFromTs(absHtmlPath: string, absTsPath: string) {\n\tconst base = componentBaseFromAngularComponent(absHtmlPath)\n\tconst componentName = toPascalCase(base)\n\n\tlet htmlContent: string | null = null\n\n\t// Try to extract inline template from the existing .ts file\n\tif (existsSync(absTsPath) && !isEmptyOrWhitespace(absTsPath)) {\n\t\tconst tsContent = readFileSync(absTsPath, 'utf8')\n\t\tconst match = tsContent.match(/template:\\s*`([\\s\\S]*?)`/)\n\t\tif (match) {\n\t\t\thtmlContent = normalizeHtmlIndentation(match[1].trim()) + '\\n'\n\t\t\t// Swap template: `...` → templateUrl in the .ts file\n\t\t\tconst updated = tsContent.replace(\n\t\t\t\t/template:\\s*`[\\s\\S]*?`/,\n\t\t\t\t`templateUrl: './${base}.component.html'`,\n\t\t\t)\n\t\t\twriteFileSync(absTsPath, updated, 'utf8')\n\t\t\tinfo(`updated angular component to use templateUrl → ${rel(absTsPath)}`)\n\t\t}\n\t}\n\n\t// Fall back to default scaffold\n\tif (htmlContent === null) {\n\t\thtmlContent = defaultAngularHtmlTemplate(componentName)\n\t}\n\n\twriteFileSync(absHtmlPath, htmlContent, 'utf8')\n\tinfo(`scaffolded angular template → ${rel(absHtmlPath)}`)\n}\n\nfunction scaffoldStoryForAngularComponent(absCompPath: string) {\n\tconst base = componentBaseFromAngularComponent(absCompPath)\n\tconst componentName = toPascalCase(base)\n\tconst className = `${componentName}Component`\n\tconst title = makeTitleFromAngularComponent(absCompPath)\n\tconst atomic = detectAtomicTag(absCompPath)\n\tconst tags = ['autodocs']\n\tif (atomic) tags.push(atomic)\n\n\tconst storyTpl =\n\t\tSCAFFOLD_CONFIG?.angular?.story?.({\n\t\t\tcomponentName,\n\t\t\tclassName,\n\t\t\tbase,\n\t\t\ttitle,\n\t\t\ttags,\n\t\t}) ??\n\t\t`import type { Meta, StoryObj } from '@storybook/angular'\nimport type { StoryParameters } from 'storybook-addon-dependency-previews'\nimport { ${className} } from './${base}.component'\n\nconst meta: Meta<${className}> = {\n\ttitle: '${title}',\n\tcomponent: ${className},\n\ttags: ${JSON.stringify(tags)},\n\tparameters: {\n\t\tlayout: 'padded',\n\t} satisfies StoryParameters,\n}\n\nexport default meta\n\ntype Story = StoryObj<${className}>\n\nexport const Primary: Story = {\n\targs: {},\n}\n`\n\tconst storyPath = storyPathForAngularComponent(absCompPath)\n\twriteFileSync(storyPath, storyTpl, 'utf8')\n\tinfo(`scaffolded angular story → ${rel(storyPath)}`)\n\treturn storyPath\n}\n\nfunction ensureStoryForAngularComponent(absCompPath: string) {\n\tconst sPath = storyPathForAngularComponent(absCompPath)\n\tif (existsSync(sPath)) return null\n\treturn scaffoldStoryForAngularComponent(absCompPath)\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Watcher\n// ───────────────────────────────────────────────────────────────────────────────\nfunction startWatcher() {\n\tconst root = projectRoot\n\t// When SRC_DIR === '' (project root is the source folder), `${SRC_DIR}/**/*`\n\t// would produce `/**/*` — a leading slash that micromatch doesn't match\n\t// against the relative paths the watcher feeds it. Drop the prefix in that\n\t// case so we watch every non-ignored file at the project root.\n\tconst srcPrefix = SRC_DIR === '' ? '' : `${SRC_DIR}/`\n\tconst includeGlobs = [\n\t\t'**/*.stories.{ts,tsx,js,jsx,mdx,svelte}',\n\t\t'**/*.story.{ts,tsx,js,jsx,mdx,svelte}',\n\t\t`${srcPrefix}**/*.{ts,tsx,js,jsx,svelte}`,\n\t\t`${srcPrefix}**/*.component.html`,\n\t\t'depcruise.config.cjs',\n\t\t'.dependency-cruiser.{js,cjs}',\n\t]\n\tconst ignoreGlobs = [\n\t\t'node_modules/**',\n\t\t'.git/**',\n\t\t'.storybook/**',\n\t\t'**/.cache/**',\n\t\t'**/dist/**',\n\t\t'**/build/**',\n\t]\n\n\tlet pending = false\n\tlet timer: NodeJS.Timeout | null = null\n\tlet isDeletingFile = false\n\n\tfunction kick(reason: string, absPath: string) {\n\t\tif (pending) return\n\t\tpending = true\n\t\tif (timer) clearTimeout(timer)\n\t\ttimer = setTimeout(() => {\n\t\t\tinfo(`${reason}: ${rel(absPath)}`)\n\t\t\tbuildOnce()\n\t\t\tpending = false\n\t\t}, 120)\n\t}\n\n\treturn watcherParcel\n\t\t.subscribe(\n\t\t\troot,\n\t\t\tasync (err, events) => {\n\t\t\t\tif (err) {\n\t\t\t\t\terror(`watch error ${err?.message || err}`)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tfor (const ev of events) {\n\t\t\t\t\tconst abs = ev.path\n\t\t\t\t\tconst relPath = rel(abs)\n\t\t\t\t\tif (!micromatch.isMatch(relPath, includeGlobs)) continue\n\n\t\t\t\t\tif (ev.type === 'delete') {\n\t\t\t\t\t\tconsole.log('Deleted:', relPath)\n\t\t\t\t\t\tisDeletingFile = true\n\t\t\t\t\t\tkick('unlink', abs)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// COMPONENT CREATE — scaffold if empty and ensure story\n\t\t\t\t\tif (isComponentsTsx(abs) && ev.type === 'create') {\n\t\t\t\t\t\tawait handleComponentCreation(abs, relPath)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// SVELTE COMPONENT CREATE — scaffold if empty and ensure story\n\t\t\t\t\tif (isComponentsSvelte(abs) && ev.type === 'create') {\n\t\t\t\t\t\tawait handleSvelteComponentCreation(abs, relPath)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// ANGULAR .component.ts CREATE — scaffold with inline template\n\t\t\t\t\tif (isComponentsAngularTs(abs) && ev.type === 'create') {\n\t\t\t\t\t\tawait handleAngularComponentCreation(abs, relPath, 'internal')\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// ANGULAR .component.html CREATE\n\t\t\t\t\tif (isComponentsAngularHtml(abs) && ev.type === 'create') {\n\t\t\t\t\t\tconst tsPath = angularComponentTsPath(abs)\n\t\t\t\t\t\tif (existsSync(tsPath) && !isEmptyOrWhitespace(tsPath)) {\n\t\t\t\t\t\t\t// .ts already exists — scaffold HTML from it (migrate inline template if present)\n\t\t\t\t\t\t\tif (isEmptyOrWhitespace(abs)) {\n\t\t\t\t\t\t\t\tscaffoldAngularHtmlFromTs(abs, tsPath)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconsole.log('Angular component creation detected:', rel(abs))\n\t\t\t\t\t\t\tconst createdStory = ensureStoryForAngularComponent(tsPath)\n\t\t\t\t\t\t\tif (createdStory) {\n\t\t\t\t\t\t\t\tkick('create:story', createdStory)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// .ts doesn't exist yet — existing behavior: scaffold both with external templateUrl\n\t\t\t\t\t\t\tawait handleAngularComponentCreation(\n\t\t\t\t\t\t\t\ttsPath,\n\t\t\t\t\t\t\t\trel(tsPath),\n\t\t\t\t\t\t\t\t'external',\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// normal rebuild\n\t\t\t\t\tkick(ev.type, abs)\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ ignore: ignoreGlobs },\n\t\t)\n\t\t.then((result) => {\n\t\t\tinfo('watching… (ready)')\n\t\t\treturn result\n\t\t})\n\t\t.catch((e) => error(`watch init failed ${e?.message || e}`))\n\n\tasync function handleComponentCreation(abs: string, relPath: string) {\n\t\tif (isEmptyOrWhitespace(abs)) {\n\t\t\tscaffoldComponent(abs)\n\t\t}\n\n\t\tconsole.log('Component creation detected:', relPath)\n\t\tconst createdStory = ensureStoryForComponent(abs)\n\t\tif (createdStory) {\n\t\t\tkick('create:story', createdStory)\n\t\t}\n\t}\n\n\tasync function handleSvelteComponentCreation(abs: string, relPath: string) {\n\t\tif (isDecoratorSvelte(abs)) {\n\t\t\tif (isEmptyOrWhitespace(abs)) {\n\t\t\t\tscaffoldSvelteDecorator(abs)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tif (isEmptyOrWhitespace(abs)) {\n\t\t\tscaffoldSvelteComponent(abs)\n\t\t}\n\n\t\tconst createdStory = ensureStoryForSvelteComponent(abs)\n\t\tif (createdStory) {\n\t\t\tkick('create:story', createdStory)\n\t\t}\n\t}\n\n\tasync function handleAngularComponentCreation(\n\t\tabs: string,\n\t\trelPath: string,\n\t\ttemplateStyle: 'internal' | 'external',\n\t) {\n\t\tif (isEmptyOrWhitespace(abs)) {\n\t\t\tscaffoldAngularComponent(abs, templateStyle)\n\t\t}\n\n\t\tconsole.log('Angular component creation detected:', relPath)\n\t\tconst createdStory = ensureStoryForAngularComponent(abs)\n\t\tif (createdStory) {\n\t\t\tkick('create:story', createdStory)\n\t\t}\n\t}\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Storybook child\n// ───────────────────────────────────────────────────────────────────────────────\nlet sbChild: ChildProcess | null = null\nasync function startStorybook() {\n\tconst isWin = process.platform === 'win32'\n\tlet cmd: string\n\tlet args: string[]\n\tlet shellMode: boolean\n\tif (SB_CUSTOM_CMD) {\n\t\tcmd = SB_CUSTOM_CMD\n\t\targs = []\n\t\tshellMode = true // shell:true handles quoted args and paths with spaces\n\t} else {\n\t\tcmd = 'npx'\n\t\targs = ['-y', 'storybook', 'dev', '-p', String(SB_PORT)]\n\t\tshellMode = isWin // ← critical to avoid EINVAL on Win + Git Bash\n\t}\n\n\tinfo(`[sb-deps] launching: ${cmd} ${args.join(' ')}`)\n\n\tsbChild = spawn(cmd, args, {\n\t\tcwd: projectRoot,\n\t\tstdio: 'inherit',\n\t\tshell: shellMode,\n\t\tenv: process.env,\n\t})\n\n\tsbChild.on('error', (err: any) => {\n\t\terror(`spawn failed: ${err?.message || err}`)\n\t})\n\n\tsbChild.on('exit', (code, sig) => {\n\t\tinfo(`storybook exited (${sig || code})`)\n\t\tsbChild = null\n\t})\n\n\tinfo(`storybook running on http://localhost:${SB_PORT}`)\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Boot\n// ───────────────────────────────────────────────────────────────────────────────\n;(async () => {\n\tif (SUBCOMMAND === 'setup') {\n\t\tawait runSetup(argv.slice(1))\n\t\treturn\n\t}\n\n\tconst cfg = await loadSbDepsConfig()\n\tANGULAR_SELECTOR_PREFIX = cfg.angularSelectorPrefix ?? 'app-'\n\tSCAFFOLD_CONFIG = cfg.scaffold ?? {}\n\t// `cfg.srcDir` can take three meaningfully-different shapes:\n\t//\n\t// - `undefined` / missing key → fall back to the bundled default `'src'`.\n\t// - exactly `''` → deliberate project-root sentinel\n\t// (downstream sites special-case this).\n\t// - anything else → validate against the safe-character\n\t// allow-list and use, or fall back to\n\t// `'src'` with a warning.\n\t//\n\t// Whitespace-only values (e.g. `srcDir: ' '`) are treated as invalid —\n\t// trimming produces an empty string, but that's almost certainly a typo,\n\t// not a deliberate request for project-root mode. Match against the\n\t// allow-list before stripping whitespace so we can distinguish the two.\n\t//\n\t// Allow-list:\n\t// - alphanumerics + `.`, `_`, `-` — covers every directory name people\n\t// conventionally use (`src`, `app`, `my-source`, `app.v2`, etc.)\n\t// - rejects glob metacharacters (`*`, `?`, `[`, `]`, `{`, `}`) that\n\t// would otherwise change watcher-glob matching when interpolated into\n\t// `${SRC_DIR}/**/*.{ts,...}`\n\t// - rejects path separators (`/`, `\\`) — srcDir must be a single segment\n\t// (`projects/foo/src` style multi-project Angular workspaces aren't\n\t// supported; use the empty-string project-root mode instead)\n\t// - rejects cmd.exe metacharacters including `%` (which triggers `%VAR%`\n\t// env expansion when the args go through a `cmd.exe`-invoked `.cmd`\n\t// shim on Windows) and `^` / `&` / `|` / `<` / `>` / `(` / `)` / `!`\n\t//\n\t// Bounding the input here means downstream interpolation sites can trust\n\t// their `SRC_DIR` source and don't each need their own escape pass.\n\tconst SAFE_SRCDIR_PATTERN = /^[A-Za-z0-9._-]+$/\n\tconst userSrcDir = cfg.srcDir\n\tif (userSrcDir === undefined) {\n\t\tSRC_DIR = 'src'\n\t} else if (userSrcDir === '') {\n\t\tSRC_DIR = ''\n\t} else {\n\t\tconst trimmed = userSrcDir.replace(/[\\\\/]+$/, '').trim()\n\t\t// Reject the special path segments `.` and `..` explicitly — they\n\t\t// match the character allow-list but they're path-traversal segments,\n\t\t// not real folder names, and would produce broken include-only regexes\n\t\t// (e.g. `^./` matches \"any-char then slash\") plus potentially escape\n\t\t// the project root when joined with other paths.\n\t\tconst isSpecialSegment = trimmed === '.' || trimmed === '..'\n\t\tif (\n\t\t\ttrimmed !== '' &&\n\t\t\t!isSpecialSegment &&\n\t\t\tSAFE_SRCDIR_PATTERN.test(trimmed)\n\t\t) {\n\t\t\tSRC_DIR = trimmed\n\t\t} else {\n\t\t\terror(\n\t\t\t\t`srcDir \"${userSrcDir}\" is invalid — must be either exactly the empty string (project root) or a single directory name containing only alphanumerics, \".\", \"_\", or \"-\" (e.g. \"src\", \"app\", \"my-source\"). \".\" and \"..\" are not allowed. Falling back to \"src\".`,\n\t\t\t)\n\t\t\tSRC_DIR = 'src'\n\t\t}\n\t}\n\n\tbanner('sb-deps')\n\tinfo(`outDir: ${rel(outDir)}`)\n\tinfo(configPath ? `config: ${rel(configPath)}` : 'config: (none)')\n\tbuildOnce()\n\n\tlet watcher: watcherParcel.AsyncSubscription | null = null\n\tif (WATCH) startWatcher().then((w) => (watcher = w || null))\n\tif (RUN_SB) startStorybook()\n\n\tprocess.on('SIGINT', async () => {\n\t\tinfo('shutting down…')\n\t\tawait watcher?.unsubscribe()\n\t\tsbChild?.kill('SIGINT')\n\t\tprocess.exit(0)\n\t})\n})()\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Utils\n// ───────────────────────────────────────────────────────────────────────────────\nfunction rel(p: string) {\n\t// remove the projectRoot prefix and normalize slashes for logs\n\tconst prefix = resolve(projectRoot) + sep\n\treturn p.replace(prefix, '')\n}\nfunction ms(n: number) {\n\treturn `${Math.max(1, Math.round(n))}ms`\n}\nfunction info(msg: string) {\n\tconsole.log('[sb-deps]', msg)\n}\nfunction error(msg: string) {\n\tconsole.error('[sb-deps]', msg)\n}\nfunction banner(title: string) {\n\tconsole.log(`\\n${title} – dependency previews\\n`)\n}\nfunction wait(time = 500) {\n\treturn new Promise((r) => setTimeout(r, time))\n}\n"],"mappings":"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"}
|
package/dist/cli/sb-deps.mjs
CHANGED
|
@@ -97,14 +97,14 @@ function resolveDepCruiseBin() {
|
|
|
97
97
|
return existsSync(bin) ? bin : null;
|
|
98
98
|
}
|
|
99
99
|
function runDepCruiseOnce() {
|
|
100
|
-
const
|
|
100
|
+
const includeOnly = SRC_DIR === "" ? "^(?!(?:[^/]*/)*node_modules/)" : `^${SRC_DIR.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/`;
|
|
101
101
|
const args = ["."];
|
|
102
102
|
if (configPath) {
|
|
103
103
|
args.push("--config", configPath);
|
|
104
104
|
} else {
|
|
105
105
|
args.push("--no-config");
|
|
106
106
|
}
|
|
107
|
-
args.push("--include-only",
|
|
107
|
+
args.push("--include-only", includeOnly, "--output-type", "json");
|
|
108
108
|
const depcruiseBin = resolveDepCruiseBin();
|
|
109
109
|
if (!depcruiseBin) {
|
|
110
110
|
throw new Error("Could not locate `dependency-cruiser` in node_modules/.bin. Run the setup wizard (`sb-deps setup`) or install `dependency-cruiser` as a dev dependency.");
|
|
@@ -118,7 +118,11 @@ function runDepCruiseOnce() {
|
|
|
118
118
|
"inherit"
|
|
119
119
|
],
|
|
120
120
|
encoding: "utf8",
|
|
121
|
-
shell: IS_WIN
|
|
121
|
+
shell: IS_WIN,
|
|
122
|
+
env: {
|
|
123
|
+
...process.env,
|
|
124
|
+
SB_DEPS_SRC_DIR: SRC_DIR
|
|
125
|
+
}
|
|
122
126
|
});
|
|
123
127
|
writeFileSync(rawPath, stdout, "utf8");
|
|
124
128
|
info(`graph ✓ (${ms(Date.now() - start)})`);
|
|
@@ -190,6 +194,9 @@ function isEmptyOrWhitespace(absPath) {
|
|
|
190
194
|
* (`STORY_FILE_REGEX`) is applied separately in the individual helpers.
|
|
191
195
|
*/
|
|
192
196
|
function srcSubpathRegex(suffixPattern) {
|
|
197
|
+
if (SRC_DIR === "") {
|
|
198
|
+
return new RegExp(`.+${suffixPattern}`, "i");
|
|
199
|
+
}
|
|
193
200
|
const escapedSrcDir = SRC_DIR.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
194
201
|
return new RegExp(`(?:^|\\/)${escapedSrcDir}\\/.+${suffixPattern}`, "i");
|
|
195
202
|
}
|
|
@@ -652,11 +659,12 @@ function ensureStoryForAngularComponent(absCompPath) {
|
|
|
652
659
|
}
|
|
653
660
|
function startWatcher() {
|
|
654
661
|
const root = projectRoot;
|
|
662
|
+
const srcPrefix = SRC_DIR === "" ? "" : `${SRC_DIR}/`;
|
|
655
663
|
const includeGlobs = [
|
|
656
664
|
"**/*.stories.{ts,tsx,js,jsx,mdx,svelte}",
|
|
657
665
|
"**/*.story.{ts,tsx,js,jsx,mdx,svelte}",
|
|
658
|
-
`${
|
|
659
|
-
`${
|
|
666
|
+
`${srcPrefix}**/*.{ts,tsx,js,jsx,svelte}`,
|
|
667
|
+
`${srcPrefix}**/*.component.html`,
|
|
660
668
|
"depcruise.config.cjs",
|
|
661
669
|
".dependency-cruiser.{js,cjs}"
|
|
662
670
|
];
|
|
@@ -812,13 +820,21 @@ async function startStorybook() {
|
|
|
812
820
|
const cfg = await loadSbDepsConfig();
|
|
813
821
|
ANGULAR_SELECTOR_PREFIX = cfg.angularSelectorPrefix ?? "app-";
|
|
814
822
|
SCAFFOLD_CONFIG = cfg.scaffold ?? {};
|
|
815
|
-
const rawSrcDir = (cfg.srcDir ?? "src").replace(/[\\/]+$/, "").trim();
|
|
816
823
|
const SAFE_SRCDIR_PATTERN = /^[A-Za-z0-9._-]+$/;
|
|
817
|
-
|
|
818
|
-
|
|
824
|
+
const userSrcDir = cfg.srcDir;
|
|
825
|
+
if (userSrcDir === undefined) {
|
|
819
826
|
SRC_DIR = "src";
|
|
827
|
+
} else if (userSrcDir === "") {
|
|
828
|
+
SRC_DIR = "";
|
|
820
829
|
} else {
|
|
821
|
-
|
|
830
|
+
const trimmed = userSrcDir.replace(/[\\/]+$/, "").trim();
|
|
831
|
+
const isSpecialSegment = trimmed === "." || trimmed === "..";
|
|
832
|
+
if (trimmed !== "" && !isSpecialSegment && SAFE_SRCDIR_PATTERN.test(trimmed)) {
|
|
833
|
+
SRC_DIR = trimmed;
|
|
834
|
+
} else {
|
|
835
|
+
error(`srcDir "${userSrcDir}" is invalid — must be either exactly the empty string (project root) or a single directory name containing only alphanumerics, ".", "_", or "-" (e.g. "src", "app", "my-source"). "." and ".." are not allowed. Falling back to "src".`);
|
|
836
|
+
SRC_DIR = "src";
|
|
837
|
+
}
|
|
822
838
|
}
|
|
823
839
|
banner("sb-deps");
|
|
824
840
|
info(`outDir: ${rel(outDir)}`);
|