giget 0.1.0 → 0.1.3

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/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  ✔ Support popular git providers (GitHub, GitLab, and Bitbucket) out of the box.
13
13
 
14
- ✔ Built-in and custom template registry.
14
+ ✔ Built-in and custom [template registry](#template-registry).
15
15
 
16
16
  ✔ Fast cloning using tarball gzip without depending on local `git` and `tar`.
17
17
 
@@ -24,22 +24,15 @@
24
24
  ## Usage (CLI)
25
25
 
26
26
  ```bash
27
- npx giget@latest <repo> [<dir>] [...options]
27
+ npx giget@latest <template> [<dir>] [...options]
28
28
  ```
29
29
 
30
- ```bash
31
- npx giget@latest unjs/template my-lib
32
- # ✨ Successfully cloned https://github.com/unjs/template/tree/main/ to my-lib
33
- ```
30
+ ### Arguments
34
31
 
35
- **Arguments:**
32
+ - **template**: Template name or a a URI describing provider, repository, subdir, and branch/ref. (See [Examples](#examples))
33
+ - **dir**: A relative or absolute path where to extract the template.
36
34
 
37
- - **repo**: A URI describing provider, repository, subdir, and branch/ref.
38
- - Format is `[provider]:repo[/subpath][#ref]`.
39
- - **dir**: A relative or absolute path where to extract the repository.
40
- - If not provided, the name of the org + repo will be used as the name.
41
-
42
- **Options:**
35
+ ### Options
43
36
 
44
37
  - `--force`: Clone to exsiting directory even if exists.
45
38
  - `--offline`: Do not attempt to download and use cached version.
@@ -48,8 +41,9 @@ npx giget@latest unjs/template my-lib
48
41
  - `--shell`: ⚠️ Open a new shell with current working directory in cloned dir. (Experimental).
49
42
  - `--registry`: URL to a custom registry.
50
43
  - `--no-registry`: Disable registry lookup and functionality.
44
+ - `--verbose`: Show verbose debugging info.
51
45
 
52
- **Examples:**
46
+ ### Examples
53
47
 
54
48
  ```sh
55
49
  # Clone the main branch of github.com/unjs/template to unjs-template directory
@@ -82,15 +76,12 @@ If you want to add your template to the built-in registry, just drop a PR to add
82
76
 
83
77
  ### Custom Registry
84
78
 
85
- A custom registry should provide one required and one optional endpoint:
79
+ A custom registry should provide an endpoint with dynamic path `/:template.json` that returns a JSON response with keys same as [custom providers](#custom-providers).
86
80
 
87
- - `/:template.json`: (Required) Returns a JSON object same as custom provider response. Keys:
88
81
  - `name`: (required) Name of the template. It will be used as default cloning dir too.
89
82
  - `tar` (required) Link to the tar download link.
90
83
  - `url`: (optional) Webpage of the template.
91
- - `subpath` (optional) Subpath of the tar file to clone.
92
- - `/_info.json`: (Optional) Returns a JSON object with following keys:
93
- - `templates`: A string array of possible templates.
84
+ - `subpath` (optional) Subpath inside the tar file.
94
85
 
95
86
  Because of the simplicity, you can even use a github repository as template registry but also you can build something more powerful by bringing your own API.
96
87
 
@@ -152,7 +143,7 @@ The return value is a promise that resolves to the resolved template.
152
143
  - [other provider template keys]
153
144
  - `url`: (string) URL of repostiroy that can be opened in browser. Useful for logging.
154
145
 
155
- ## Custom providers
146
+ ## Custom Providers
156
147
 
157
148
  Using programmatic method, you can make your own custom template providers.
158
149
 
@@ -171,6 +162,17 @@ const rainbow: TemplateProvider = async (input) => {
171
162
  const { source, dir } = await downloadRepo('rainbow:one', { providers: { rainbow } })
172
163
  ```
173
164
 
165
+ ### Custom Registry Providers
166
+
167
+ You can define additional [custom registry](#custom-registry) providers using `registryProvider` utility and register to `providers`.
168
+
169
+ ```ts
170
+ import { registryProvider } from 'giget'
171
+
172
+ const themes = registryProvider('https://raw.githubusercontent.com/unjs/giget/main/templates')
173
+
174
+ const { source, dir } = await downloadRepo('themes:test', { providers: { themes } })
175
+ ```
174
176
 
175
177
  ## 💻 Development
176
178
 
package/dist/cli.cjs CHANGED
@@ -4,7 +4,7 @@
4
4
  const node_path = require('node:path');
5
5
  const mri = require('mri');
6
6
  const colorette = require('colorette');
7
- const giget = require('./shared/giget.9473a836.cjs');
7
+ const giget = require('./shared/giget.2ac4718b.cjs');
8
8
  require('node:fs/promises');
9
9
  require('node:os');
10
10
  require('node:fs');
@@ -19,13 +19,18 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
19
19
  const mri__default = /*#__PURE__*/_interopDefaultLegacy(mri);
20
20
 
21
21
  async function main() {
22
- const args = mri__default(process.argv.slice(2));
22
+ const args = mri__default(process.argv.slice(2), {
23
+ boolean: ["help", "force", "force-clean", "offline", "prefer-offline", "shell", "registry", "verbose"]
24
+ });
23
25
  const input = args._[0];
24
26
  const dir = args._[1];
25
27
  if (!input || args.help || args.h) {
26
- console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry]");
28
+ console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose]");
27
29
  process.exit(1);
28
30
  }
31
+ if (args.verbose) {
32
+ process.env.DEBUG = process.env.DEBUG || "true";
33
+ }
29
34
  const r = await giget.downloadTemplate(input, {
30
35
  dir,
31
36
  force: args.force,
@@ -33,7 +38,7 @@ async function main() {
33
38
  offline: args.offline,
34
39
  registry: args.registry
35
40
  });
36
- console.log(`\u2728 Successfully cloned ${colorette.cyan(r.url)} to ${colorette.cyan(node_path.relative(process.cwd(), r.dir))}
41
+ console.log(`\u2728 Successfully cloned ${colorette.cyan(r.name || r.url)} to ${colorette.cyan(node_path.relative(process.cwd(), r.dir))}
37
42
  `);
38
43
  if (args.shell) {
39
44
  giget.startShell(r.dir);
package/dist/cli.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { relative } from 'node:path';
3
3
  import mri from 'mri';
4
4
  import { cyan } from 'colorette';
5
- import { d as downloadTemplate, s as startShell } from './shared/giget.3990f4ae.mjs';
5
+ import { d as downloadTemplate, s as startShell } from './shared/giget.4b579418.mjs';
6
6
  import 'node:fs/promises';
7
7
  import 'node:os';
8
8
  import 'node:fs';
@@ -13,13 +13,18 @@ import 'node:child_process';
13
13
  import 'node-fetch-native';
14
14
 
15
15
  async function main() {
16
- const args = mri(process.argv.slice(2));
16
+ const args = mri(process.argv.slice(2), {
17
+ boolean: ["help", "force", "force-clean", "offline", "prefer-offline", "shell", "registry", "verbose"]
18
+ });
17
19
  const input = args._[0];
18
20
  const dir = args._[1];
19
21
  if (!input || args.help || args.h) {
20
- console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry]");
22
+ console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose]");
21
23
  process.exit(1);
22
24
  }
25
+ if (args.verbose) {
26
+ process.env.DEBUG = process.env.DEBUG || "true";
27
+ }
23
28
  const r = await downloadTemplate(input, {
24
29
  dir,
25
30
  force: args.force,
@@ -27,7 +32,7 @@ async function main() {
27
32
  offline: args.offline,
28
33
  registry: args.registry
29
34
  });
30
- console.log(`\u2728 Successfully cloned ${cyan(r.url)} to ${cyan(relative(process.cwd(), r.dir))}
35
+ console.log(`\u2728 Successfully cloned ${cyan(r.name || r.url)} to ${cyan(relative(process.cwd(), r.dir))}
31
36
  `);
32
37
  if (args.shell) {
33
38
  startShell(r.dir);
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const giget = require('./shared/giget.9473a836.cjs');
5
+ const giget = require('./shared/giget.2ac4718b.cjs');
6
6
  require('node:fs/promises');
7
7
  require('node:os');
8
8
  require('node:fs');
@@ -15,4 +15,5 @@ require('node-fetch-native');
15
15
 
16
16
 
17
17
  exports.downloadTemplate = giget.downloadTemplate;
18
+ exports.registryProvider = giget.registryProvider;
18
19
  exports.startShell = giget.startShell;
package/dist/index.d.ts CHANGED
@@ -36,6 +36,8 @@ declare function downloadTemplate(input: string, opts?: DownloadTemplateOptions)
36
36
  url?: string;
37
37
  }>;
38
38
 
39
+ declare const registryProvider: (registryEndpoint?: string) => TemplateProvider;
40
+
39
41
  declare function startShell(cwd: string): void;
40
42
 
41
- export { DownloadTemplateOptions, GitInfo, TemplateInfo, TemplateProvider, downloadTemplate, startShell };
43
+ export { DownloadTemplateOptions, GitInfo, TemplateInfo, TemplateProvider, downloadTemplate, registryProvider, startShell };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { d as downloadTemplate, s as startShell } from './shared/giget.3990f4ae.mjs';
1
+ export { d as downloadTemplate, r as registryProvider, s as startShell } from './shared/giget.4b579418.mjs';
2
2
  import 'node:fs/promises';
3
3
  import 'node:os';
4
4
  import 'node:fs';
@@ -30,11 +30,10 @@ async function download(url, filePath) {
30
30
  await promises$1.pipeline(res.body, stream);
31
31
  await promises.writeFile(infoPath, JSON.stringify(info), "utf8");
32
32
  }
33
- const inputRegex = /^(?<repo>\w+\/\w+)(?<subdir>[^#]+)?(?<ref>#\w+)?/;
33
+ const inputRegex = /^(?<repo>[\w.-]+\/[\w.-]+)(?<subdir>[^#]+)?(?<ref>#[\w.-]+)?/;
34
34
  function parseGitURI(input) {
35
35
  const m = input.match(inputRegex)?.groups;
36
36
  return {
37
- provider: m.provider ? m.provider.substring(0, m.provider.length - 1) : "github",
38
37
  repo: m.repo,
39
38
  subdir: m.subdir || "/",
40
39
  ref: m.ref ? m.ref.substring(1) : "main"
@@ -70,6 +69,7 @@ const github = (input) => {
70
69
  return {
71
70
  name: parsed.repo.replace("/", "-"),
72
71
  version: parsed.ref,
72
+ subdir: parsed.subdir,
73
73
  url: `https://github.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
74
74
  tar: `https://github.com/${parsed.repo}/archive/${parsed.ref}.tar.gz`
75
75
  };
@@ -79,6 +79,7 @@ const gitlab = (input) => {
79
79
  return {
80
80
  name: parsed.repo.replace("/", "-"),
81
81
  version: parsed.ref,
82
+ subdir: parsed.subdir,
82
83
  url: `https://gitlab.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
83
84
  tar: `https://gitlab.com/${parsed.repo}/-/archive/${parsed.ref}.tar.gz`
84
85
  };
@@ -88,6 +89,7 @@ const bitbucket = (input) => {
88
89
  return {
89
90
  name: parsed.repo.replace("/", "-"),
90
91
  version: parsed.ref,
92
+ subdir: parsed.subdir,
91
93
  url: `https://bitbucket.com/${parsed.repo}/src/${parsed.ref}${parsed.subdir}`,
92
94
  tar: `https://bitbucket.org/${parsed.repo}/get/${parsed.ref}.tar.gz`
93
95
  };
@@ -100,8 +102,9 @@ const providers = {
100
102
  };
101
103
 
102
104
  const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/unjs/giget/main/templates";
103
- const createRegistryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
105
+ const registryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
104
106
  return async (input) => {
107
+ const start = Date.now();
105
108
  const registryURL = `${registryEndpoint}/${input}.json`;
106
109
  const res = await fetch__default(registryURL);
107
110
  if (res.status >= 400) {
@@ -111,13 +114,14 @@ const createRegistryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
111
114
  if (!info.tar || !info.name) {
112
115
  throw new Error(`Invalid template info from ${registryURL}. name or tar fields are missing!`);
113
116
  }
117
+ debug(`Fetched ${input} template info from ${registryURL} in ${Date.now() - start}ms`);
114
118
  return info;
115
119
  };
116
120
  };
117
121
 
118
- const sourceProtoRe = /^([\w]+):/;
122
+ const sourceProtoRe = /^([\w-.]+):/;
119
123
  async function downloadTemplate(input, opts = {}) {
120
- const registryProvider = opts.registry !== false ? createRegistryProvider(opts.registry) : null;
124
+ const registry = opts.registry !== false ? registryProvider(opts.registry) : null;
121
125
  let providerName = opts.provider || (registryProvider ? "registry" : "github");
122
126
  let source = input;
123
127
  const sourceProvierMatch = input.match(sourceProtoRe);
@@ -125,7 +129,7 @@ async function downloadTemplate(input, opts = {}) {
125
129
  providerName = sourceProvierMatch[1];
126
130
  source = input.substring(sourceProvierMatch[0].length);
127
131
  }
128
- const provider = opts.providers?.[providerName] || providers[providerName] || registryProvider;
132
+ const provider = opts.providers?.[providerName] || providers[providerName] || registry;
129
133
  if (!provider) {
130
134
  throw new Error(`Unsupported provider: ${providerName}`);
131
135
  }
@@ -186,4 +190,5 @@ async function downloadTemplate(input, opts = {}) {
186
190
  }
187
191
 
188
192
  exports.downloadTemplate = downloadTemplate;
193
+ exports.registryProvider = registryProvider;
189
194
  exports.startShell = startShell;
@@ -24,11 +24,10 @@ async function download(url, filePath) {
24
24
  await pipeline(res.body, stream);
25
25
  await writeFile(infoPath, JSON.stringify(info), "utf8");
26
26
  }
27
- const inputRegex = /^(?<repo>\w+\/\w+)(?<subdir>[^#]+)?(?<ref>#\w+)?/;
27
+ const inputRegex = /^(?<repo>[\w.-]+\/[\w.-]+)(?<subdir>[^#]+)?(?<ref>#[\w.-]+)?/;
28
28
  function parseGitURI(input) {
29
29
  const m = input.match(inputRegex)?.groups;
30
30
  return {
31
- provider: m.provider ? m.provider.substring(0, m.provider.length - 1) : "github",
32
31
  repo: m.repo,
33
32
  subdir: m.subdir || "/",
34
33
  ref: m.ref ? m.ref.substring(1) : "main"
@@ -64,6 +63,7 @@ const github = (input) => {
64
63
  return {
65
64
  name: parsed.repo.replace("/", "-"),
66
65
  version: parsed.ref,
66
+ subdir: parsed.subdir,
67
67
  url: `https://github.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
68
68
  tar: `https://github.com/${parsed.repo}/archive/${parsed.ref}.tar.gz`
69
69
  };
@@ -73,6 +73,7 @@ const gitlab = (input) => {
73
73
  return {
74
74
  name: parsed.repo.replace("/", "-"),
75
75
  version: parsed.ref,
76
+ subdir: parsed.subdir,
76
77
  url: `https://gitlab.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
77
78
  tar: `https://gitlab.com/${parsed.repo}/-/archive/${parsed.ref}.tar.gz`
78
79
  };
@@ -82,6 +83,7 @@ const bitbucket = (input) => {
82
83
  return {
83
84
  name: parsed.repo.replace("/", "-"),
84
85
  version: parsed.ref,
86
+ subdir: parsed.subdir,
85
87
  url: `https://bitbucket.com/${parsed.repo}/src/${parsed.ref}${parsed.subdir}`,
86
88
  tar: `https://bitbucket.org/${parsed.repo}/get/${parsed.ref}.tar.gz`
87
89
  };
@@ -94,8 +96,9 @@ const providers = {
94
96
  };
95
97
 
96
98
  const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/unjs/giget/main/templates";
97
- const createRegistryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
99
+ const registryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
98
100
  return async (input) => {
101
+ const start = Date.now();
99
102
  const registryURL = `${registryEndpoint}/${input}.json`;
100
103
  const res = await fetch$1(registryURL);
101
104
  if (res.status >= 400) {
@@ -105,13 +108,14 @@ const createRegistryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
105
108
  if (!info.tar || !info.name) {
106
109
  throw new Error(`Invalid template info from ${registryURL}. name or tar fields are missing!`);
107
110
  }
111
+ debug(`Fetched ${input} template info from ${registryURL} in ${Date.now() - start}ms`);
108
112
  return info;
109
113
  };
110
114
  };
111
115
 
112
- const sourceProtoRe = /^([\w]+):/;
116
+ const sourceProtoRe = /^([\w-.]+):/;
113
117
  async function downloadTemplate(input, opts = {}) {
114
- const registryProvider = opts.registry !== false ? createRegistryProvider(opts.registry) : null;
118
+ const registry = opts.registry !== false ? registryProvider(opts.registry) : null;
115
119
  let providerName = opts.provider || (registryProvider ? "registry" : "github");
116
120
  let source = input;
117
121
  const sourceProvierMatch = input.match(sourceProtoRe);
@@ -119,7 +123,7 @@ async function downloadTemplate(input, opts = {}) {
119
123
  providerName = sourceProvierMatch[1];
120
124
  source = input.substring(sourceProvierMatch[0].length);
121
125
  }
122
- const provider = opts.providers?.[providerName] || providers[providerName] || registryProvider;
126
+ const provider = opts.providers?.[providerName] || providers[providerName] || registry;
123
127
  if (!provider) {
124
128
  throw new Error(`Unsupported provider: ${providerName}`);
125
129
  }
@@ -179,4 +183,4 @@ async function downloadTemplate(input, opts = {}) {
179
183
  };
180
184
  }
181
185
 
182
- export { downloadTemplate as d, startShell as s };
186
+ export { downloadTemplate as d, registryProvider as r, startShell as s };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "giget",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "description": "Download templates and git repositories with pleasure!",
5
5
  "repository": "unjs/giget",
6
6
  "license": "MIT",
@@ -32,13 +32,13 @@
32
32
  "@nuxtjs/eslint-config-typescript": "^11.0.0",
33
33
  "@types/node": "^18.7.16",
34
34
  "@types/tar": "^6.1.2",
35
- "@vitest/coverage-c8": "^0.23.1",
35
+ "@vitest/coverage-c8": "^0.23.2",
36
36
  "eslint": "^8.23.0",
37
37
  "jiti": "^1.15.0",
38
38
  "standard-version": "^9.5.0",
39
- "typescript": "^4.8.2",
39
+ "typescript": "^4.8.3",
40
40
  "unbuild": "^0.8.10",
41
- "vitest": "^0.23.1"
41
+ "vitest": "^0.23.2"
42
42
  },
43
43
  "packageManager": "pnpm@7.11.0",
44
44
  "scripts": {
@@ -46,7 +46,7 @@
46
46
  "dev": "vitest dev",
47
47
  "giget": "jiti ./src/cli.ts",
48
48
  "lint": "eslint --ext .ts,.js,.mjs,.cjs .",
49
- "play": "DEBUG=1 pnpm giget gh:unjs/template .tmp/clone --force-clean",
49
+ "play": "pnpm giget --force-clean --verbose unjs .tmp/clone",
50
50
  "release": "pnpm test && standard-version && git push --follow-tags && pnpm publish",
51
51
  "test": "pnpm lint && vitest run --coverage"
52
52
  }