dispersa 0.1.3 → 0.2.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.
@@ -0,0 +1,11 @@
1
+ type CliIO = {
2
+ stdout: (message: string) => void;
3
+ stderr: (message: string) => void;
4
+ };
5
+ type RunOptions = {
6
+ cwd?: string;
7
+ io?: CliIO;
8
+ };
9
+ declare function runCli(args: string[], options?: RunOptions): Promise<number>;
10
+
11
+ export { runCli };
@@ -0,0 +1,201 @@
1
+ import { access } from 'fs/promises';
2
+ import { createRequire } from 'module';
3
+ import { dirname, resolve, isAbsolute } from 'path';
4
+ import process from 'process';
5
+ import { Dispersa } from 'dispersa';
6
+ import { createJiti } from 'jiti';
7
+
8
+ // src/cli/cli.ts
9
+ var defaultConfigNames = [
10
+ "dispersa.config.ts",
11
+ "dispersa.config.js",
12
+ "dispersa.config.mts",
13
+ "dispersa.config.mjs",
14
+ "dispersa.config.cts",
15
+ "dispersa.config.cjs"
16
+ ];
17
+ async function runCli(args, options = {}) {
18
+ const cwd = options.cwd ?? process.cwd();
19
+ const io = options.io ?? {
20
+ stdout: (message) => process.stdout.write(`${message}
21
+ `),
22
+ stderr: (message) => process.stderr.write(`${message}
23
+ `)
24
+ };
25
+ const command = args[0] ?? "build";
26
+ if (command === "--help" || command === "-h" || command === "help") {
27
+ printHelp(io);
28
+ return 0;
29
+ }
30
+ if (command !== "build") {
31
+ io.stderr(`Unknown command: ${command}`);
32
+ printHelp(io);
33
+ return 1;
34
+ }
35
+ const configPath = getArgValue(args, "--config");
36
+ const verbose = hasFlag(args, "--verbose") || hasFlag(args, "-v");
37
+ const resolvedPath = await resolveConfigPath(configPath, cwd);
38
+ if (resolvedPath === void 0) {
39
+ io.stderr(
40
+ `No config found. Expected one of: ${defaultConfigNames.join(", ")} or pass --config <path>.`
41
+ );
42
+ return 1;
43
+ }
44
+ if (verbose) {
45
+ io.stdout(`Config: ${resolvedPath}`);
46
+ }
47
+ let config;
48
+ try {
49
+ config = await loadConfig(resolvedPath, cwd);
50
+ } catch (error) {
51
+ io.stderr(`Failed to load config: ${resolvedPath}`);
52
+ io.stderr(`- ${error instanceof Error ? error.message : String(error)}`);
53
+ return 1;
54
+ }
55
+ const configDir = dirname(resolvedPath);
56
+ const normalizedConfig = normalizeConfigPaths(config, configDir);
57
+ const { validation, resolver, buildPath, ...buildConfig } = normalizedConfig;
58
+ if (verbose) {
59
+ const outputCount = buildConfig.outputs?.length ?? 0;
60
+ io.stdout(`Outputs: ${outputCount} configured`);
61
+ if (buildPath) {
62
+ io.stdout(`Build path: ${buildPath}`);
63
+ }
64
+ }
65
+ const startTime = Date.now();
66
+ const dispersa = new Dispersa({ resolver, buildPath, validation });
67
+ const result = await dispersa.build(buildConfig);
68
+ const elapsed = Date.now() - startTime;
69
+ if (!result.success) {
70
+ io.stderr("Build failed.");
71
+ for (const error of result.errors ?? []) {
72
+ io.stderr(`- [${error.code}] ${error.message}`);
73
+ if (verbose && error.tokenPath) {
74
+ io.stderr(` Token: ${error.tokenPath}`);
75
+ }
76
+ if (verbose && error.path) {
77
+ io.stderr(` File: ${error.path}`);
78
+ }
79
+ if (verbose && error.suggestions && error.suggestions.length > 0) {
80
+ io.stderr(` Suggestions: ${error.suggestions.join(", ")}`);
81
+ }
82
+ }
83
+ if (verbose) {
84
+ io.stderr(`Duration: ${elapsed}ms`);
85
+ }
86
+ return 1;
87
+ }
88
+ io.stdout("Build succeeded.");
89
+ for (const output of result.outputs) {
90
+ const location = output.path ?? "(in-memory)";
91
+ io.stdout(`- ${output.name}: ${location}`);
92
+ }
93
+ if (verbose) {
94
+ io.stdout(`Duration: ${elapsed}ms`);
95
+ }
96
+ return 0;
97
+ }
98
+ function getArgValue(args, flag) {
99
+ const index = args.indexOf(flag);
100
+ if (index === -1 || index === args.length - 1) {
101
+ return void 0;
102
+ }
103
+ const value = args[index + 1];
104
+ if (value == null || value.startsWith("-")) {
105
+ return void 0;
106
+ }
107
+ return value;
108
+ }
109
+ function hasFlag(args, flag) {
110
+ return args.includes(flag);
111
+ }
112
+ async function resolveConfigPath(configPath, cwd) {
113
+ if (configPath) {
114
+ const fullPath = resolve(cwd, configPath);
115
+ if (!await fileExists(fullPath)) {
116
+ return void 0;
117
+ }
118
+ return fullPath;
119
+ }
120
+ for (const name of defaultConfigNames) {
121
+ const fullPath = resolve(cwd, name);
122
+ if (await fileExists(fullPath)) {
123
+ return fullPath;
124
+ }
125
+ }
126
+ return void 0;
127
+ }
128
+ async function loadConfig(configPath, cwd) {
129
+ const alias = await buildAliasMap(cwd);
130
+ const loader = createJiti(cwd, {
131
+ interopDefault: true,
132
+ alias
133
+ });
134
+ const loaded = await loader(configPath);
135
+ const config = loaded.default ?? loaded;
136
+ if (config == null || typeof config !== "object") {
137
+ throw new Error(`Invalid config: ${configPath} did not export an object`);
138
+ }
139
+ return config;
140
+ }
141
+ function normalizeConfigPaths(config, configDir) {
142
+ const resolver = typeof config.resolver === "string" ? resolveIfRelative(config.resolver, configDir) : config.resolver;
143
+ const buildPath = resolveIfRelative(config.buildPath, configDir);
144
+ const outputs = config.outputs ?? [];
145
+ return {
146
+ ...config,
147
+ resolver,
148
+ buildPath,
149
+ outputs
150
+ };
151
+ }
152
+ function resolveIfRelative(value, baseDir) {
153
+ if (!value) {
154
+ return value;
155
+ }
156
+ return isAbsolute(value) ? value : resolve(baseDir, value);
157
+ }
158
+ async function fileExists(path) {
159
+ try {
160
+ await access(path);
161
+ return true;
162
+ } catch {
163
+ return false;
164
+ }
165
+ }
166
+ async function buildAliasMap(cwd) {
167
+ const alias = {};
168
+ const coreSourcePath = resolve(cwd, "packages/core/src/index.ts");
169
+ if (await fileExists(coreSourcePath)) {
170
+ alias["dispersa"] = coreSourcePath;
171
+ return alias;
172
+ }
173
+ if (!isPackageResolvable("dispersa", cwd)) {
174
+ const require2 = createRequire(import.meta.url);
175
+ try {
176
+ alias["dispersa"] = require2.resolve("dispersa");
177
+ } catch {
178
+ }
179
+ }
180
+ return alias;
181
+ }
182
+ function isPackageResolvable(name, cwd) {
183
+ const require2 = createRequire(import.meta.url);
184
+ try {
185
+ require2.resolve(name, { paths: [cwd] });
186
+ return true;
187
+ } catch {
188
+ return false;
189
+ }
190
+ }
191
+ function printHelp(io) {
192
+ io.stdout("dispersa build [options]");
193
+ io.stdout("");
194
+ io.stdout("Options:");
195
+ io.stdout(" --config <path> Path to dispersa.config.(ts|js|mts|mjs|cts|cjs)");
196
+ io.stdout(" --verbose, -v Show detailed build output (timing, error context)");
197
+ }
198
+
199
+ export { runCli };
200
+ //# sourceMappingURL=cli.js.map
201
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/cli.ts"],"names":["require"],"mappings":"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","file":"cli.js","sourcesContent":["import { access } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { dirname, isAbsolute, resolve } from 'node:path'\nimport process from 'node:process'\n\nimport { Dispersa, type BuildConfig } from 'dispersa'\nimport { createJiti } from 'jiti'\n\nimport type { CliConfig } from './config'\n\ntype CliIO = {\n stdout: (message: string) => void\n stderr: (message: string) => void\n}\n\ntype RunOptions = {\n cwd?: string\n io?: CliIO\n}\n\nconst defaultConfigNames = [\n 'dispersa.config.ts',\n 'dispersa.config.js',\n 'dispersa.config.mts',\n 'dispersa.config.mjs',\n 'dispersa.config.cts',\n 'dispersa.config.cjs',\n]\n\nexport async function runCli(args: string[], options: RunOptions = {}): Promise<number> {\n const cwd = options.cwd ?? process.cwd()\n const io: CliIO = options.io ?? {\n stdout: (message) => process.stdout.write(`${message}\\n`),\n stderr: (message) => process.stderr.write(`${message}\\n`),\n }\n\n const command = args[0] ?? 'build'\n if (command === '--help' || command === '-h' || command === 'help') {\n printHelp(io)\n return 0\n }\n\n if (command !== 'build') {\n io.stderr(`Unknown command: ${command}`)\n printHelp(io)\n return 1\n }\n\n const configPath = getArgValue(args, '--config')\n const verbose = hasFlag(args, '--verbose') || hasFlag(args, '-v')\n const resolvedPath = await resolveConfigPath(configPath, cwd)\n if (resolvedPath === undefined) {\n io.stderr(\n `No config found. Expected one of: ${defaultConfigNames.join(', ')} ` +\n 'or pass --config <path>.',\n )\n return 1\n }\n\n if (verbose) {\n io.stdout(`Config: ${resolvedPath}`)\n }\n\n let config: CliConfig\n try {\n config = await loadConfig(resolvedPath, cwd)\n } catch (error) {\n io.stderr(`Failed to load config: ${resolvedPath}`)\n io.stderr(`- ${error instanceof Error ? error.message : String(error)}`)\n return 1\n }\n\n const configDir = dirname(resolvedPath)\n const normalizedConfig = normalizeConfigPaths(config, configDir)\n const { validation, resolver, buildPath, ...buildConfig } = normalizedConfig\n\n if (verbose) {\n const outputCount = buildConfig.outputs?.length ?? 0\n io.stdout(`Outputs: ${outputCount} configured`)\n if (buildPath) {\n io.stdout(`Build path: ${buildPath}`)\n }\n }\n\n const startTime = Date.now()\n const dispersa = new Dispersa({ resolver, buildPath, validation })\n const result = await dispersa.build(buildConfig as BuildConfig)\n const elapsed = Date.now() - startTime\n\n if (!result.success) {\n io.stderr('Build failed.')\n for (const error of result.errors ?? []) {\n io.stderr(`- [${error.code}] ${error.message}`)\n if (verbose && error.tokenPath) {\n io.stderr(` Token: ${error.tokenPath}`)\n }\n if (verbose && error.path) {\n io.stderr(` File: ${error.path}`)\n }\n if (verbose && error.suggestions && error.suggestions.length > 0) {\n io.stderr(` Suggestions: ${error.suggestions.join(', ')}`)\n }\n }\n if (verbose) {\n io.stderr(`Duration: ${elapsed}ms`)\n }\n return 1\n }\n\n io.stdout('Build succeeded.')\n for (const output of result.outputs) {\n const location = output.path ?? '(in-memory)'\n io.stdout(`- ${output.name}: ${location}`)\n }\n\n if (verbose) {\n io.stdout(`Duration: ${elapsed}ms`)\n }\n\n return 0\n}\n\nfunction getArgValue(args: string[], flag: string): string | undefined {\n const index = args.indexOf(flag)\n if (index === -1 || index === args.length - 1) {\n return undefined\n }\n const value = args[index + 1]\n if (value == null || value.startsWith('-')) {\n return undefined\n }\n return value\n}\n\nfunction hasFlag(args: string[], flag: string): boolean {\n return args.includes(flag)\n}\n\nasync function resolveConfigPath(\n configPath: string | undefined,\n cwd: string,\n): Promise<string | undefined> {\n if (configPath) {\n const fullPath = resolve(cwd, configPath)\n if (!(await fileExists(fullPath))) {\n return undefined\n }\n return fullPath\n }\n\n for (const name of defaultConfigNames) {\n const fullPath = resolve(cwd, name)\n if (await fileExists(fullPath)) {\n return fullPath\n }\n }\n\n return undefined\n}\n\nasync function loadConfig(configPath: string, cwd: string): Promise<CliConfig> {\n const alias = await buildAliasMap(cwd)\n const loader = createJiti(cwd, {\n interopDefault: true,\n alias,\n })\n const loaded = await loader(configPath)\n const config = (loaded as { default?: CliConfig }).default ?? (loaded as CliConfig)\n\n if (config == null || typeof config !== 'object') {\n throw new Error(`Invalid config: ${configPath} did not export an object`)\n }\n\n return config\n}\n\nfunction normalizeConfigPaths(config: CliConfig, configDir: string): CliConfig {\n const resolver =\n typeof config.resolver === 'string'\n ? resolveIfRelative(config.resolver, configDir)\n : config.resolver\n const buildPath = resolveIfRelative(config.buildPath, configDir)\n const outputs = config.outputs ?? []\n\n return {\n ...config,\n resolver,\n buildPath,\n outputs,\n }\n}\n\nfunction resolveIfRelative(value: string | undefined, baseDir: string): string | undefined {\n if (!value) {\n return value\n }\n return isAbsolute(value) ? value : resolve(baseDir, value)\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path)\n return true\n } catch {\n return false\n }\n}\n\nasync function buildAliasMap(cwd: string): Promise<Record<string, string>> {\n const alias: Record<string, string> = {}\n\n // Dev monorepo: point to source files for hot-reload\n const coreSourcePath = resolve(cwd, 'packages/core/src/index.ts')\n if (await fileExists(coreSourcePath)) {\n alias['dispersa'] = coreSourcePath\n return alias\n }\n\n // Not resolvable from cwd — try from the CLI module's own location\n // (handles workspace symlinks and global installs)\n if (!isPackageResolvable('dispersa', cwd)) {\n const require = createRequire(import.meta.url)\n try {\n alias['dispersa'] = require.resolve('dispersa')\n } catch {\n // Not resolvable at all; config loading will fail with a clear error\n }\n }\n\n return alias\n}\n\nfunction isPackageResolvable(name: string, cwd: string): boolean {\n const require = createRequire(import.meta.url)\n try {\n require.resolve(name, { paths: [cwd] })\n return true\n } catch {\n return false\n }\n}\n\nfunction printHelp(io: CliIO): void {\n io.stdout('dispersa build [options]')\n io.stdout('')\n io.stdout('Options:')\n io.stdout(' --config <path> Path to dispersa.config.(ts|js|mts|mjs|cts|cjs)')\n io.stdout(' --verbose, -v Show detailed build output (timing, error context)')\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import { BuildConfig, ValidationOptions } from 'dispersa';
2
+
3
+ type CliConfig = BuildConfig & {
4
+ validation?: ValidationOptions;
5
+ };
6
+ declare function defineConfig(config: CliConfig): CliConfig;
7
+
8
+ export { type CliConfig, defineConfig };
@@ -0,0 +1,8 @@
1
+ // src/cli/config.ts
2
+ function defineConfig(config) {
3
+ return config;
4
+ }
5
+
6
+ export { defineConfig };
7
+ //# sourceMappingURL=config.js.map
8
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/config.ts"],"names":[],"mappings":";AAMO,SAAS,aAAa,MAAA,EAA8B;AACzD,EAAA,OAAO,MAAA;AACT","file":"config.js","sourcesContent":["import type { BuildConfig, ValidationOptions } from 'dispersa'\n\nexport type CliConfig = BuildConfig & {\n validation?: ValidationOptions\n}\n\nexport function defineConfig(config: CliConfig): CliConfig {\n return config\n}\n"]}
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env node
2
+ import { access } from 'fs/promises';
3
+ import { createRequire } from 'module';
4
+ import { dirname, resolve, isAbsolute } from 'path';
5
+ import process2 from 'process';
6
+ import { Dispersa } from 'dispersa';
7
+ import { createJiti } from 'jiti';
8
+
9
+ var defaultConfigNames = [
10
+ "dispersa.config.ts",
11
+ "dispersa.config.js",
12
+ "dispersa.config.mts",
13
+ "dispersa.config.mjs",
14
+ "dispersa.config.cts",
15
+ "dispersa.config.cjs"
16
+ ];
17
+ async function runCli(args, options = {}) {
18
+ const cwd = options.cwd ?? process2.cwd();
19
+ const io = options.io ?? {
20
+ stdout: (message) => process2.stdout.write(`${message}
21
+ `),
22
+ stderr: (message) => process2.stderr.write(`${message}
23
+ `)
24
+ };
25
+ const command = args[0] ?? "build";
26
+ if (command === "--help" || command === "-h" || command === "help") {
27
+ printHelp(io);
28
+ return 0;
29
+ }
30
+ if (command !== "build") {
31
+ io.stderr(`Unknown command: ${command}`);
32
+ printHelp(io);
33
+ return 1;
34
+ }
35
+ const configPath = getArgValue(args, "--config");
36
+ const verbose = hasFlag(args, "--verbose") || hasFlag(args, "-v");
37
+ const resolvedPath = await resolveConfigPath(configPath, cwd);
38
+ if (resolvedPath === void 0) {
39
+ io.stderr(
40
+ `No config found. Expected one of: ${defaultConfigNames.join(", ")} or pass --config <path>.`
41
+ );
42
+ return 1;
43
+ }
44
+ if (verbose) {
45
+ io.stdout(`Config: ${resolvedPath}`);
46
+ }
47
+ let config;
48
+ try {
49
+ config = await loadConfig(resolvedPath, cwd);
50
+ } catch (error) {
51
+ io.stderr(`Failed to load config: ${resolvedPath}`);
52
+ io.stderr(`- ${error instanceof Error ? error.message : String(error)}`);
53
+ return 1;
54
+ }
55
+ const configDir = dirname(resolvedPath);
56
+ const normalizedConfig = normalizeConfigPaths(config, configDir);
57
+ const { validation, resolver, buildPath, ...buildConfig } = normalizedConfig;
58
+ if (verbose) {
59
+ const outputCount = buildConfig.outputs?.length ?? 0;
60
+ io.stdout(`Outputs: ${outputCount} configured`);
61
+ if (buildPath) {
62
+ io.stdout(`Build path: ${buildPath}`);
63
+ }
64
+ }
65
+ const startTime = Date.now();
66
+ const dispersa = new Dispersa({ resolver, buildPath, validation });
67
+ const result = await dispersa.build(buildConfig);
68
+ const elapsed = Date.now() - startTime;
69
+ if (!result.success) {
70
+ io.stderr("Build failed.");
71
+ for (const error of result.errors ?? []) {
72
+ io.stderr(`- [${error.code}] ${error.message}`);
73
+ if (verbose && error.tokenPath) {
74
+ io.stderr(` Token: ${error.tokenPath}`);
75
+ }
76
+ if (verbose && error.path) {
77
+ io.stderr(` File: ${error.path}`);
78
+ }
79
+ if (verbose && error.suggestions && error.suggestions.length > 0) {
80
+ io.stderr(` Suggestions: ${error.suggestions.join(", ")}`);
81
+ }
82
+ }
83
+ if (verbose) {
84
+ io.stderr(`Duration: ${elapsed}ms`);
85
+ }
86
+ return 1;
87
+ }
88
+ io.stdout("Build succeeded.");
89
+ for (const output of result.outputs) {
90
+ const location = output.path ?? "(in-memory)";
91
+ io.stdout(`- ${output.name}: ${location}`);
92
+ }
93
+ if (verbose) {
94
+ io.stdout(`Duration: ${elapsed}ms`);
95
+ }
96
+ return 0;
97
+ }
98
+ function getArgValue(args, flag) {
99
+ const index = args.indexOf(flag);
100
+ if (index === -1 || index === args.length - 1) {
101
+ return void 0;
102
+ }
103
+ const value = args[index + 1];
104
+ if (value == null || value.startsWith("-")) {
105
+ return void 0;
106
+ }
107
+ return value;
108
+ }
109
+ function hasFlag(args, flag) {
110
+ return args.includes(flag);
111
+ }
112
+ async function resolveConfigPath(configPath, cwd) {
113
+ if (configPath) {
114
+ const fullPath = resolve(cwd, configPath);
115
+ if (!await fileExists(fullPath)) {
116
+ return void 0;
117
+ }
118
+ return fullPath;
119
+ }
120
+ for (const name of defaultConfigNames) {
121
+ const fullPath = resolve(cwd, name);
122
+ if (await fileExists(fullPath)) {
123
+ return fullPath;
124
+ }
125
+ }
126
+ return void 0;
127
+ }
128
+ async function loadConfig(configPath, cwd) {
129
+ const alias = await buildAliasMap(cwd);
130
+ const loader = createJiti(cwd, {
131
+ interopDefault: true,
132
+ alias
133
+ });
134
+ const loaded = await loader(configPath);
135
+ const config = loaded.default ?? loaded;
136
+ if (config == null || typeof config !== "object") {
137
+ throw new Error(`Invalid config: ${configPath} did not export an object`);
138
+ }
139
+ return config;
140
+ }
141
+ function normalizeConfigPaths(config, configDir) {
142
+ const resolver = typeof config.resolver === "string" ? resolveIfRelative(config.resolver, configDir) : config.resolver;
143
+ const buildPath = resolveIfRelative(config.buildPath, configDir);
144
+ const outputs = config.outputs ?? [];
145
+ return {
146
+ ...config,
147
+ resolver,
148
+ buildPath,
149
+ outputs
150
+ };
151
+ }
152
+ function resolveIfRelative(value, baseDir) {
153
+ if (!value) {
154
+ return value;
155
+ }
156
+ return isAbsolute(value) ? value : resolve(baseDir, value);
157
+ }
158
+ async function fileExists(path) {
159
+ try {
160
+ await access(path);
161
+ return true;
162
+ } catch {
163
+ return false;
164
+ }
165
+ }
166
+ async function buildAliasMap(cwd) {
167
+ const alias = {};
168
+ const coreSourcePath = resolve(cwd, "packages/core/src/index.ts");
169
+ if (await fileExists(coreSourcePath)) {
170
+ alias["dispersa"] = coreSourcePath;
171
+ return alias;
172
+ }
173
+ if (!isPackageResolvable("dispersa", cwd)) {
174
+ const require2 = createRequire(import.meta.url);
175
+ try {
176
+ alias["dispersa"] = require2.resolve("dispersa");
177
+ } catch {
178
+ }
179
+ }
180
+ return alias;
181
+ }
182
+ function isPackageResolvable(name, cwd) {
183
+ const require2 = createRequire(import.meta.url);
184
+ try {
185
+ require2.resolve(name, { paths: [cwd] });
186
+ return true;
187
+ } catch {
188
+ return false;
189
+ }
190
+ }
191
+ function printHelp(io) {
192
+ io.stdout("dispersa build [options]");
193
+ io.stdout("");
194
+ io.stdout("Options:");
195
+ io.stdout(" --config <path> Path to dispersa.config.(ts|js|mts|mjs|cts|cjs)");
196
+ io.stdout(" --verbose, -v Show detailed build output (timing, error context)");
197
+ }
198
+
199
+ // src/cli/index.ts
200
+ var exitCode = await runCli(process.argv.slice(2));
201
+ process.exitCode = exitCode;
202
+ //# sourceMappingURL=index.js.map
203
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/cli.ts","../../src/cli/index.ts"],"names":["process","require"],"mappings":"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","file":"index.js","sourcesContent":["import { access } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { dirname, isAbsolute, resolve } from 'node:path'\nimport process from 'node:process'\n\nimport { Dispersa, type BuildConfig } from 'dispersa'\nimport { createJiti } from 'jiti'\n\nimport type { CliConfig } from './config'\n\ntype CliIO = {\n stdout: (message: string) => void\n stderr: (message: string) => void\n}\n\ntype RunOptions = {\n cwd?: string\n io?: CliIO\n}\n\nconst defaultConfigNames = [\n 'dispersa.config.ts',\n 'dispersa.config.js',\n 'dispersa.config.mts',\n 'dispersa.config.mjs',\n 'dispersa.config.cts',\n 'dispersa.config.cjs',\n]\n\nexport async function runCli(args: string[], options: RunOptions = {}): Promise<number> {\n const cwd = options.cwd ?? process.cwd()\n const io: CliIO = options.io ?? {\n stdout: (message) => process.stdout.write(`${message}\\n`),\n stderr: (message) => process.stderr.write(`${message}\\n`),\n }\n\n const command = args[0] ?? 'build'\n if (command === '--help' || command === '-h' || command === 'help') {\n printHelp(io)\n return 0\n }\n\n if (command !== 'build') {\n io.stderr(`Unknown command: ${command}`)\n printHelp(io)\n return 1\n }\n\n const configPath = getArgValue(args, '--config')\n const verbose = hasFlag(args, '--verbose') || hasFlag(args, '-v')\n const resolvedPath = await resolveConfigPath(configPath, cwd)\n if (resolvedPath === undefined) {\n io.stderr(\n `No config found. Expected one of: ${defaultConfigNames.join(', ')} ` +\n 'or pass --config <path>.',\n )\n return 1\n }\n\n if (verbose) {\n io.stdout(`Config: ${resolvedPath}`)\n }\n\n let config: CliConfig\n try {\n config = await loadConfig(resolvedPath, cwd)\n } catch (error) {\n io.stderr(`Failed to load config: ${resolvedPath}`)\n io.stderr(`- ${error instanceof Error ? error.message : String(error)}`)\n return 1\n }\n\n const configDir = dirname(resolvedPath)\n const normalizedConfig = normalizeConfigPaths(config, configDir)\n const { validation, resolver, buildPath, ...buildConfig } = normalizedConfig\n\n if (verbose) {\n const outputCount = buildConfig.outputs?.length ?? 0\n io.stdout(`Outputs: ${outputCount} configured`)\n if (buildPath) {\n io.stdout(`Build path: ${buildPath}`)\n }\n }\n\n const startTime = Date.now()\n const dispersa = new Dispersa({ resolver, buildPath, validation })\n const result = await dispersa.build(buildConfig as BuildConfig)\n const elapsed = Date.now() - startTime\n\n if (!result.success) {\n io.stderr('Build failed.')\n for (const error of result.errors ?? []) {\n io.stderr(`- [${error.code}] ${error.message}`)\n if (verbose && error.tokenPath) {\n io.stderr(` Token: ${error.tokenPath}`)\n }\n if (verbose && error.path) {\n io.stderr(` File: ${error.path}`)\n }\n if (verbose && error.suggestions && error.suggestions.length > 0) {\n io.stderr(` Suggestions: ${error.suggestions.join(', ')}`)\n }\n }\n if (verbose) {\n io.stderr(`Duration: ${elapsed}ms`)\n }\n return 1\n }\n\n io.stdout('Build succeeded.')\n for (const output of result.outputs) {\n const location = output.path ?? '(in-memory)'\n io.stdout(`- ${output.name}: ${location}`)\n }\n\n if (verbose) {\n io.stdout(`Duration: ${elapsed}ms`)\n }\n\n return 0\n}\n\nfunction getArgValue(args: string[], flag: string): string | undefined {\n const index = args.indexOf(flag)\n if (index === -1 || index === args.length - 1) {\n return undefined\n }\n const value = args[index + 1]\n if (value == null || value.startsWith('-')) {\n return undefined\n }\n return value\n}\n\nfunction hasFlag(args: string[], flag: string): boolean {\n return args.includes(flag)\n}\n\nasync function resolveConfigPath(\n configPath: string | undefined,\n cwd: string,\n): Promise<string | undefined> {\n if (configPath) {\n const fullPath = resolve(cwd, configPath)\n if (!(await fileExists(fullPath))) {\n return undefined\n }\n return fullPath\n }\n\n for (const name of defaultConfigNames) {\n const fullPath = resolve(cwd, name)\n if (await fileExists(fullPath)) {\n return fullPath\n }\n }\n\n return undefined\n}\n\nasync function loadConfig(configPath: string, cwd: string): Promise<CliConfig> {\n const alias = await buildAliasMap(cwd)\n const loader = createJiti(cwd, {\n interopDefault: true,\n alias,\n })\n const loaded = await loader(configPath)\n const config = (loaded as { default?: CliConfig }).default ?? (loaded as CliConfig)\n\n if (config == null || typeof config !== 'object') {\n throw new Error(`Invalid config: ${configPath} did not export an object`)\n }\n\n return config\n}\n\nfunction normalizeConfigPaths(config: CliConfig, configDir: string): CliConfig {\n const resolver =\n typeof config.resolver === 'string'\n ? resolveIfRelative(config.resolver, configDir)\n : config.resolver\n const buildPath = resolveIfRelative(config.buildPath, configDir)\n const outputs = config.outputs ?? []\n\n return {\n ...config,\n resolver,\n buildPath,\n outputs,\n }\n}\n\nfunction resolveIfRelative(value: string | undefined, baseDir: string): string | undefined {\n if (!value) {\n return value\n }\n return isAbsolute(value) ? value : resolve(baseDir, value)\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path)\n return true\n } catch {\n return false\n }\n}\n\nasync function buildAliasMap(cwd: string): Promise<Record<string, string>> {\n const alias: Record<string, string> = {}\n\n // Dev monorepo: point to source files for hot-reload\n const coreSourcePath = resolve(cwd, 'packages/core/src/index.ts')\n if (await fileExists(coreSourcePath)) {\n alias['dispersa'] = coreSourcePath\n return alias\n }\n\n // Not resolvable from cwd — try from the CLI module's own location\n // (handles workspace symlinks and global installs)\n if (!isPackageResolvable('dispersa', cwd)) {\n const require = createRequire(import.meta.url)\n try {\n alias['dispersa'] = require.resolve('dispersa')\n } catch {\n // Not resolvable at all; config loading will fail with a clear error\n }\n }\n\n return alias\n}\n\nfunction isPackageResolvable(name: string, cwd: string): boolean {\n const require = createRequire(import.meta.url)\n try {\n require.resolve(name, { paths: [cwd] })\n return true\n } catch {\n return false\n }\n}\n\nfunction printHelp(io: CliIO): void {\n io.stdout('dispersa build [options]')\n io.stdout('')\n io.stdout('Options:')\n io.stdout(' --config <path> Path to dispersa.config.(ts|js|mts|mjs|cts|cjs)')\n io.stdout(' --verbose, -v Show detailed build output (timing, error context)')\n}\n","#!/usr/bin/env node\nimport { runCli } from './cli.js'\n\nconst exitCode = await runCli(process.argv.slice(2))\nprocess.exitCode = exitCode\n"]}
package/dist/filters.cjs CHANGED
@@ -150,7 +150,7 @@ var ValidationHandler = class {
150
150
  }
151
151
  };
152
152
 
153
- // src/lib/resolution/alias-resolver.ts
153
+ // src/resolution/alias-resolver.ts
154
154
  var AliasResolver = class _AliasResolver {
155
155
  options;
156
156
  resolving;
@@ -406,19 +406,20 @@ var AliasResolver = class _AliasResolver {
406
406
  }
407
407
  };
408
408
 
409
- // src/lib/processing/processors/filters/built-in.ts
409
+ // src/processing/processors/filters/built-in.ts
410
410
  function byType(type) {
411
411
  return {
412
412
  filter: (token) => token.$type === type
413
413
  };
414
414
  }
415
415
  function byPath(pattern) {
416
- const regex = typeof pattern === "string" ? new RegExp(`^${pattern}`) : pattern;
416
+ if (typeof pattern === "string") {
417
+ return {
418
+ filter: (token) => token.path.join(".").startsWith(pattern)
419
+ };
420
+ }
417
421
  return {
418
- filter: (token) => {
419
- const fullPath = token.path.join(".");
420
- return regex.test(fullPath);
421
- }
422
+ filter: (token) => pattern.test(token.path.join("."))
422
423
  };
423
424
  }
424
425
  function isAlias() {