-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
paths.ts
168 lines (141 loc) · 6.57 KB
/
paths.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import {join, basename, extname, relative} from 'node:path';
import {fileURLToPath} from 'node:url';
import {strip_end, strip_start} from '@ryanatkn/belt/string.js';
import {gray} from 'kleur/colors';
import type {Flavored} from '@ryanatkn/belt/types.js';
import {z} from 'zod';
/*
A path `id` is an absolute path to the source/.gro/dist directory.
It's the same nomenclature that Rollup uses.
A `base_path` is the format used by `CheapWatch`.
It's a bare relative path without a source or .gro directory,
e.g. 'foo/bar.ts'.
`CheapWatch` also uses an array of `path_parts`.
For path './foo/bar/baz.ts',
the `path_parts` are `['foo', 'foo/bar', 'foo/bar/baz.ts']`.
*/
// TODO pass these to `create_paths` and override from gro config
// TODO this is kinda gross - do we want to maintain the convention to have the trailing slash in most usage?
export const SOURCE_DIRNAME = 'src';
export const GRO_DIRNAME = '.gro';
export const GRO_DIST_PREFIX = 'dist_'; //
export const SERVER_DIST_PATH = 'dist_server'; // TODO should all of these be `_PATH` or should this be `DIRNAME`?
export const LIB_DIRNAME = 'lib'; // TODO use Svelte config `files.lib`
export const ROUTES_DIRNAME = 'routes'; // TODO use Svelte config `files.lib`
export const GRO_DEV_DIRNAME = GRO_DIRNAME + '/dev';
export const SOURCE_DIR = SOURCE_DIRNAME + '/';
export const GRO_DIR = GRO_DIRNAME + '/';
export const GRO_DEV_DIR = GRO_DEV_DIRNAME + '/';
export const LIB_PATH = SOURCE_DIR + LIB_DIRNAME;
export const LIB_DIR = LIB_PATH + '/'; // TODO @multiple get from the sveltekit config
export const CONFIG_PATH = 'gro.config.ts';
export const README_FILENAME = 'README.md';
export const SVELTEKIT_CONFIG_FILENAME = 'svelte.config.js';
export const VITE_CONFIG_FILENAME = 'vite.config.ts';
export const SVELTEKIT_DEV_DIRNAME = '.svelte-kit'; // TODO use Svelte config value `outDir`
export const SVELTEKIT_BUILD_DIRNAME = 'build';
export const SVELTEKIT_DIST_DIRNAME = 'dist';
export const NODE_MODULES_DIRNAME = 'node_modules';
export const SVELTEKIT_VITE_CACHE_PATH = NODE_MODULES_DIRNAME + '/.vite';
export const GITHUB_DIRNAME = '.github';
export const GIT_DIRNAME = '.git';
export const TSCONFIG_FILENAME = 'tsconfig.json';
export interface Paths {
root: string;
source: string;
lib: string;
build: string;
build_dev: string;
config: string;
}
// TODO upstream to util, and probably add `Path`/`FilePath` and `FileUrl`
export const Url = z.string();
export type Url = Flavored<z.infer<typeof Url>, 'Url'>;
export const Email = z.string();
export type Email = Flavored<z.infer<typeof Email>, 'Email'>;
export const Source_Id = z.string();
export type Source_Id = Flavored<z.infer<typeof Source_Id>, 'Source_Id'>;
export const Build_Id = z.string();
export type Build_Id = Flavored<z.infer<typeof Build_Id>, 'Build_Id'>;
export const create_paths = (root_dir: string): Paths => {
// TODO remove reliance on trailing slash towards windows support
const root = strip_end(root_dir, '/') + '/';
return {
root,
source: root + SOURCE_DIR,
lib: root + LIB_DIR, // TODO @multiple get from the sveltekit config
build: root + GRO_DIR,
build_dev: root + GRO_DEV_DIR,
config: root + CONFIG_PATH,
};
};
export const paths_from_id = (id: string): Paths => (is_gro_id(id) ? gro_paths : paths);
export const is_gro_id = (id: string): boolean => id.startsWith(gro_paths.root);
// TODO maybe infer `p` for the functions that take in ids using `paths_from_id`?
// '/home/me/app/src/foo/bar/baz.ts' → 'src/foo/bar/baz.ts'
export const to_root_path = (id: string, p = paths): string => strip_start(id, p.root);
// '/home/me/app/src/foo/bar/baz.ts' → 'foo/bar/baz.ts'
export const source_id_to_base_path = (source_id: Source_Id, p = paths): string =>
relative(p.source, source_id);
// TODO base_path is an obsolete concept, it was a remnant from forcing `src/`
// 'foo/bar/baz.ts' → '/home/me/app/src/foo/bar/baz.ts'
export const base_path_to_source_id = (base_path: string, p = paths): Source_Id =>
join(p.source, base_path);
// To run Gro's tasks from its own project, we resolve from dist/ instead of src/.
// 'foo/bar/baz.ts' → '/home/me/app/src/lib/foo/bar/baz.ts'
// 'foo/bar/baz.ts' → '/home/me/app/dist/foo/bar/baz.ts'
export const lib_path_to_import_id = (base_path: string, p = paths): Source_Id => {
if (p.root === gro_paths.root) {
return p.root + 'dist/' + base_path;
} else {
return base_path_to_source_id(LIB_DIRNAME + '/' + base_path, p);
}
};
// An `import_id` can be a source_id in a project,
// or a Gro source_id when running inside Gro,
// or a `gro/dist/` file id in node_modules when inside another project.
export const import_id_to_lib_path = (import_id: string, p = paths_from_id(import_id)): string => {
if (p.root === gro_paths.root) {
const stripped = strip_start(strip_start(import_id, p.lib), gro_sveltekit_dist_dir); // TODO hacky, needs more work to clarify related things
const lib_path = is_this_project_gro ? stripped : replace_extension(stripped, '.ts');
return lib_path;
} else {
return strip_start(import_id, p.lib);
}
};
export const to_gro_input_path = (input_path: string): string => {
const base_path = input_path === paths.lib.slice(0, -1) ? '' : strip_start(input_path, paths.lib);
return gro_sveltekit_dist_dir + base_path;
};
// Can be used to map a source id from e.g. the cwd to gro's.
export const replace_root_dir = (id: string, root_dir: string, p = paths): string =>
join(root_dir, to_root_path(id, p));
export const print_path = (path: string, p = paths, prefix = './'): string => {
const root_path = path === gro_sveltekit_dist_dir ? 'gro' : to_root_path(path, p);
return gray(`${prefix}${root_path}`);
};
export const print_path_or_gro_path = (path: string, from_paths = paths): string => {
const inferred_paths = paths_from_id(path);
if (from_paths === gro_paths || inferred_paths === from_paths) {
return print_path(path, inferred_paths, '');
}
return print_path(path, gro_paths, '');
};
export const replace_extension = (path: string, new_extension: string): string => {
const {length} = extname(path);
return (length === 0 ? path : path.substring(0, path.length - length)) + new_extension;
};
const filename = fileURLToPath(import.meta.url);
const gro_dir = join(
filename,
filename.includes('/gro/src/lib/')
? '../../../'
: filename.includes('/gro/dist/')
? '../../'
: '../',
);
export const gro_dir_basename = basename(gro_dir) + '/';
export const paths = create_paths(process.cwd() + '/');
export const is_this_project_gro = gro_dir === paths.root;
export const gro_paths = is_this_project_gro ? paths : create_paths(gro_dir);
export const gro_sveltekit_dist_dir = gro_paths.root + SVELTEKIT_DIST_DIRNAME + '/';