svelte-ag 1.3.0 → 1.3.1

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.
Files changed (39) hide show
  1. package/dist/bin/build-tailwind-manifest/build-tailwind-manifest.unit.test.d.ts.map +1 -0
  2. package/dist/bin/build-tailwind-manifest/build-tailwind-manifest.unit.test.js +386 -0
  3. package/dist/bin/build-tailwind-manifest/cli.d.ts +2 -0
  4. package/dist/bin/build-tailwind-manifest/cli.d.ts.map +1 -0
  5. package/dist/bin/build-tailwind-manifest/cli.js +122 -0
  6. package/dist/bin/build-tailwind-manifest/graph.d.ts +9 -0
  7. package/dist/bin/build-tailwind-manifest/graph.d.ts.map +1 -0
  8. package/dist/bin/build-tailwind-manifest/graph.js +405 -0
  9. package/dist/bin/build-tailwind-manifest/index.d.ts +1 -0
  10. package/dist/bin/build-tailwind-manifest/index.js +6 -0
  11. package/dist/bin/build-tailwind-manifest/manifest-generator.d.ts +7 -0
  12. package/dist/bin/build-tailwind-manifest/manifest-generator.d.ts.map +1 -0
  13. package/dist/bin/build-tailwind-manifest/manifest-generator.js +85 -0
  14. package/dist/bin/build-tailwind-manifest/path-utils.d.ts +6 -0
  15. package/dist/bin/build-tailwind-manifest/path-utils.d.ts.map +1 -0
  16. package/dist/bin/build-tailwind-manifest/path-utils.js +41 -0
  17. package/dist/bin/build-tailwind-manifest/types.d.ts +15 -0
  18. package/dist/bin/build-tailwind-manifest/types.d.ts.map +1 -0
  19. package/dist/bin/build-tailwind-manifest/types.js +1 -0
  20. package/dist/tailwind-sources.manifest.jsonc +193 -3
  21. package/dist/vite/vite-plugin-component-source-collector.d.ts.map +1 -1
  22. package/dist/vite/vite-plugin-component-source-collector.js +1 -6
  23. package/package.json +4 -3
  24. package/src/lib/bin/build-tailwind-manifest/build-tailwind-manifest.unit.test.ts +591 -0
  25. package/src/lib/bin/build-tailwind-manifest/cli.ts +147 -0
  26. package/src/lib/bin/build-tailwind-manifest/graph.ts +521 -0
  27. package/src/lib/bin/build-tailwind-manifest/index.ts +8 -0
  28. package/src/lib/bin/build-tailwind-manifest/manifest-generator.ts +119 -0
  29. package/src/lib/bin/build-tailwind-manifest/path-utils.ts +53 -0
  30. package/src/lib/bin/build-tailwind-manifest/types.ts +18 -0
  31. package/src/lib/vite/vite-plugin-component-source-collector.ts +1 -6
  32. package/dist/bin/build-tailwind-manifest.d.ts +0 -15
  33. package/dist/bin/build-tailwind-manifest.d.ts.map +0 -1
  34. package/dist/bin/build-tailwind-manifest.js +0 -581
  35. package/dist/bin/build-tailwind-manifest.unit.test.d.ts.map +0 -1
  36. package/dist/bin/build-tailwind-manifest.unit.test.js +0 -208
  37. package/src/lib/bin/build-tailwind-manifest.ts +0 -757
  38. package/src/lib/bin/build-tailwind-manifest.unit.test.ts +0 -309
  39. /package/dist/bin/{build-tailwind-manifest.unit.test.d.ts → build-tailwind-manifest/build-tailwind-manifest.unit.test.d.ts} +0 -0
@@ -0,0 +1,119 @@
1
+ import path from 'node:path';
2
+
3
+ import { readPackageJson, writeIfDifferent } from 'ts-ag';
4
+ import type { PackageJson } from 'type-fest';
5
+
6
+ import {
7
+ getTailwindSourcesManifestPath,
8
+ serializeTailwindSourceManifest,
9
+ shouldIncludeManifestExport,
10
+ type TailwindSourceManifest,
11
+ type TailwindSourceManifestLeaf,
12
+ type TailwindSourcePackageJsonLike
13
+ } from '../../vite/tailwind-sources-manifest.js';
14
+ import { createGraphScanner } from './graph.js';
15
+ import { resolvePackageEntryFile } from './path-utils.js';
16
+ import type { GeneratorOptions, GraphScan, SymbolManifest } from './types.js';
17
+
18
+ export async function generateTailwindManifestForPackage(
19
+ packageDir: string,
20
+ options: GeneratorOptions
21
+ ): Promise<{ didWrite: boolean; outputFile: string; exportCount: number }> {
22
+ const packageJson = (await readPackageJson(path.join(packageDir, 'package.json'))) as PackageJson &
23
+ TailwindSourcePackageJsonLike;
24
+ if (!packageJson) throw new Error(`No package.json found in ${packageDir}`);
25
+
26
+ const manifest: TailwindSourceManifest = { version: 1, exports: {} };
27
+ const exports = collectPackageExportEntries(packageJson.exports).filter(([exportKey]) =>
28
+ shouldIncludeManifestExport(exportKey, options.exportFilters)
29
+ );
30
+ const graphScanner = createGraphScanner(packageDir);
31
+
32
+ await Promise.all(
33
+ exports.map(async ([exportKey, exportTarget]) => {
34
+ if (exportKey.includes('*') || hasWildcardTarget(exportTarget)) {
35
+ console.warn(`[tailwind-manifest] Skipping wildcard export ${exportKey} in ${packageDir}`);
36
+ } else {
37
+ const entryFiles = collectRuntimeTargets(exportTarget)
38
+ .map((target) => resolvePackageEntryFile(packageDir, target))
39
+ .filter((targetPath): targetPath is string => targetPath !== null);
40
+
41
+ if (entryFiles.length === 0) return;
42
+
43
+ const manifestEntry = toManifestLeaf(await graphScanner.scanFileGraph(entryFiles));
44
+ const symbols = await collectExportSymbols(entryFiles, graphScanner);
45
+
46
+ manifest.exports[exportKey] = Object.keys(symbols).length > 0 ? { ...manifestEntry, symbols } : manifestEntry;
47
+ }
48
+ })
49
+ );
50
+
51
+ const outputFile = getTailwindSourcesManifestPath(packageDir, packageJson);
52
+ const didWrite = await writeIfDifferent(outputFile, serializeTailwindSourceManifest(manifest));
53
+ return { didWrite, outputFile, exportCount: Object.keys(manifest.exports).length };
54
+ }
55
+
56
+ async function collectExportSymbols(
57
+ entryFiles: string[],
58
+ graphScanner: ReturnType<typeof createGraphScanner>
59
+ ): Promise<SymbolManifest> {
60
+ const symbols = new Map<string, GraphScan>();
61
+
62
+ for (const entryFile of entryFiles) {
63
+ const targets = await graphScanner.readEntrySymbolTargets(entryFile);
64
+ await Promise.all(
65
+ targets.entries().map(async ([symbolName, targetFile]) => {
66
+ const scan = await graphScanner.scanFileGraph([targetFile]);
67
+ const existing = symbols.get(symbolName);
68
+
69
+ if (existing) {
70
+ for (const className of scan.classes) existing.classes.add(className);
71
+ for (const sourcePath of scan.sources) existing.sources.add(sourcePath);
72
+ } else {
73
+ symbols.set(symbolName, { classes: new Set(scan.classes), sources: new Set(scan.sources) });
74
+ }
75
+ })
76
+ );
77
+ }
78
+
79
+ return Object.fromEntries(
80
+ [...symbols.entries()]
81
+ .sort(([left], [right]) => left.localeCompare(right))
82
+ .map(([symbolName, scan]) => [symbolName, toManifestLeaf(scan)])
83
+ );
84
+ }
85
+
86
+ function toManifestLeaf(scan: GraphScan): TailwindSourceManifestLeaf {
87
+ return { classes: [...scan.classes].sort(), sources: [...scan.sources].sort() };
88
+ }
89
+
90
+ function collectRuntimeTargets(target: PackageJson.Exports): string[] {
91
+ if (target === null) return [];
92
+ if (typeof target === 'string') {
93
+ return target.endsWith('.d.ts') ? [] : [target];
94
+ }
95
+
96
+ if (Array.isArray(target)) {
97
+ return target.flatMap(collectRuntimeTargets);
98
+ }
99
+
100
+ return Object.entries(target).flatMap(([key, value]) => (key === 'types' ? [] : collectRuntimeTargets(value)));
101
+ }
102
+
103
+ function hasWildcardTarget(target: PackageJson.Exports): boolean {
104
+ if (target === null) return false;
105
+ return typeof target === 'string'
106
+ ? target.includes('*')
107
+ : Array.isArray(target)
108
+ ? target.some(hasWildcardTarget)
109
+ : Object.values(target).some(hasWildcardTarget);
110
+ }
111
+
112
+ function collectPackageExportEntries(exports: PackageJson.Exports | undefined): [string, PackageJson.Exports][] {
113
+ if (exports === undefined) return [];
114
+ if (exports === null || typeof exports === 'string' || Array.isArray(exports)) return [['.', exports]];
115
+
116
+ const entries = Object.entries(exports);
117
+ const hasSubpathExports = entries.some(([key]) => key === '.' || key.startsWith('./'));
118
+ return hasSubpathExports ? entries : [['.', exports]];
119
+ }
@@ -0,0 +1,53 @@
1
+ import { existsSync, statSync } from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ export function isRelativeSpecifier(specifier: string): boolean {
5
+ return specifier.startsWith('./') || specifier.startsWith('../') || specifier.startsWith('/');
6
+ }
7
+
8
+ export function resolveLocalImportPath(specifier: string, importerPath: string): string | null {
9
+ return resolveFileCandidate(path.resolve(path.dirname(importerPath), specifier.split(/[?#]/, 1)[0] ?? specifier));
10
+ }
11
+
12
+ export function resolvePackageEntryFile(packageDir: string, entryTarget: string): string | null {
13
+ return resolveFileCandidate(
14
+ path.resolve(packageDir, entryTarget.startsWith('./') ? entryTarget : `./${entryTarget}`)
15
+ );
16
+ }
17
+
18
+ export function isPathInside(parentPath: string, childPath: string): boolean {
19
+ const relativePath = path.relative(parentPath, childPath);
20
+ return relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));
21
+ }
22
+
23
+ export function toPosixPath(filePath: string): string {
24
+ return filePath.replaceAll('\\', '/');
25
+ }
26
+
27
+ function resolveFileCandidate(targetPath: string): string | null {
28
+ for (const candidate of [
29
+ ...buildBaseCandidates(targetPath),
30
+ ...buildBaseCandidates(path.join(targetPath, 'index'))
31
+ ]) {
32
+ if (existsSync(candidate) && statSync(candidate).isFile()) {
33
+ return candidate;
34
+ }
35
+ }
36
+
37
+ return null;
38
+ }
39
+
40
+ function buildBaseCandidates(basePath: string): string[] {
41
+ const candidates = new Set([basePath, `${basePath}.js`, `${basePath}.mjs`, `${basePath}.cjs`]);
42
+
43
+ for (const candidateBase of [basePath.replace(/\.(?:mjs|cjs|js)$/i, ''), basePath]) {
44
+ candidates.add(`${candidateBase}.ts`);
45
+ candidates.add(`${candidateBase}.tsx`);
46
+ candidates.add(`${candidateBase}.jsx`);
47
+ candidates.add(`${candidateBase}.svelte`);
48
+ candidates.add(`${candidateBase}.svelte.ts`);
49
+ candidates.add(`${candidateBase}.css`);
50
+ }
51
+
52
+ return [...candidates];
53
+ }
@@ -0,0 +1,18 @@
1
+ import type { TailwindSourceManifestLeaf } from '../../vite/tailwind-sources-manifest.js';
2
+
3
+ export type GeneratorOptions = {
4
+ exportFilters: string[];
5
+ };
6
+
7
+ export type GraphScan = {
8
+ classes: Set<string>;
9
+ sources: Set<string>;
10
+ };
11
+
12
+ export type CliOptions = {
13
+ exportFilters: string[];
14
+ packagePatterns: string[];
15
+ watch: boolean;
16
+ };
17
+
18
+ export type SymbolManifest = Record<string, TailwindSourceManifestLeaf>;
@@ -5,6 +5,7 @@ import { resolve, join, relative, dirname, isAbsolute, parse as parsePath } from
5
5
  import { init, parse as parseEsm } from 'es-module-lexer';
6
6
  import { parse as parseSvelte } from 'svelte/compiler';
7
7
  import { exists, writeIfDifferent } from 'ts-ag';
8
+ import { ensureDotRelative } from 'ts-ag';
8
9
  import type { Plugin, ResolvedConfig } from 'vite';
9
10
 
10
11
  import {
@@ -50,12 +51,6 @@ const packageJsonCache = new Map<string, Promise<string | null>>();
50
51
  const packageManifestCache = new Map<string, Promise<TailwindSourceManifest | null>>();
51
52
  const TAILWIND_TOKEN_PROPERTY_PATTERN = String.raw`(?:class|(?:"[^"\n]*class[^"\n]*"|'[^'\n]*class[^'\n]*'|[A-Za-z_$][\w$]*class[\w$]*))`;
52
53
 
53
- // TODO replace with ts-ag method
54
- function ensureDotRelative(filePath: string): string {
55
- if (filePath.startsWith('./')) return filePath;
56
- return `./${filePath}`;
57
- }
58
-
59
54
  async function touch(path: string) {
60
55
  const handle = await open(path, 'a');
61
56
  await handle.close();
@@ -1,15 +0,0 @@
1
- //#region dist/bin/build-tailwind-manifest.d.ts
2
- type GeneratorOptions = {
3
- exportFilters: string[];
4
- };
5
- /** Build a Tailwind source manifest for one package export map. */
6
- declare function generateTailwindManifestForPackage(packageDir: string, options: GeneratorOptions): Promise<{
7
- didWrite: boolean;
8
- outputFile: string;
9
- exportCount: number;
10
- }>;
11
- /** Run the manifest builder once or in watch mode from the current working directory. */
12
- declare function main(argv?: string[]): Promise<void>;
13
- //#endregion
14
- export { generateTailwindManifestForPackage, main };
15
- //# sourceMappingURL=build-tailwind-manifest.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"build-tailwind-manifest.d.ts","names":["exportFilters","packageDir","GeneratorOptions","options","Promise","didWrite","outputFile","exportCount","argv"],"sources":["../../home/runner/work/svelte-ag/svelte-ag/dist/bin/build-tailwind-manifest.d.ts"],"mappings":";KAAK,gBAAA;EACDA,aAAa;AAAA;;iBAGO,kCAAA,CAAmCC,UAAAA,UAAoBE,OAAAA,EAAS,gBAAA,GAAmB,OAAO;EAC9GE,QAAAA;EACAC,UAAAA;EACAC,WAAAA;AAAAA;;iBAGoB,IAAA,CAAKC,IAAAA,cAAkB,OAAO"}