create-wxl 0.0.0-stage → 3.1.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/LICENSE ADDED
@@ -0,0 +1,127 @@
1
+ Educational Community License, Version 2.0 (ECL-2.0)
2
+ Educational Community License
3
+
4
+ Version 2.0, April 2007
5
+
6
+ The Educational Community License version 2.0 ("ECL") consists of the Apache 2.0 license, modified to change the
7
+ scope of the patent grant in section 3 to be specific to the needs of the education communities using this license.
8
+ The original Apache 2.0 license can be found at: http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
11
+
12
+ 1. Definitions.
13
+
14
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1
15
+ through 9 of this document.
16
+
17
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
18
+
19
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or
20
+ are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct
21
+ or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership
22
+ of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source
27
+ code, documentation source, and configuration files.
28
+
29
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including
30
+ but not limited to compiled object code, generated documentation, and conversions to other media types.
31
+
32
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as
33
+ indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
34
+
35
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the
36
+ Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an
37
+ original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable
38
+ from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
39
+
40
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions
41
+ to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright
42
+ owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this
43
+ definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives,
44
+ including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems
45
+ that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding
46
+ communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
47
+
48
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by
49
+ Licensor and subsequently incorporated within the Work.
50
+
51
+ 2. Grant of Copyright License.
52
+
53
+ Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
54
+ no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly
55
+ perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
56
+
57
+ 3. Grant of Patent License.
58
+
59
+ Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
60
+ no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell,
61
+ sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such
62
+ Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with
63
+ the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a
64
+ cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct
65
+ or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate
66
+ as of the date such litigation is filed. Any patent license granted hereby with respect to contributions by an individual employed
67
+ by an institution or organization is limited to patent claims where the individual that is the author of the Work is also the
68
+ inventor of the patent claims licensed, and where the organization or institution has the right to grant such license under
69
+ applicable grant and research funding agreements. No other express or implied licenses are granted.
70
+
71
+ 4. Redistribution.
72
+
73
+ You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications,
74
+ and in Source or Object form, provided that You meet the following conditions:
75
+
76
+ You must give any other recipients of the Work or Derivative Works a copy of this License; and
77
+ You must cause any modified files to carry prominent notices stating that You changed the files; and
78
+ You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution
79
+ notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
80
+ If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include
81
+ a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any
82
+ part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative
83
+ Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the
84
+ Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational
85
+ purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute,
86
+ alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed
87
+ as modifying the License.
88
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions
89
+ for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use,
90
+ reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
91
+
92
+ 5. Submission of Contributions.
93
+
94
+ Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor
95
+ shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above,
96
+ nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding
97
+ such Contributions.
98
+
99
+ 6. Trademarks.
100
+
101
+ This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except
102
+ as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
103
+
104
+ 7. Disclaimer of Warranty.
105
+
106
+ Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions)
107
+ on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any
108
+ warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible
109
+ for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of
110
+ permissions under this License.
111
+
112
+ 8. Limitation of Liability.
113
+
114
+ In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable
115
+ law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages,
116
+ including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or
117
+ out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure
118
+ or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of
119
+ such damages.
120
+
121
+ 9. Accepting Warranty or Additional Liability.
122
+
123
+ While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support,
124
+ warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations,
125
+ You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to
126
+ indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by
127
+ reason of your accepting any such warranty or additional liability.
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env node
2
+ // create-wxl's real entry point (0005-S1, traceability.md "Step order" row 1 and "Signals"):
3
+ // `npm create wxl` / `pnpm create wxl` runs this file. Checks `process.versions.node` BEFORE
4
+ // importing anything else (a too-old Node must not crash trying to parse a later module instead
5
+ // of reporting CW-E01 cleanly); everything else is imported dynamically only after that check.
6
+ //
7
+ // Step 2's package source record check (`dist/source.json`'s fields and the engine's hash) lives
8
+ // entirely inside `run()`'s own step 2 (`src/run.mjs`), not here: this file's own `try`/`catch`
9
+ // below only covers LOADING `dist/` -- a missing file, invalid JSON, or an engine that fails to
10
+ // import at all (a syntax error) -- and turns any of those into `source: null`, `engine:
11
+ // undefined`. `run()` then does argv parsing, the `--no-setup` conflict check and
12
+ // `CREATE_WXL_COMMIT`'s grammar BEFORE it ever looks at `source` (Command grammar: "Argument
13
+ // errors are checked before the package source record"), so an argument error still wins over a
14
+ // broken package (AC-2); when `source` is null, `run()`'s own step 2 fails closed and prints
15
+ // CW-E13 itself, in the environment's language -- this file never prints CW-E13 on its own.
16
+
17
+ // Used only for the pre-import version gate below (step 1 must run before any project-local
18
+ // module loads); once that gate passes, the REAL minimum (`src/node-version.mjs`) is what every
19
+ // later check uses. Kept distinct so this literal is never mistaken for the one source of truth.
20
+ const MINIMUM_NODE_VERSION_FALLBACK = [22, 6, 0]
21
+
22
+ function isNodeVersionOkInline(version, minimum = MINIMUM_NODE_VERSION_FALLBACK) {
23
+ if (!/^\d+(\.\d+)*$/.test(version)) return false
24
+ const parts = version.split('.').map(Number)
25
+ for (let i = 0; i < minimum.length; i++) {
26
+ const have = parts[i] ?? 0
27
+ const want = minimum[i]
28
+ if (have > want) return true
29
+ if (have < want) return false
30
+ }
31
+ return true
32
+ }
33
+
34
+ /** The too-old-Node report (step 1's own failure): reuses `node-version.mjs`'s real minimum and
35
+ * `messages.mjs`'s real CW-E01 text through `language.mjs`'s real language rule, instead of
36
+ * hand-duplicating any of the three (S-03: one place for the minimum and the text; S-04: the
37
+ * same LC_ALL/LC_MESSAGES/LANG-then-Intl fallback `language.mjs` uses, not a shorter hand-rolled
38
+ * one that stops at `'en'`). Importing these three now is safe: the version decision itself is
39
+ * already made; this import is only to report it correctly. A Node so old even these tiny,
40
+ * dependency-free modules fail to load falls back to a hand-written, best-effort English line. */
41
+ async function reportNodeTooOld(version) {
42
+ let text
43
+ try {
44
+ const [{ MINIMUM_NODE_VERSION }, { selectLanguage }, { messages }] = await Promise.all([
45
+ import('../src/node-version.mjs'),
46
+ import('../src/language.mjs'),
47
+ import('../src/messages.mjs'),
48
+ ])
49
+ const lang = selectLanguage({ env: process.env })
50
+ text = messages[lang]['CW-E01']({ running: version, minimum: MINIMUM_NODE_VERSION })
51
+ } catch {
52
+ const minimum = MINIMUM_NODE_VERSION_FALLBACK.join('.')
53
+ text = `CW-E01: the running Node.js "${version}" is older than the minimum "${minimum}"; install a newer Node.js from https://nodejs.org/.`
54
+ }
55
+ process.stderr.write(text + '\n')
56
+ }
57
+
58
+ async function main() {
59
+ // Step 1: before importing anything else.
60
+ if (!isNodeVersionOkInline(process.versions.node)) {
61
+ await reportNodeTooOld(process.versions.node)
62
+ process.exitCode = 1
63
+ return
64
+ }
65
+
66
+ const { pathToFileURL, fileURLToPath } = await import('node:url')
67
+ const { dirname, join } = await import('node:path')
68
+ const fsp = await import('node:fs/promises')
69
+ const { readFile } = fsp
70
+ const { tmpdir } = await import('node:os')
71
+
72
+ const { run } = await import('../src/run.mjs')
73
+ const { createSpawnGitRunner } = await import('../src/git-runner.mjs')
74
+
75
+ const here = dirname(fileURLToPath(import.meta.url))
76
+ const packageRoot = dirname(here)
77
+
78
+ // Step 2's load (this file's own catch, traceability.md "Step order" row 2): a missing
79
+ // `dist/source.json`, invalid JSON, a missing `dist/fork-init.mjs`, or an engine that fails to
80
+ // import (a syntax error) -- any of these leaves `source` null and `engine` undefined, so
81
+ // `run()`'s own step 2 (`validateSourceRecord`) fails closed without ever touching `engine`.
82
+ let source = null
83
+ let engine
84
+ try {
85
+ const sourceText = await readFile(join(packageRoot, 'dist', 'source.json'), 'utf8')
86
+ source = JSON.parse(sourceText)
87
+ engine = await import(pathToFileURL(join(packageRoot, 'dist', 'fork-init.mjs')).href)
88
+ } catch {
89
+ source = null
90
+ engine = undefined
91
+ }
92
+
93
+ const packageJson = JSON.parse(await readFile(join(packageRoot, 'package.json'), 'utf8'))
94
+
95
+ const deps = {
96
+ env: process.env,
97
+ cwd: process.cwd(),
98
+ nodeVersion: process.versions.node,
99
+ locale: Intl.DateTimeFormat().resolvedOptions().locale,
100
+ packageVersion: packageJson.version,
101
+ source,
102
+ engine,
103
+ engineFile: join(packageRoot, 'dist', 'fork-init.mjs'),
104
+ fetchArchive: async (repository, ref, { signal } = {}) => {
105
+ const response = await fetch(`https://codeload.github.com/${repository}/tar.gz/${ref}`, { signal })
106
+ const body = new Uint8Array(await response.arrayBuffer())
107
+ return { status: response.status, body }
108
+ },
109
+ downloadTimeoutMs: 120000,
110
+ tmpRoot: tmpdir(),
111
+ runGit: createSpawnGitRunner(),
112
+ fs: fsp,
113
+ // `process` itself is `deps.signals` (the seam's own dependency list, traceability.md
114
+ // 0005-S1): `createSignalGuard` (run.mjs, from step 3 on) registers its own listeners
115
+ // directly on it and removes them once `run` returns, so Node's default SIGINT/SIGTERM/SIGHUP
116
+ // termination holds before step 3 and after `run` returns -- this file never registers a
117
+ // listener of its own to re-emit from (that used to suppress the default termination for the
118
+ // whole run, including steps 1-2, and leave it suppressed after `run` returned). The readline
119
+ // forwarder (`questions.mjs`) already does `deps.signals.emit('SIGINT')`, which is a real
120
+ // `process.emit('SIGINT')` here, reaching the guard's own listener the same way an actual
121
+ // signal would.
122
+ signals: process,
123
+ checkpoint: () => {},
124
+ }
125
+
126
+ const io = {
127
+ stdin: process.stdin,
128
+ stdout: process.stdout,
129
+ stderr: process.stderr,
130
+ interactive: Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY),
131
+ }
132
+
133
+ const argv = process.argv.slice(2)
134
+ // `process.exitCode` (not `process.exit`): the latter can truncate output still buffered on a
135
+ // piped stdout/stderr.
136
+ process.exitCode = await run(argv, io, deps)
137
+ }
138
+
139
+ // traceability.md "Signals": "An error that is none of the CW codes (a bug) ... is printed as
140
+ // CW-E14 ... and exits 1" -- `run()` already does this for everything inside its own body; this
141
+ // is the same rule for everything OUTSIDE it (reading `package.json`, `process.cwd()`, the
142
+ // dynamic imports above, ...), which used to become an unhandled rejection printing Node's own
143
+ // raw stack trace instead.
144
+ main().catch(async (err) => {
145
+ let text
146
+ try {
147
+ const [{ selectLanguage }, { messages }] = await Promise.all([import('../src/language.mjs'), import('../src/messages.mjs')])
148
+ const lang = selectLanguage({ env: process.env })
149
+ text = messages[lang]['CW-E14']({ message: err?.message ?? String(err) })
150
+ } catch {
151
+ text = `CW-E14: an unexpected error happened: ${JSON.stringify(err?.message ?? String(err))}.`
152
+ }
153
+ process.stderr.write(text + '\n')
154
+ process.exitCode = 1
155
+ })