@fusion.dev/create-helix-app 0.25.1 → 0.30.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.
- package/README.md +6 -0
- package/bin.mjs +87 -7
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -24,6 +24,12 @@ This is `helix new` from
|
|
|
24
24
|
reached from somewhere with no project yet. A project that already has Helix
|
|
25
25
|
installed can run `npx helix new` instead, and gets the same templates.
|
|
26
26
|
|
|
27
|
+
**It says when a newer Helix is out.** Without `@latest`, npm can run a copy it
|
|
28
|
+
cached earlier, so this asks npm for the newest version while it writes the
|
|
29
|
+
project and prints one line if it isn't this one. It waits three seconds at most
|
|
30
|
+
and says nothing if npm doesn't answer. It doesn't ask in CI, from a
|
|
31
|
+
pre-release, or when `HELIX_NO_UPDATE_CHECK` is set.
|
|
32
|
+
|
|
27
33
|
**Scoped because the plain name is taken.** `create-helix-app` on npm belongs to
|
|
28
34
|
an unrelated project, so `npm create helix-app` runs somebody else's code.
|
|
29
35
|
`npm create @fusion.dev/helix-app` resolves to this package and no other.
|
package/bin.mjs
CHANGED
|
@@ -16,22 +16,102 @@
|
|
|
16
16
|
* own cache. So this hands over the package it resolved, which is the one
|
|
17
17
|
* versioned with the binary beside it. `HELIX_TEMPLATES` already set wins, as it
|
|
18
18
|
* does everywhere else it is read.
|
|
19
|
+
*
|
|
20
|
+
* **And it says when it is not the newest**, which the binary cannot: it has no
|
|
21
|
+
* HTTP client, by design, and this door is the one that goes stale. Asked
|
|
22
|
+
* without `@latest`, npm runs whatever copy it cached last time, so a reader can
|
|
23
|
+
* scaffold from a release months old without anything saying so. See `newer`.
|
|
19
24
|
*/
|
|
20
|
-
import {
|
|
25
|
+
import { spawn } from 'node:child_process'
|
|
26
|
+
import { readFileSync } from 'node:fs'
|
|
21
27
|
import { createRequire } from 'node:module'
|
|
22
|
-
import { dirname } from 'node:path'
|
|
28
|
+
import { dirname, join } from 'node:path'
|
|
29
|
+
import { fileURLToPath } from 'node:url'
|
|
23
30
|
|
|
24
31
|
const require = createRequire(import.meta.url)
|
|
25
32
|
const templates = dirname(require.resolve('@fusion.dev/helix-templates/templates.json'))
|
|
26
33
|
const helix = require.resolve('@fusion.dev/helix-cli/bin.mjs')
|
|
34
|
+
const own = JSON.parse(
|
|
35
|
+
readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'package.json'), 'utf8'),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
/** How long the registry gets, since a scaffold must never wait on it. */
|
|
39
|
+
const PATIENCE = 3000
|
|
40
|
+
|
|
41
|
+
/** `[major, minor, patch]`, or undefined for a pre-release or anything else. */
|
|
42
|
+
const release = (version) => {
|
|
43
|
+
const found = /^(\d+)\.(\d+)\.(\d+)$/.exec(String(version).trim())
|
|
44
|
+
return found ? found.slice(1).map(Number) : undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The version newer than this one that npm calls latest, or undefined.
|
|
49
|
+
*
|
|
50
|
+
* **Asked through npm rather than over HTTP**, because npm holds the reader's
|
|
51
|
+
* login and these packages are restricted until they are public: an anonymous
|
|
52
|
+
* request is answered 404 for a package that exists. npm is on the path by
|
|
53
|
+
* definition, this having been started by it.
|
|
54
|
+
*
|
|
55
|
+
* **Never in the way.** Given three seconds and killed after them, and every
|
|
56
|
+
* failure is silence: offline, refused, slow, or answering something that is not
|
|
57
|
+
* a version. Not asked in CI, where nobody reads it, nor from a pre-release,
|
|
58
|
+
* which somebody chose on purpose, nor where `HELIX_NO_UPDATE_CHECK` is set.
|
|
59
|
+
*/
|
|
60
|
+
const newer = () => {
|
|
61
|
+
const mine = release(own.version)
|
|
62
|
+
if (mine === undefined || process.env.CI || process.env.HELIX_NO_UPDATE_CHECK) {
|
|
63
|
+
return Promise.resolve(undefined)
|
|
64
|
+
}
|
|
65
|
+
return new Promise((resolve) => {
|
|
66
|
+
let said = ''
|
|
67
|
+
const asking = spawn('npm', ['view', `${own.name}@latest`, 'version'], {
|
|
68
|
+
shell: process.platform === 'win32',
|
|
69
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
70
|
+
})
|
|
71
|
+
const done = (answer) => {
|
|
72
|
+
clearTimeout(timer)
|
|
73
|
+
resolve(answer)
|
|
74
|
+
}
|
|
75
|
+
const timer = setTimeout(() => {
|
|
76
|
+
asking.kill()
|
|
77
|
+
done(undefined)
|
|
78
|
+
}, PATIENCE)
|
|
79
|
+
asking.stdout.on('data', (chunk) => {
|
|
80
|
+
said += chunk
|
|
81
|
+
})
|
|
82
|
+
asking.on('error', () => done(undefined))
|
|
83
|
+
asking.on('close', (code) => {
|
|
84
|
+
const latest = release(said)
|
|
85
|
+
if (code !== 0 || latest === undefined) {
|
|
86
|
+
done(undefined)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
const ahead = latest.findIndex((part, index) => part !== mine[index])
|
|
90
|
+
done(ahead !== -1 && latest[ahead] > mine[ahead] ? said.trim() : undefined)
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Asked while the project is written rather than before, so a reader waits on
|
|
96
|
+
the registry only if it is slower than the scaffold. */
|
|
97
|
+
const checking = newer()
|
|
27
98
|
|
|
28
|
-
const
|
|
99
|
+
const running = spawn(process.execPath, [helix, 'new', ...process.argv.slice(2)], {
|
|
29
100
|
env: { ...process.env, HELIX_TEMPLATES: process.env.HELIX_TEMPLATES ?? templates },
|
|
30
101
|
stdio: 'inherit',
|
|
31
102
|
})
|
|
32
|
-
|
|
33
|
-
if (error && status === null) {
|
|
103
|
+
running.on('error', (error) => {
|
|
34
104
|
console.error(`create-helix-app: could not run helix: ${error.message}`)
|
|
35
105
|
process.exit(70)
|
|
36
|
-
}
|
|
37
|
-
|
|
106
|
+
})
|
|
107
|
+
running.on('close', async (status) => {
|
|
108
|
+
/* On stderr, so `--json` on stdout stays a document a script can read. */
|
|
109
|
+
const latest = await checking
|
|
110
|
+
if (latest !== undefined) {
|
|
111
|
+
console.error(
|
|
112
|
+
`\nHelix ${latest} is out, and this is ${own.version}. For the newest templates:\n\n` +
|
|
113
|
+
` npm create ${own.name.replace('create-', '')}@latest\n`,
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
process.exit(status ?? 70)
|
|
117
|
+
})
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/create-helix-app",
|
|
3
3
|
"description": "Starts a Helix project: `npm create @fusion.dev/helix-app`, which is `helix new` for somebody with no project yet.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.30.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
},
|
|
22
22
|
"bugs": "https://github.com/project-fusion/fusion/issues",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@fusion.dev/helix-cli": "0.
|
|
25
|
-
"@fusion.dev/helix-templates": "0.
|
|
24
|
+
"@fusion.dev/helix-cli": "0.30.0",
|
|
25
|
+
"@fusion.dev/helix-templates": "0.30.0"
|
|
26
26
|
},
|
|
27
27
|
"homepage": "https://fusion.dev",
|
|
28
28
|
"keywords": [
|