@chouquette/gleam 1.0.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/.prettierrc ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "printWidth": 80,
3
+ "semi": false,
4
+ "singleQuote": true,
5
+ "arrowParens": "avoid",
6
+ "trailingComma": "es5",
7
+ "importOrder": ["^\\@.*$", "^[^@\\.].*$", "^\\..*$"],
8
+ "importOrderSortSpecifiers": true,
9
+ "plugins": ["@trivago/prettier-plugin-sort-imports"],
10
+ "proseWrap": "always"
11
+ }
package/LICENCE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2024 Guillaume Hivert
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Gleam Lang
2
+
3
+ [Gleam](https://gleam.run) is a functional language that compiles to JavaScript!
4
+ More information can be found
5
+ [in the documentation](https://gleam.run/documentation/) directly, to get you
6
+ started!
7
+
8
+ ## What is this package for?
9
+
10
+ For stantard development purposes, a classic gleam installation should be done,
11
+ [following the official instructions](https://gleam.run/getting-started/installing/).
12
+ However, having a gleam package on NPM allows everyone to embed gleam directly
13
+ from a `package.json`, for certain scenarios:
14
+
15
+ - When running on CI, and dependent on the `package.json`.
16
+ - When you can't install softwares directly.
17
+ - When you want to maintain multiple versions of gleam with NPM.
18
+
19
+ ## Installation
20
+
21
+ ```
22
+ yarn add @chouquette/gleam
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```
28
+ yarn gleam --help
29
+ ```
30
+
31
+ ## Goal of the package
32
+
33
+ This package will mimic main releases of gleam, meaning all intermediates
34
+ versions (1.1.0-rc1 for instance) will not be taken into account. Expect a new
35
+ version of this package to ship soon after the official releases lands on
36
+ GitHub.
37
+
38
+ ## Limitations
39
+
40
+ Because gleam compiles both to JS and Erlang, the gleam compiler can output both
41
+ code. However, do not expect this package to help in Erlang development. This
42
+ package is mainly aimed to use in the JS ecosystem, and do not ship Erlang
43
+ runtime neither rebar3. Follow the classical installation of gleam and Erlang to
44
+ get started with Erlang development!
45
+
46
+ In case you succeed to use this package in an Erlang workflow, congrats! You
47
+ achieved a strong engineering achievement! Do not ask for help if it bug though!
48
+ 😇
package/bin/cli.mjs ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import * as installer from '#chouquette/installer'
3
+ import * as childProcess from 'node:child_process'
4
+ import * as fs from 'node:fs'
5
+ import * as path from 'node:path'
6
+
7
+ // Replaces __dirname.
8
+ const { cache, dirname } = installer.directories()
9
+ const data = await installer.prepareDownload(dirname, cache)
10
+
11
+ // User can run install with ignore scripts, compiler should be
12
+ // downloaded before using it.
13
+ const isExec = fs.existsSync(data.binPath)
14
+ if (!isExec) await installer.install()
15
+
16
+ // Run the compiler.
17
+ const args = process.argv.slice(2)
18
+ const options = { stdio: 'inherit' }
19
+ childProcess.spawn(data.binPath, args, options).on('exit', process.exit)
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@chouquette/gleam",
3
+ "version": "1.0.0",
4
+ "author": "Guillaume Hivert <hivert.is.coming@gmail.com>",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": "bin/cli.mjs",
8
+ "repository": "https://github.com/ghivert/gleam-lang-npm",
9
+ "packageManager": "yarn@4.6.0",
10
+ "imports": {
11
+ "#chouquette/*": "./src/*.mjs"
12
+ },
13
+ "scripts": {
14
+ "install": "node src/main.mjs"
15
+ },
16
+ "keywords": [
17
+ "beam",
18
+ "bin",
19
+ "binary",
20
+ "build",
21
+ "bundler",
22
+ "cli",
23
+ "compile",
24
+ "compiler",
25
+ "erlang",
26
+ "fallback",
27
+ "gleam",
28
+ "install",
29
+ "installation",
30
+ "lustre",
31
+ "wrapper"
32
+ ],
33
+ "devDependencies": {
34
+ "@trivago/prettier-plugin-sort-imports": "^4.3.0",
35
+ "prettier": "^3.2.5"
36
+ },
37
+ "dependencies": {
38
+ "tar": "^7.1.0"
39
+ }
40
+ }
@@ -0,0 +1,37 @@
1
+ import * as os from 'node:os'
2
+ import * as path from 'node:path'
3
+
4
+ function posix(id) {
5
+ const xdgCache = process.env.XDG_CACHE_HOME
6
+ const cacheHome = xdgCache || path.join(os.homedir(), '.cache')
7
+ return path.join(cacheHome, id)
8
+ }
9
+
10
+ function darwin(id) {
11
+ return path.join(os.homedir(), 'Library', 'Caches', id)
12
+ }
13
+
14
+ function win32(id) {
15
+ const local = process.env.LOCALAPPDATA
16
+ const appData = local || path.join(os.homedir(), 'AppData', 'Local')
17
+ return path.join(appData, id, 'Cache')
18
+ }
19
+
20
+ export function cachedir(id) {
21
+ switch (process.platform) {
22
+ case 'darwin':
23
+ return darwin(id)
24
+ case 'win32':
25
+ return win32(id)
26
+ case 'aix':
27
+ case 'android':
28
+ case 'freebsd':
29
+ case 'linux':
30
+ case 'netbsd':
31
+ case 'openbsd':
32
+ case 'sunos':
33
+ return posix(id)
34
+ default:
35
+ return null
36
+ }
37
+ }
@@ -0,0 +1,54 @@
1
+ import * as fs from 'node:fs'
2
+ import * as path from 'node:path'
3
+
4
+ export { cachedir } from './environment/cachedir.mjs'
5
+
6
+ export async function infos(dirname) {
7
+ const arch = getArch()
8
+ const platform = getPlatform()
9
+ const version = await getVersion(dirname)
10
+ return { arch, platform, version }
11
+ }
12
+
13
+ export function dirname() {
14
+ const file = new URL(import.meta.url)
15
+ const dirname = path.dirname(file.pathname)
16
+ return dirname
17
+ }
18
+
19
+ async function getVersion(dirname) {
20
+ const pack = path.resolve(dirname, '../package.json')
21
+ const content = await fs.promises.readFile(pack, 'utf-8')
22
+ const package_ = JSON.parse(content)
23
+ return `v${package_.version}`
24
+ }
25
+
26
+ function getArch() {
27
+ switch (process.arch) {
28
+ case 'arm64':
29
+ return 'aarch64'
30
+ case 'x64':
31
+ return 'x86_64'
32
+ default:
33
+ return null
34
+ }
35
+ }
36
+
37
+ function getPlatform() {
38
+ switch (process.platform) {
39
+ case 'darwin':
40
+ return 'apple-darwin'
41
+ case 'win32':
42
+ return 'pc-windows-msvc'
43
+ case 'aix':
44
+ case 'android':
45
+ case 'freebsd':
46
+ case 'linux':
47
+ case 'netbsd':
48
+ case 'openbsd':
49
+ case 'sunos':
50
+ return 'unknown-linux-musl'
51
+ default:
52
+ return null
53
+ }
54
+ }
@@ -0,0 +1,15 @@
1
+ import * as fs from 'node:fs'
2
+
3
+ function endpoint(version, arch, platform) {
4
+ const base = 'https://github.com/gleam-lang/gleam/releases/download'
5
+ return `${base}/${version}/gleam-${version}-${arch}-${platform}.tar.gz`
6
+ }
7
+
8
+ export async function download({ tgzPath, version, arch, platform }) {
9
+ if (fs.existsSync(tgzPath)) return
10
+ const endpt = endpoint(version, arch, platform)
11
+ const res = await fetch(endpt)
12
+ if (!res.ok) throw new Error('Unreachable')
13
+ const tgz = await res.arrayBuffer()
14
+ await fs.promises.writeFile(tgzPath, Buffer.from(tgz))
15
+ }
package/src/gleam.mjs ADDED
@@ -0,0 +1 @@
1
+ export * as compiler from './gleam/compiler.mjs'
@@ -0,0 +1,51 @@
1
+ import * as fs from 'node:fs'
2
+ import * as path from 'node:path'
3
+ import * as tar from 'tar'
4
+ import * as environment from './environment.mjs'
5
+ import * as gleam from './gleam.mjs'
6
+
7
+ export async function install(options) {
8
+ const { dirname, cache } = directories()
9
+ const data = await prepareDownload(dirname, cache)
10
+ try {
11
+ await fs.promises.mkdir(cache, { recursive: true })
12
+ await fs.promises.mkdir(data.binDir, { recursive: true })
13
+ await gleam.compiler.download(data)
14
+ await tar.extract({ file: data.tgzPath, cwd: data.binDir })
15
+ } catch (error) {
16
+ const isBadArchive = error.message.includes('TAR_BAD_ARCHIVE')
17
+ const shouldRetry = !(options?.propagateErrors ?? false)
18
+ const archiveExists = fs.existsSync(data.tgzPath)
19
+ if (isBadArchive && shouldRetry && archiveExists) {
20
+ await fs.promises.rm(data.tgzPath)
21
+ return install({ propagateErrors: true })
22
+ }
23
+ console.error(error)
24
+ console.error(
25
+ [
26
+ '--- ERROR -----------------------------------------------------',
27
+ 'It looks like your operating system does not support Gleam yet.',
28
+ 'Currently, Gleam supports macOS, Linux and Windows. ',
29
+ '---------------------------------------------------------------',
30
+ ].join('\n')
31
+ )
32
+ }
33
+ }
34
+
35
+ export function directories() {
36
+ const dirname = environment.dirname()
37
+ const cache = environment.cachedir('gleam-npm')
38
+ if (!cache) throw new Error()
39
+ return { dirname, cache }
40
+ }
41
+
42
+ export async function prepareDownload(dirname, cache) {
43
+ const { arch, version, platform } = await environment.infos(dirname)
44
+ if (!arch || !platform) throw new Error('Impossible to detect the env.')
45
+ const archiveName = `gleam-${version}-${arch}-${platform}.tgz`
46
+ const binName = `gleam-${version}-${arch}-${platform}`
47
+ const tgzPath = path.resolve(cache, archiveName)
48
+ const binDir = path.resolve(cache, binName)
49
+ const binPath = path.resolve(binDir, 'gleam')
50
+ return { tgzPath, binDir, binPath, arch, version, platform }
51
+ }
package/src/main.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import * as installer from './installer.mjs'
2
+
3
+ installer.install()