svelte-ag 1.0.67 → 1.0.68

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,29 @@
1
+ export interface ResolvePathsProject {
2
+ tsconfigPath: string;
3
+ rootDir: string;
4
+ srcDir: string;
5
+ distDir: string;
6
+ }
7
+ export interface ResolvePathsOptions {
8
+ cwd?: string;
9
+ excludeAliases?: string[];
10
+ inputs?: string[];
11
+ }
12
+ export interface ResolvePathsWatcher {
13
+ close(): void;
14
+ projects: ResolvePathsProject[];
15
+ }
16
+ interface CliOptions {
17
+ excludeAliases: string[];
18
+ inputs: string[];
19
+ watchMode: boolean;
20
+ }
21
+ export declare function buildProject(project: ResolvePathsProject, options?: ResolvePathsOptions): Promise<void>;
22
+ export declare function findProjects(options?: ResolvePathsOptions): Promise<ResolvePathsProject[]>;
23
+ export declare function buildProjects(options?: ResolvePathsOptions): Promise<ResolvePathsProject[]>;
24
+ export declare function watchProjects(options?: ResolvePathsOptions): Promise<ResolvePathsWatcher>;
25
+ export declare function parseCliArgs(args: string[]): CliOptions;
26
+ export declare function isDirectExecution(entryPath?: string, moduleUrl?: string): boolean;
27
+ export declare function main(args?: string[]): Promise<void>;
28
+ export {};
29
+ //# sourceMappingURL=resolve-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-paths.d.ts","sourceRoot":"","sources":["../../src/lib/scripts/resolve-paths.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAED,UAAU,UAAU;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AA6HD,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMjH;AAED,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CA8CpG;AAED,wBAAsB,aAAa,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAcrG;AAgGD,wBAAsB,aAAa,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAenG;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA0DvD;AAyBD,wBAAgB,iBAAiB,CAAC,SAAS,SAAkB,EAAE,SAAS,SAAkB,GAAG,OAAO,CAMnG;AAED,wBAAsB,IAAI,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAStE"}
@@ -0,0 +1,347 @@
1
+ import { cp, glob, mkdir, rm, stat } from 'node:fs/promises';
2
+ import { realpathSync, watch } from 'node:fs';
3
+ import { basename, dirname, isAbsolute, relative, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { replaceTscAliasPaths } from 'tsc-alias';
6
+ import { loadConfig, prepareConfig } from 'tsc-alias/dist/helpers/config.js';
7
+ import { Output, TrieNode } from 'tsc-alias/dist/utils/index.js';
8
+ const DEFAULT_INPUTS = ['tsconfig.json'];
9
+ const GLOB_EXCLUDES = ['**/node_modules/**', '**/.git/**', '**/.svelte-kit/**', '**/dist/**'];
10
+ const LABEL = '[resolve-paths]';
11
+ const REPLACEABLE_FILE_EXTENSIONS = {
12
+ inputGlob: '{ts,tsx,js,jsx,mjs,cjs,svelte,d.{mts,cts,ts,tsx}}',
13
+ outputCheck: [
14
+ 'ts',
15
+ 'tsx',
16
+ 'js',
17
+ 'jsx',
18
+ 'mjs',
19
+ 'cjs',
20
+ 'svelte',
21
+ 'json',
22
+ 'mts',
23
+ 'cts',
24
+ 'd.ts',
25
+ 'd.tsx',
26
+ 'd.mts',
27
+ 'd.cts'
28
+ ]
29
+ };
30
+ function formatPath(targetPath, cwd = process.cwd()) {
31
+ return relative(cwd, targetPath) || '.';
32
+ }
33
+ function logInfo(message) {
34
+ console.log(`${LABEL} ${message}`);
35
+ }
36
+ function logError(message) {
37
+ console.error(`${LABEL} ${message}`);
38
+ }
39
+ async function pathExists(targetPath) {
40
+ try {
41
+ await stat(targetPath);
42
+ return true;
43
+ }
44
+ catch (error) {
45
+ if (error.code === 'ENOENT') {
46
+ return false;
47
+ }
48
+ throw error;
49
+ }
50
+ }
51
+ async function resolveDirectInput(input, cwd) {
52
+ const absoluteInputPath = isAbsolute(input) ? input : resolve(cwd, input);
53
+ if (!(await pathExists(absoluteInputPath))) {
54
+ return [];
55
+ }
56
+ const inputStats = await stat(absoluteInputPath);
57
+ if (inputStats.isDirectory()) {
58
+ const nestedTsconfigPath = resolve(absoluteInputPath, 'tsconfig.json');
59
+ return (await pathExists(nestedTsconfigPath)) ? [nestedTsconfigPath] : [];
60
+ }
61
+ return [absoluteInputPath];
62
+ }
63
+ async function expandInput(input, cwd) {
64
+ const directMatches = await resolveDirectInput(input, cwd);
65
+ if (directMatches.length > 0) {
66
+ return directMatches;
67
+ }
68
+ const matches = await Array.fromAsync(glob(input, {
69
+ cwd,
70
+ exclude: GLOB_EXCLUDES
71
+ }));
72
+ return matches.map((match) => resolve(cwd, match));
73
+ }
74
+ function normalizeAliasPrefix(alias) {
75
+ return alias.replace(/\/\*$/, '').replace(/\/+$/, '');
76
+ }
77
+ function createSilentOutput() {
78
+ return new Output(false, false);
79
+ }
80
+ async function createFilteredAliasTrie(project, excludedAliases) {
81
+ if (excludedAliases.length === 0) {
82
+ return undefined;
83
+ }
84
+ const normalizedExcludedAliases = new Set(excludedAliases.map(normalizeAliasPrefix).filter(Boolean));
85
+ const output = createSilentOutput();
86
+ const loadedConfig = loadConfig(project.tsconfigPath, output);
87
+ if (!loadedConfig.paths) {
88
+ return undefined;
89
+ }
90
+ const filteredPaths = Object.fromEntries(Object.entries(loadedConfig.paths).filter(([alias]) => !normalizedExcludedAliases.has(normalizeAliasPrefix(alias))));
91
+ const preparedConfig = await prepareConfig({
92
+ configFile: project.tsconfigPath,
93
+ fileExtensions: {
94
+ inputGlob: REPLACEABLE_FILE_EXTENSIONS.inputGlob,
95
+ outputCheck: [...REPLACEABLE_FILE_EXTENSIONS.outputCheck]
96
+ },
97
+ outDir: project.distDir,
98
+ output
99
+ });
100
+ return TrieNode.buildAliasTrie(preparedConfig, filteredPaths);
101
+ }
102
+ async function resolveAliases(project, options = {}) {
103
+ await replaceTscAliasPaths({
104
+ aliasTrie: await createFilteredAliasTrie(project, options.excludeAliases ?? []),
105
+ configFile: project.tsconfigPath,
106
+ outDir: project.distDir,
107
+ fileExtensions: {
108
+ inputGlob: REPLACEABLE_FILE_EXTENSIONS.inputGlob,
109
+ outputCheck: [...REPLACEABLE_FILE_EXTENSIONS.outputCheck]
110
+ }
111
+ });
112
+ }
113
+ async function copyProjectSource(project) {
114
+ await rm(project.distDir, {
115
+ force: true,
116
+ recursive: true
117
+ });
118
+ await mkdir(project.rootDir, { recursive: true });
119
+ await cp(project.srcDir, project.distDir, {
120
+ force: true,
121
+ recursive: true
122
+ });
123
+ }
124
+ export async function buildProject(project, options = {}) {
125
+ await copyProjectSource(project);
126
+ await resolveAliases(project, {
127
+ ...options,
128
+ excludeAliases: [...new Set((options.excludeAliases ?? []).map(normalizeAliasPrefix).filter(Boolean))]
129
+ });
130
+ }
131
+ export async function findProjects(options = {}) {
132
+ const cwd = options.cwd ?? process.cwd();
133
+ const inputs = options.inputs && options.inputs.length > 0 ? options.inputs : DEFAULT_INPUTS;
134
+ const resolvedTsconfigPaths = new Set();
135
+ for (const input of inputs) {
136
+ const matches = await expandInput(input, cwd);
137
+ if (matches.length === 0) {
138
+ throw new Error(`No tsconfig.json files matched "${input}" from ${formatPath(cwd, cwd)}`);
139
+ }
140
+ for (const match of matches) {
141
+ if (basename(match) !== 'tsconfig.json') {
142
+ continue;
143
+ }
144
+ resolvedTsconfigPaths.add(resolve(match));
145
+ }
146
+ }
147
+ const projects = await Promise.all([...resolvedTsconfigPaths]
148
+ .sort((left, right) => left.localeCompare(right))
149
+ .map(async (tsconfigPath) => {
150
+ const rootDir = dirname(tsconfigPath);
151
+ const srcDir = resolve(rootDir, 'src');
152
+ if (!(await pathExists(srcDir))) {
153
+ throw new Error(`Missing src directory for ${formatPath(tsconfigPath, cwd)} at ${formatPath(srcDir, cwd)}`);
154
+ }
155
+ return {
156
+ distDir: resolve(rootDir, 'dist'),
157
+ rootDir,
158
+ srcDir,
159
+ tsconfigPath
160
+ };
161
+ }));
162
+ if (projects.length === 0) {
163
+ throw new Error(`No tsconfig.json files matched: ${inputs.join(', ')}`);
164
+ }
165
+ return projects;
166
+ }
167
+ export async function buildProjects(options = {}) {
168
+ const cwd = options.cwd ?? process.cwd();
169
+ const projects = await findProjects(options);
170
+ await Promise.all(projects.map(async (project) => {
171
+ await buildProject(project, options);
172
+ logInfo(`updated ${formatPath(project.distDir, cwd)} from ${formatPath(project.srcDir, cwd)} using ${formatPath(project.tsconfigPath, cwd)}`);
173
+ }));
174
+ return projects;
175
+ }
176
+ function createDebouncedProjectRunner(project, cwd, options) {
177
+ let closed = false;
178
+ let activeBuild;
179
+ let pendingReason;
180
+ let timer;
181
+ const run = async () => {
182
+ if (closed) {
183
+ return;
184
+ }
185
+ if (activeBuild) {
186
+ return;
187
+ }
188
+ const reason = pendingReason ?? 'change';
189
+ pendingReason = undefined;
190
+ activeBuild = (async () => {
191
+ logInfo(`rebuilding ${formatPath(project.tsconfigPath, cwd)} after ${reason}`);
192
+ await buildProject(project, options);
193
+ logInfo(`watch updated ${formatPath(project.distDir, cwd)}`);
194
+ })();
195
+ try {
196
+ await activeBuild;
197
+ }
198
+ finally {
199
+ activeBuild = undefined;
200
+ if (pendingReason) {
201
+ await run();
202
+ }
203
+ }
204
+ };
205
+ return {
206
+ close() {
207
+ closed = true;
208
+ if (timer) {
209
+ clearTimeout(timer);
210
+ timer = undefined;
211
+ }
212
+ },
213
+ schedule(reason) {
214
+ if (closed) {
215
+ return;
216
+ }
217
+ pendingReason = reason;
218
+ if (timer) {
219
+ clearTimeout(timer);
220
+ }
221
+ timer = setTimeout(() => {
222
+ timer = undefined;
223
+ void run().catch((error) => {
224
+ logError(`watch rebuild failed for ${formatPath(project.tsconfigPath, cwd)}: ${error.message}`);
225
+ });
226
+ }, 100);
227
+ }
228
+ };
229
+ }
230
+ function watchProject(project, cwd, options) {
231
+ const runner = createDebouncedProjectRunner(project, cwd, options);
232
+ const sourceWatcher = watch(project.srcDir, { recursive: true }, (_eventType, fileName) => {
233
+ const suffix = fileName ? ` (${fileName.toString()})` : '';
234
+ runner.schedule(`src change${suffix}`);
235
+ });
236
+ const configWatcher = watch(project.tsconfigPath, () => {
237
+ runner.schedule('tsconfig change');
238
+ });
239
+ return [
240
+ sourceWatcher,
241
+ configWatcher,
242
+ {
243
+ close() {
244
+ runner.close();
245
+ }
246
+ }
247
+ ];
248
+ }
249
+ export async function watchProjects(options = {}) {
250
+ const cwd = options.cwd ?? process.cwd();
251
+ const projects = await buildProjects(options);
252
+ const watchers = projects.flatMap((project) => watchProject(project, cwd, options));
253
+ logInfo(`watching ${projects.length} project(s)`);
254
+ return {
255
+ close() {
256
+ for (const watcher of watchers) {
257
+ watcher.close();
258
+ }
259
+ },
260
+ projects
261
+ };
262
+ }
263
+ export function parseCliArgs(args) {
264
+ const excludeAliases = [];
265
+ const inputs = [];
266
+ let watchMode = false;
267
+ for (let index = 0; index < args.length; index += 1) {
268
+ const arg = args[index];
269
+ if (arg === '-w' || arg === '--watch') {
270
+ watchMode = true;
271
+ continue;
272
+ }
273
+ if (arg === '--exclude-alias') {
274
+ const value = args[index + 1];
275
+ if (!value || value.startsWith('-')) {
276
+ throw new Error('Missing value for --exclude-alias');
277
+ }
278
+ excludeAliases.push(...value
279
+ .split(',')
280
+ .map((item) => item.trim())
281
+ .filter(Boolean));
282
+ index += 1;
283
+ continue;
284
+ }
285
+ if (arg.startsWith('--exclude-alias=')) {
286
+ excludeAliases.push(...arg
287
+ .slice('--exclude-alias='.length)
288
+ .split(',')
289
+ .map((item) => item.trim())
290
+ .filter(Boolean));
291
+ continue;
292
+ }
293
+ if (arg === '-h' || arg === '--help') {
294
+ printUsage();
295
+ process.exit(0);
296
+ }
297
+ if (arg.startsWith('-')) {
298
+ throw new Error(`Unknown option "${arg}"`);
299
+ }
300
+ inputs.push(arg);
301
+ }
302
+ return {
303
+ excludeAliases,
304
+ inputs,
305
+ watchMode
306
+ };
307
+ }
308
+ function printUsage() {
309
+ console.log([
310
+ 'Usage: resolve-paths [--watch] [tsconfig.json path or glob ...]',
311
+ '',
312
+ 'Examples:',
313
+ ' resolve-paths',
314
+ ' resolve-paths tsconfig.json',
315
+ " resolve-paths --exclude-alias '$shared,$generated' tsconfig.json",
316
+ " resolve-paths 'packages/*/tsconfig.json'",
317
+ " resolve-paths --watch 'packages/*/tsconfig.json'"
318
+ ].join('\n'));
319
+ }
320
+ function normalizeExecutablePath(targetPath) {
321
+ try {
322
+ return realpathSync.native(targetPath);
323
+ }
324
+ catch {
325
+ return resolve(targetPath);
326
+ }
327
+ }
328
+ export function isDirectExecution(entryPath = process.argv[1], moduleUrl = import.meta.url) {
329
+ if (!entryPath) {
330
+ return false;
331
+ }
332
+ return normalizeExecutablePath(entryPath) === normalizeExecutablePath(fileURLToPath(moduleUrl));
333
+ }
334
+ export async function main(args = process.argv.slice(2)) {
335
+ const { excludeAliases, inputs, watchMode } = parseCliArgs(args);
336
+ if (watchMode) {
337
+ await watchProjects({ excludeAliases, inputs });
338
+ return;
339
+ }
340
+ await buildProjects({ excludeAliases, inputs });
341
+ }
342
+ if (isDirectExecution()) {
343
+ void main().catch((error) => {
344
+ logError(error.message);
345
+ process.exit(1);
346
+ });
347
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=resolve-paths.unit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-paths.unit.test.d.ts","sourceRoot":"","sources":["../../src/lib/scripts/resolve-paths.unit.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,167 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { mkdir, mkdtemp, readFile, rm, symlink, unlink, writeFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import { pathToFileURL } from 'node:url';
6
+ import { buildProjects, isDirectExecution, watchProjects } from './resolve-paths.js';
7
+ const tempDirectories = [];
8
+ async function createTempDirectory(prefix) {
9
+ const directory = await mkdtemp(join(tmpdir(), prefix));
10
+ tempDirectories.push(directory);
11
+ return directory;
12
+ }
13
+ async function writeJson(filePath, value) {
14
+ await writeFile(filePath, JSON.stringify(value, null, 2));
15
+ }
16
+ async function createProject(root) {
17
+ await mkdir(join(root, 'src', 'lib'), { recursive: true });
18
+ await mkdir(join(root, 'src', 'components'), { recursive: true });
19
+ await writeJson(join(root, 'tsconfig.json'), {
20
+ compilerOptions: {
21
+ baseUrl: '.',
22
+ paths: {
23
+ '$components/*': ['src/components/*'],
24
+ '$lib/*': ['src/lib/*']
25
+ }
26
+ }
27
+ });
28
+ await writeFile(join(root, 'src', 'index.ts'), [
29
+ "import { answer } from '../utils';",
30
+ "import Button from '../components/Button.svelte';",
31
+ '',
32
+ 'export { answer, Button };',
33
+ ''
34
+ ].join('\n'));
35
+ await writeFile(join(root, 'src', 'lib', 'utils.ts'), 'export const answer = 42;\n');
36
+ await writeFile(join(root, 'src', 'components', 'Button.svelte'), '<button>Click</button>\n');
37
+ await writeFile(join(root, 'src', 'styles.css'), '.root { color: red; }\n');
38
+ }
39
+ async function createProjectWithExternalAlias(root) {
40
+ const sharedRoot = join(root, '..', 'shared');
41
+ await mkdir(join(root, 'src', 'lib'), { recursive: true });
42
+ await mkdir(sharedRoot, { recursive: true });
43
+ await writeJson(join(root, 'tsconfig.json'), {
44
+ compilerOptions: {
45
+ baseUrl: '.',
46
+ paths: {
47
+ '$lib/*': ['src/lib/*'],
48
+ '$shared/*': ['../shared/*']
49
+ }
50
+ },
51
+ include: ['src/**/*.ts']
52
+ });
53
+ await writeFile(join(root, 'src', 'index.ts'), [
54
+ "import { answer } from '../utils';",
55
+ "import { sharedAnswer } from '$shared/utils';",
56
+ '',
57
+ 'export { answer, sharedAnswer };',
58
+ ''
59
+ ].join('\n'));
60
+ await writeFile(join(root, 'src', 'lib', 'utils.ts'), 'export const answer = 42;\n');
61
+ await writeFile(join(sharedRoot, 'utils.ts'), 'export const sharedAnswer = 7;\n');
62
+ }
63
+ async function waitFor(assertion, timeoutMs = 5000) {
64
+ const deadline = Date.now() + timeoutMs;
65
+ let lastError;
66
+ while (Date.now() < deadline) {
67
+ try {
68
+ await assertion();
69
+ return;
70
+ }
71
+ catch (error) {
72
+ lastError = error;
73
+ await new Promise((resolve) => setTimeout(resolve, 50));
74
+ }
75
+ }
76
+ throw lastError;
77
+ }
78
+ describe('resolve-paths', () => {
79
+ beforeEach(() => {
80
+ vi.restoreAllMocks();
81
+ vi.spyOn(console, 'log').mockImplementation(() => { });
82
+ vi.spyOn(console, 'error').mockImplementation(() => { });
83
+ });
84
+ afterEach(async () => {
85
+ vi.restoreAllMocks();
86
+ await Promise.all(tempDirectories.splice(0).map((directory) => rm(directory, {
87
+ force: true,
88
+ recursive: true
89
+ })));
90
+ });
91
+ it('copies a project src tree into dist and resolves tsconfig path aliases', async () => {
92
+ const root = await createTempDirectory('resolve-paths-project-');
93
+ await createProject(root);
94
+ const projects = await buildProjects({
95
+ inputs: [join(root, 'tsconfig.json')]
96
+ });
97
+ expect(projects).toHaveLength(1);
98
+ await expect(readFile(join(root, 'dist', 'lib', 'utils.ts'), 'utf8')).resolves.toBe('export const answer = 42;\n');
99
+ await expect(readFile(join(root, 'dist', 'styles.css'), 'utf8')).resolves.toBe('.root { color: red; }\n');
100
+ const indexSource = await readFile(join(root, 'dist', 'index.ts'), 'utf8');
101
+ expect(indexSource).toContain("from './lib/utils'");
102
+ expect(indexSource).toContain("from './components/Button.svelte'");
103
+ expect(indexSource).not.toContain('$lib/utils');
104
+ expect(indexSource).not.toContain('$components/Button.svelte');
105
+ });
106
+ it('supports globbed tsconfig inputs across multiple projects', async () => {
107
+ const workspaceRoot = await createTempDirectory('resolve-paths-workspace-');
108
+ const packageARoot = join(workspaceRoot, 'packages', 'a');
109
+ const packageBRoot = join(workspaceRoot, 'packages', 'b');
110
+ await createProject(packageARoot);
111
+ await createProject(packageBRoot);
112
+ const projects = await buildProjects({
113
+ cwd: workspaceRoot,
114
+ inputs: ['packages/*/tsconfig.json']
115
+ });
116
+ expect(projects).toHaveLength(2);
117
+ const packageAIndex = await readFile(join(packageARoot, 'dist', 'index.ts'), 'utf8');
118
+ const packageBIndex = await readFile(join(packageBRoot, 'dist', 'index.ts'), 'utf8');
119
+ expect(packageAIndex).toContain("from './lib/utils'");
120
+ expect(packageBIndex).toContain("from './components/Button.svelte'");
121
+ });
122
+ it('does not resolve explicitly excluded aliases', async () => {
123
+ const root = await createTempDirectory('resolve-paths-excluded-alias-');
124
+ await createProjectWithExternalAlias(root);
125
+ await buildProjects({
126
+ excludeAliases: ['$shared'],
127
+ inputs: [join(root, 'tsconfig.json')]
128
+ });
129
+ const indexSource = await readFile(join(root, 'dist', 'index.ts'), 'utf8');
130
+ expect(indexSource).toContain("from './lib/utils'");
131
+ expect(indexSource).toContain("from '$shared/utils'");
132
+ expect(indexSource).not.toContain('../shared/utils');
133
+ });
134
+ it('rebuilds dist in watch mode when src files change or are removed', async () => {
135
+ const root = await createTempDirectory('resolve-paths-watch-');
136
+ await createProject(root);
137
+ const watcher = await watchProjects({
138
+ inputs: [join(root, 'tsconfig.json')]
139
+ });
140
+ try {
141
+ await writeFile(join(root, 'src', 'index.ts'), ["import { answer } from '../utils';", '', 'export const doubled = answer * 2;', ''].join('\n'));
142
+ await unlink(join(root, 'src', 'styles.css'));
143
+ await waitFor(async () => {
144
+ const indexSource = await readFile(join(root, 'dist', 'index.ts'), 'utf8');
145
+ expect(indexSource).toContain("from './lib/utils'");
146
+ expect(indexSource).toContain('export const doubled = answer * 2;');
147
+ expect(indexSource).not.toContain('$lib/utils');
148
+ });
149
+ await waitFor(async () => {
150
+ await expect(readFile(join(root, 'dist', 'styles.css'), 'utf8')).rejects.toMatchObject({
151
+ code: 'ENOENT'
152
+ });
153
+ });
154
+ }
155
+ finally {
156
+ watcher.close();
157
+ }
158
+ });
159
+ it('treats symlinked entry paths as direct execution of the same module', async () => {
160
+ const root = await createTempDirectory('resolve-paths-symlink-');
161
+ const actualFilePath = join(root, 'actual.js');
162
+ const symlinkPath = join(root, 'linked.js');
163
+ await writeFile(actualFilePath, 'export {};\n');
164
+ await symlink(actualFilePath, symlinkPath);
165
+ expect(isDirectExecution(symlinkPath, pathToFileURL(actualFilePath).href)).toBe(true);
166
+ });
167
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"vite-plugin-component-source-collector.d.ts","sourceRoot":"","sources":["../../src/lib/vite/vite-plugin-component-source-collector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAkB,MAAM,MAAM,CAAC;AAMnD,UAAU,OAAO;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B;;OAEG;IACH,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AA2CD,wBAA8B,wBAAwB,CAAC,IAAI,GAAE,OAA8B,GAAG,OAAO,CAAC,MAAM,CAAC,CAuN5G"}
1
+ {"version":3,"file":"vite-plugin-component-source-collector.d.ts","sourceRoot":"","sources":["../../src/lib/vite/vite-plugin-component-source-collector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAkB,MAAM,MAAM,CAAC;AAMnD,UAAU,OAAO;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B;;OAEG;IACH,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AA4CD,wBAA8B,wBAAwB,CAAC,IAAI,GAAE,OAA8B,GAAG,OAAO,CAAC,MAAM,CAAC,CA2M5G"}
@@ -93,7 +93,6 @@ export default async function componentSourceCollector(opts = { safePackages: []
93
93
  const relativeFilePath = toPosixPath(relative(dirname(outputFilePath), normalizedFilePath));
94
94
  if (normalizedFilePath === outputFilePath || relativeFilePath === outFileName)
95
95
  return;
96
- // Dont add itself
97
96
  componentFiles.add(ensureDotRelative(relativeFilePath));
98
97
  }
99
98
  function scheduleInitialWrite() {
@@ -101,14 +100,14 @@ export default async function componentSourceCollector(opts = { safePackages: []
101
100
  clearTimeout(initialTransformTimer);
102
101
  initialTransformTimer = setTimeout(() => {
103
102
  if (!initialTransformDone) {
104
- writeOutFile();
103
+ void writeOutFile();
105
104
  initialTransformDone = true;
106
105
  }
107
106
  }, 1000);
108
107
  }
109
108
  const writeOutFile = async () => {
110
109
  const lines = Array.from(componentFiles)
111
- .map((d) => `@source '${d}';`)
110
+ .map((filePath) => `@source '${filePath}';`)
112
111
  .sort();
113
112
  if (outputFilePath) {
114
113
  const didWrite = await writeIfDifferent(outputFilePath, lines.join('\n'));
@@ -116,13 +115,9 @@ export default async function componentSourceCollector(opts = { safePackages: []
116
115
  console.log('tailwind-sources:wrote', lines.length);
117
116
  }
118
117
  };
119
- // ---- plugin ---- //
120
118
  return {
121
119
  name: 'vite-plugin-component-source-collector',
122
- enforce: 'pre', // i want to see comments
123
- /**
124
- * Setup. Add exisitng files to internal state if dev
125
- */
120
+ enforce: 'pre',
126
121
  async configResolved(resolved) {
127
122
  config = resolved;
128
123
  outputFilePath = resolve(config.root, outFileName);
@@ -132,8 +127,7 @@ export default async function componentSourceCollector(opts = { safePackages: []
132
127
  nodeModulesPath = join(current, 'node_modules');
133
128
  break;
134
129
  }
135
- else
136
- current = dirname(current);
130
+ current = dirname(current);
137
131
  }
138
132
  console.log('tailwind-sources:configResolved: Command is', config.command);
139
133
  await touch(outputFilePath);
@@ -176,9 +170,8 @@ export default async function componentSourceCollector(opts = { safePackages: []
176
170
  'bun.lockb',
177
171
  'bun.lock',
178
172
  'npm-shrinkwrap.json',
179
- // pnpm install-state changes:
180
173
  'node_modules/.modules.yaml'
181
- ].map((p) => join(config.root, p));
174
+ ].map((path) => join(config.root, path));
182
175
  server.watcher.add(lockFiles);
183
176
  const onChange = async (file) => {
184
177
  if (!lockFiles.includes(file))
@@ -198,7 +191,6 @@ export default async function componentSourceCollector(opts = { safePackages: []
198
191
  if (id.includes('css') && code.includes('@import')) {
199
192
  const matches = code.matchAll(importRegex);
200
193
  for (const match of matches) {
201
- // console.log('MATching', match);
202
194
  try {
203
195
  const resolved = await this.resolve(match[1], id);
204
196
  if (resolved) {
@@ -206,11 +198,10 @@ export default async function componentSourceCollector(opts = { safePackages: []
206
198
  }
207
199
  }
208
200
  catch {
209
- // Cant resolve: dont add
201
+ // Ignore unresolved CSS imports while building the Tailwind source list.
210
202
  }
211
203
  }
212
204
  }
213
- // Adds all other files with the classRegex
214
205
  if (shouldAdd(code, id)) {
215
206
  await addPath(id);
216
207
  }
@@ -218,7 +209,7 @@ export default async function componentSourceCollector(opts = { safePackages: []
218
209
  scheduleInitialWrite();
219
210
  }
220
211
  },
221
- async handleHotUpdate(_ctx) {
212
+ async handleHotUpdate() {
222
213
  await writeOutFile();
223
214
  },
224
215
  async buildEnd() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-ag",
3
- "version": "1.0.67",
3
+ "version": "1.0.68",
4
4
  "description": "Useful svelte components",
5
5
  "bugs": "https://github.com/ageorgeh/svelte-ag/issues",
6
6
  "repository": {
@@ -25,6 +25,9 @@
25
25
  "default": "./dist/*"
26
26
  }
27
27
  },
28
+ "bin": {
29
+ "resolve-paths": "dist/scripts/resolve-paths.js"
30
+ },
28
31
  "files": [
29
32
  "./src/lib",
30
33
  "./dist"
@@ -60,6 +63,7 @@
60
63
  "tailwind-merge": "^3.5.0",
61
64
  "tailwind-variants": "^3.2.2",
62
65
  "ts-ag": "^1.1.14",
66
+ "tsc-alias": "^1.8.16",
63
67
  "valibot": "^1.3.1"
64
68
  },
65
69
  "devDependencies": {