rebrand and splitting so its not a monorepo

This commit is contained in:
2026-06-30 20:34:02 +02:00
parent 6fe57399c4
commit def33f7d54
161 changed files with 4269 additions and 31776 deletions
+4
View File
@@ -0,0 +1,4 @@
*.beam
*.ez
/build
erl_crash.dump
+17
View File
@@ -0,0 +1,17 @@
[
{
"label": "gleam run",
"command": "gleam",
"args": ["run"],
"use_new_terminal": false,
"reveal": "never",
},
{
"label": "gleam format",
"command": "gleam",
"args": ["format"],
"use_new_terminal": false,
"reveal": "never",
},
]
+3 -23
View File
@@ -1,24 +1,4 @@
# markdown2
# Luma
[![Package Version](https://img.shields.io/hexpm/v/markdown2)](https://hex.pm/packages/markdown2)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/markdown2/)
```sh
gleam add markdown2@1
```
```gleam
import markdown2
pub fn main() -> Nil {
// TODO: An example of the project in use
}
```
Further documentation can be found at <https://hexdocs.pm/markdown2>.
## Development
```sh
gleam run # Run the project
gleam test # Run the tests
```
A parser for a semantic note taking markup language.
The parser is written in Gleam. you can test it with gleam run.
+8
View File
@@ -0,0 +1,8 @@
gleam build --target javascript
npx esbuild build/dev/javascript/markdown2/markdown2.mjs \
--bundle \
--outfile=parser.js \
--format=iife \
--global-name=App
rm -rf ui/parser.js
mv parser.js ui/parser.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../esbuild/bin/esbuild
+66
View File
@@ -0,0 +1,66 @@
{
"name": "markdown2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/@esbuild/linux-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz",
"integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/esbuild": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
"integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.28.1",
"@esbuild/android-arm": "0.28.1",
"@esbuild/android-arm64": "0.28.1",
"@esbuild/android-x64": "0.28.1",
"@esbuild/darwin-arm64": "0.28.1",
"@esbuild/darwin-x64": "0.28.1",
"@esbuild/freebsd-arm64": "0.28.1",
"@esbuild/freebsd-x64": "0.28.1",
"@esbuild/linux-arm": "0.28.1",
"@esbuild/linux-arm64": "0.28.1",
"@esbuild/linux-ia32": "0.28.1",
"@esbuild/linux-loong64": "0.28.1",
"@esbuild/linux-mips64el": "0.28.1",
"@esbuild/linux-ppc64": "0.28.1",
"@esbuild/linux-riscv64": "0.28.1",
"@esbuild/linux-s390x": "0.28.1",
"@esbuild/linux-x64": "0.28.1",
"@esbuild/netbsd-arm64": "0.28.1",
"@esbuild/netbsd-x64": "0.28.1",
"@esbuild/openbsd-arm64": "0.28.1",
"@esbuild/openbsd-x64": "0.28.1",
"@esbuild/openharmony-arm64": "0.28.1",
"@esbuild/sunos-x64": "0.28.1",
"@esbuild/win32-arm64": "0.28.1",
"@esbuild/win32-ia32": "0.28.1",
"@esbuild/win32-x64": "0.28.1"
}
}
}
}
+3
View File
@@ -0,0 +1,3 @@
# esbuild
This is the Linux 64-bit binary for esbuild, a JavaScript bundler and minifier. See https://github.com/evanw/esbuild for details.
Generated Vendored Executable
BIN
View File
Binary file not shown.
+20
View File
@@ -0,0 +1,20 @@
{
"name": "@esbuild/linux-x64",
"version": "0.28.1",
"description": "The Linux 64-bit binary for esbuild, a JavaScript bundler.",
"repository": {
"type": "git",
"url": "git+https://github.com/evanw/esbuild.git"
},
"license": "MIT",
"preferUnplugged": true,
"engines": {
"node": ">=18"
},
"os": [
"linux"
],
"cpu": [
"x64"
]
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Evan Wallace
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.
+3
View File
@@ -0,0 +1,3 @@
# esbuild
This is a JavaScript bundler and minifier. See https://github.com/evanw/esbuild and the [JavaScript API documentation](https://esbuild.github.io/api/) for details.
Generated Vendored Executable
BIN
View File
Binary file not shown.
+300
View File
@@ -0,0 +1,300 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// lib/npm/node-platform.ts
var fs = require("fs");
var os = require("os");
var path = require("path");
var ESBUILD_BINARY_PATH = process.env.ESBUILD_BINARY_PATH || ESBUILD_BINARY_PATH;
var isValidBinaryPath = (x) => !!x && x !== "/usr/bin/esbuild";
var knownWindowsPackages = {
"win32 arm64 LE": "@esbuild/win32-arm64",
"win32 ia32 LE": "@esbuild/win32-ia32",
"win32 x64 LE": "@esbuild/win32-x64"
};
var knownUnixlikePackages = {
"aix ppc64 BE": "@esbuild/aix-ppc64",
"android arm64 LE": "@esbuild/android-arm64",
"darwin arm64 LE": "@esbuild/darwin-arm64",
"darwin x64 LE": "@esbuild/darwin-x64",
"freebsd arm64 LE": "@esbuild/freebsd-arm64",
"freebsd x64 LE": "@esbuild/freebsd-x64",
"linux arm LE": "@esbuild/linux-arm",
"linux arm64 LE": "@esbuild/linux-arm64",
"linux ia32 LE": "@esbuild/linux-ia32",
"linux mips64el LE": "@esbuild/linux-mips64el",
"linux ppc64 LE": "@esbuild/linux-ppc64",
"linux riscv64 LE": "@esbuild/linux-riscv64",
"linux s390x BE": "@esbuild/linux-s390x",
"linux x64 LE": "@esbuild/linux-x64",
"linux loong64 LE": "@esbuild/linux-loong64",
"netbsd arm64 LE": "@esbuild/netbsd-arm64",
"netbsd x64 LE": "@esbuild/netbsd-x64",
"openbsd arm64 LE": "@esbuild/openbsd-arm64",
"openbsd x64 LE": "@esbuild/openbsd-x64",
"sunos x64 LE": "@esbuild/sunos-x64"
};
var knownWebAssemblyFallbackPackages = {
"android arm LE": "@esbuild/android-arm",
"android x64 LE": "@esbuild/android-x64",
"openharmony arm64 LE": "@esbuild/openharmony-arm64"
};
function pkgAndSubpathForCurrentPlatform() {
let pkg;
let subpath;
let isWASM = false;
let platformKey = `${process.platform} ${os.arch()} ${os.endianness()}`;
if (platformKey in knownWindowsPackages) {
pkg = knownWindowsPackages[platformKey];
subpath = "esbuild.exe";
} else if (platformKey in knownUnixlikePackages) {
pkg = knownUnixlikePackages[platformKey];
subpath = "bin/esbuild";
} else if (platformKey in knownWebAssemblyFallbackPackages) {
pkg = knownWebAssemblyFallbackPackages[platformKey];
subpath = "bin/esbuild";
isWASM = true;
} else {
throw new Error(`Unsupported platform: ${platformKey}`);
}
return { pkg, subpath, isWASM };
}
function downloadedBinPath(pkg, subpath) {
const esbuildLibDir = path.dirname(require.resolve("esbuild"));
return path.join(esbuildLibDir, `downloaded-${pkg.replace("/", "-")}-${path.basename(subpath)}`);
}
// lib/npm/node-install.ts
var fs2 = require("fs");
var os2 = require("os");
var path2 = require("path");
var zlib = require("zlib");
var https = require("https");
var crypto = require("crypto");
var child_process = require("child_process");
var packageJSON = require(path2.join(__dirname, "package.json"));
var toPath = path2.join(__dirname, "bin", "esbuild");
var isToPathJS = true;
function validateBinaryVersion(...command) {
command.push("--version");
let stdout;
try {
stdout = child_process.execFileSync(command.shift(), command, {
// Without this, this install script strangely crashes with the error
// "EACCES: permission denied, write" but only on Ubuntu Linux when node is
// installed from the Snap Store. This is not a problem when you download
// the official version of node. The problem appears to be that stderr
// (i.e. file descriptor 2) isn't writable?
//
// More info:
// - https://snapcraft.io/ (what the Snap Store is)
// - https://nodejs.org/dist/ (download the official version of node)
// - https://github.com/evanw/esbuild/issues/1711#issuecomment-1027554035
//
stdio: "pipe"
}).toString().trim();
} catch (err) {
if (os2.platform() === "darwin" && /_SecTrustEvaluateWithError/.test(err + "")) {
let os3 = "this version of macOS";
try {
os3 = "macOS " + child_process.execFileSync("sw_vers", ["-productVersion"]).toString().trim();
} catch {
}
throw new Error(`The "esbuild" package cannot be installed because ${os3} is too outdated.
The Go compiler (which esbuild relies on) no longer supports ${os3},
which means the "esbuild" binary executable can't be run. You can either:
* Update your version of macOS to one that the Go compiler supports
* Use the "esbuild-wasm" package instead of the "esbuild" package
* Build esbuild yourself using an older version of the Go compiler
`);
}
throw err;
}
if (stdout !== packageJSON.version) {
throw new Error(`Expected ${JSON.stringify(packageJSON.version)} but got ${JSON.stringify(stdout)}`);
}
}
function isYarn() {
const { npm_config_user_agent } = process.env;
if (npm_config_user_agent) {
return /\byarn\//.test(npm_config_user_agent);
}
return false;
}
function fetch(url) {
return new Promise((resolve, reject) => {
https.get(url, (res) => {
if ((res.statusCode === 301 || res.statusCode === 302) && res.headers.location)
return fetch(res.headers.location).then(resolve, reject);
if (res.statusCode !== 200)
return reject(new Error(`Server responded with ${res.statusCode}`));
let chunks = [];
res.on("data", (chunk) => chunks.push(chunk));
res.on("end", () => resolve(Buffer.concat(chunks)));
}).on("error", reject);
});
}
function extractFileFromTarGzip(buffer, subpath) {
try {
buffer = zlib.unzipSync(buffer);
} catch (err) {
throw new Error(`Invalid gzip data in archive: ${err && err.message || err}`);
}
let str = (i, n) => String.fromCharCode(...buffer.subarray(i, i + n)).replace(/\0.*$/, "");
let offset = 0;
subpath = `package/${subpath}`;
while (offset < buffer.length) {
let name = str(offset, 100);
let size = parseInt(str(offset + 124, 12), 8);
offset += 512;
if (!isNaN(size) && size >= 0) {
if (name === subpath) return buffer.subarray(offset, offset + size);
offset += size + 511 & ~511;
}
}
throw new Error(`Could not find ${JSON.stringify(subpath)} in archive`);
}
function installUsingNPM(pkg, subpath, binPath) {
const env = { ...process.env, npm_config_global: void 0 };
const esbuildLibDir = path2.dirname(require.resolve("esbuild"));
const installDir = path2.join(esbuildLibDir, "npm-install");
fs2.mkdirSync(installDir);
try {
fs2.writeFileSync(path2.join(installDir, "package.json"), "{}");
child_process.execSync(
`npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${packageJSON.version}`,
{ cwd: installDir, stdio: "pipe", env }
);
const installedBinPath = path2.join(installDir, "node_modules", pkg, subpath);
binaryIntegrityCheck(pkg, subpath, fs2.readFileSync(installedBinPath));
fs2.renameSync(installedBinPath, binPath);
} finally {
try {
removeRecursive(installDir);
} catch {
}
}
}
function removeRecursive(dir) {
for (const entry of fs2.readdirSync(dir)) {
const entryPath = path2.join(dir, entry);
let stats;
try {
stats = fs2.lstatSync(entryPath);
} catch {
continue;
}
if (stats.isDirectory()) removeRecursive(entryPath);
else fs2.unlinkSync(entryPath);
}
fs2.rmdirSync(dir);
}
function applyManualBinaryPathOverride(overridePath) {
const pathString = JSON.stringify(overridePath);
fs2.writeFileSync(toPath, `#!/usr/bin/env node
require('child_process').execFileSync(${pathString}, process.argv.slice(2), { stdio: 'inherit' });
`);
const libMain = path2.join(__dirname, "lib", "main.js");
const code = fs2.readFileSync(libMain, "utf8");
fs2.writeFileSync(libMain, `var ESBUILD_BINARY_PATH = ${pathString};
${code}`);
}
function maybeOptimizePackage(binPath, isWASM) {
if (os2.platform() !== "win32" && !isYarn() && !isWASM) {
const tempPath = path2.join(__dirname, "bin-esbuild");
try {
fs2.linkSync(binPath, tempPath);
fs2.renameSync(tempPath, toPath);
isToPathJS = false;
fs2.unlinkSync(tempPath);
} catch {
}
}
}
function binaryIntegrityCheck(pkg, subpath, bytes) {
const hash = crypto.createHash("sha256").update(bytes).digest("hex");
const key = `${pkg}/${subpath}`;
const expected = packageJSON["esbuild.binaryHashes"][key];
if (!expected) throw new Error(`Missing hash for "${key}"`);
if (hash !== expected) throw new Error(`"${hash.slice(0, 8)}..." doesn't match "${expected.slice(0, 8)}..." for "${pkg}"`);
}
async function downloadDirectlyFromNPM(pkg, subpath, binPath) {
const url = `https://registry.npmjs.org/${pkg}/-/${pkg.replace("@esbuild/", "")}-${packageJSON.version}.tgz`;
console.error(`[esbuild] Trying to download ${JSON.stringify(url)}`);
try {
const bytes = extractFileFromTarGzip(await fetch(url), subpath);
binaryIntegrityCheck(pkg, subpath, bytes);
fs2.writeFileSync(binPath, bytes);
fs2.chmodSync(binPath, 493);
} catch (e) {
console.error(`[esbuild] Failed to download ${JSON.stringify(url)}: ${e && e.message || e}`);
throw e;
}
}
async function checkAndPreparePackage() {
if (isValidBinaryPath(ESBUILD_BINARY_PATH)) {
if (!fs2.existsSync(ESBUILD_BINARY_PATH)) {
console.warn(`[esbuild] Ignoring bad configuration: ESBUILD_BINARY_PATH=${ESBUILD_BINARY_PATH}`);
} else {
applyManualBinaryPathOverride(ESBUILD_BINARY_PATH);
return;
}
}
const { pkg, subpath, isWASM } = pkgAndSubpathForCurrentPlatform();
let binPath;
try {
binPath = require.resolve(`${pkg}/${subpath}`);
} catch (e) {
console.error(`[esbuild] Failed to find package "${pkg}" on the file system
This can happen if you use the "--no-optional" flag. The "optionalDependencies"
package.json feature is used by esbuild to install the correct binary executable
for your current platform. This install script will now attempt to work around
this. If that fails, you need to remove the "--no-optional" flag to use esbuild.
`);
if (isWASM) throw new Error(`Failed to install package "${pkg}"`);
binPath = downloadedBinPath(pkg, subpath);
try {
console.error(`[esbuild] Trying to install package "${pkg}" using npm`);
installUsingNPM(pkg, subpath, binPath);
} catch (e2) {
console.error(`[esbuild] Failed to install package "${pkg}" using npm: ${e2 && e2.message || e2}`);
try {
await downloadDirectlyFromNPM(pkg, subpath, binPath);
} catch (e3) {
throw new Error(`Failed to install package "${pkg}"`);
}
}
}
maybeOptimizePackage(binPath, isWASM);
}
checkAndPreparePackage().then(() => {
if (isToPathJS) {
validateBinaryVersion(process.execPath, toPath);
} else {
validateBinaryVersion(toPath);
}
});
+716
View File
@@ -0,0 +1,716 @@
export type Platform = 'browser' | 'node' | 'neutral'
export type Format = 'iife' | 'cjs' | 'esm'
export type Loader = 'base64' | 'binary' | 'copy' | 'css' | 'dataurl' | 'default' | 'empty' | 'file' | 'js' | 'json' | 'jsx' | 'local-css' | 'text' | 'ts' | 'tsx'
export type LogLevel = 'verbose' | 'debug' | 'info' | 'warning' | 'error' | 'silent'
export type Charset = 'ascii' | 'utf8'
export type Drop = 'console' | 'debugger'
export type AbsPaths = 'code' | 'log' | 'metafile'
interface CommonOptions {
/** Documentation: https://esbuild.github.io/api/#sourcemap */
sourcemap?: boolean | 'linked' | 'inline' | 'external' | 'both'
/** Documentation: https://esbuild.github.io/api/#legal-comments */
legalComments?: 'none' | 'inline' | 'eof' | 'linked' | 'external'
/** Documentation: https://esbuild.github.io/api/#source-root */
sourceRoot?: string
/** Documentation: https://esbuild.github.io/api/#sources-content */
sourcesContent?: boolean
/** Documentation: https://esbuild.github.io/api/#format */
format?: Format
/** Documentation: https://esbuild.github.io/api/#global-name */
globalName?: string
/** Documentation: https://esbuild.github.io/api/#target */
target?: string | string[]
/** Documentation: https://esbuild.github.io/api/#supported */
supported?: Record<string, boolean>
/** Documentation: https://esbuild.github.io/api/#platform */
platform?: Platform
/** Documentation: https://esbuild.github.io/api/#mangle-props */
mangleProps?: RegExp
/** Documentation: https://esbuild.github.io/api/#mangle-props */
reserveProps?: RegExp
/** Documentation: https://esbuild.github.io/api/#mangle-props */
mangleQuoted?: boolean
/** Documentation: https://esbuild.github.io/api/#mangle-props */
mangleCache?: Record<string, string | false>
/** Documentation: https://esbuild.github.io/api/#drop */
drop?: Drop[]
/** Documentation: https://esbuild.github.io/api/#drop-labels */
dropLabels?: string[]
/** Documentation: https://esbuild.github.io/api/#minify */
minify?: boolean
/** Documentation: https://esbuild.github.io/api/#minify */
minifyWhitespace?: boolean
/** Documentation: https://esbuild.github.io/api/#minify */
minifyIdentifiers?: boolean
/** Documentation: https://esbuild.github.io/api/#minify */
minifySyntax?: boolean
/** Documentation: https://esbuild.github.io/api/#line-limit */
lineLimit?: number
/** Documentation: https://esbuild.github.io/api/#charset */
charset?: Charset
/** Documentation: https://esbuild.github.io/api/#tree-shaking */
treeShaking?: boolean
/** Documentation: https://esbuild.github.io/api/#ignore-annotations */
ignoreAnnotations?: boolean
/** Documentation: https://esbuild.github.io/api/#jsx */
jsx?: 'transform' | 'preserve' | 'automatic'
/** Documentation: https://esbuild.github.io/api/#jsx-factory */
jsxFactory?: string
/** Documentation: https://esbuild.github.io/api/#jsx-fragment */
jsxFragment?: string
/** Documentation: https://esbuild.github.io/api/#jsx-import-source */
jsxImportSource?: string
/** Documentation: https://esbuild.github.io/api/#jsx-development */
jsxDev?: boolean
/** Documentation: https://esbuild.github.io/api/#jsx-side-effects */
jsxSideEffects?: boolean
/** Documentation: https://esbuild.github.io/api/#define */
define?: { [key: string]: string }
/** Documentation: https://esbuild.github.io/api/#pure */
pure?: string[]
/** Documentation: https://esbuild.github.io/api/#keep-names */
keepNames?: boolean
/** Documentation: https://esbuild.github.io/api/#abs-paths */
absPaths?: AbsPaths[]
/** Documentation: https://esbuild.github.io/api/#color */
color?: boolean
/** Documentation: https://esbuild.github.io/api/#log-level */
logLevel?: LogLevel
/** Documentation: https://esbuild.github.io/api/#log-limit */
logLimit?: number
/** Documentation: https://esbuild.github.io/api/#log-override */
logOverride?: Record<string, LogLevel>
/** Documentation: https://esbuild.github.io/api/#tsconfig-raw */
tsconfigRaw?: string | TsconfigRaw
}
export interface TsconfigRaw {
compilerOptions?: {
alwaysStrict?: boolean
baseUrl?: string
experimentalDecorators?: boolean
importsNotUsedAsValues?: 'remove' | 'preserve' | 'error'
jsx?: 'preserve' | 'react-native' | 'react' | 'react-jsx' | 'react-jsxdev'
jsxFactory?: string
jsxFragmentFactory?: string
jsxImportSource?: string
paths?: Record<string, string[]>
preserveValueImports?: boolean
strict?: boolean
target?: string
useDefineForClassFields?: boolean
verbatimModuleSyntax?: boolean
}
}
export interface BuildOptions extends CommonOptions {
/** Documentation: https://esbuild.github.io/api/#bundle */
bundle?: boolean
/** Documentation: https://esbuild.github.io/api/#splitting */
splitting?: boolean
/** Documentation: https://esbuild.github.io/api/#preserve-symlinks */
preserveSymlinks?: boolean
/** Documentation: https://esbuild.github.io/api/#outfile */
outfile?: string
/** Documentation: https://esbuild.github.io/api/#metafile */
metafile?: boolean
/** Documentation: https://esbuild.github.io/api/#outdir */
outdir?: string
/** Documentation: https://esbuild.github.io/api/#outbase */
outbase?: string
/** Documentation: https://esbuild.github.io/api/#external */
external?: string[]
/** Documentation: https://esbuild.github.io/api/#packages */
packages?: 'bundle' | 'external'
/** Documentation: https://esbuild.github.io/api/#alias */
alias?: Record<string, string>
/** Documentation: https://esbuild.github.io/api/#loader */
loader?: { [ext: string]: Loader }
/** Documentation: https://esbuild.github.io/api/#resolve-extensions */
resolveExtensions?: string[]
/** Documentation: https://esbuild.github.io/api/#main-fields */
mainFields?: string[]
/** Documentation: https://esbuild.github.io/api/#conditions */
conditions?: string[]
/** Documentation: https://esbuild.github.io/api/#write */
write?: boolean
/** Documentation: https://esbuild.github.io/api/#allow-overwrite */
allowOverwrite?: boolean
/** Documentation: https://esbuild.github.io/api/#tsconfig */
tsconfig?: string
/** Documentation: https://esbuild.github.io/api/#out-extension */
outExtension?: { [ext: string]: string }
/** Documentation: https://esbuild.github.io/api/#public-path */
publicPath?: string
/** Documentation: https://esbuild.github.io/api/#entry-names */
entryNames?: string
/** Documentation: https://esbuild.github.io/api/#chunk-names */
chunkNames?: string
/** Documentation: https://esbuild.github.io/api/#asset-names */
assetNames?: string
/** Documentation: https://esbuild.github.io/api/#inject */
inject?: string[]
/** Documentation: https://esbuild.github.io/api/#banner */
banner?: { [type: string]: string }
/** Documentation: https://esbuild.github.io/api/#footer */
footer?: { [type: string]: string }
/** Documentation: https://esbuild.github.io/api/#entry-points */
entryPoints?: (string | { in: string, out: string })[] | Record<string, string>
/** Documentation: https://esbuild.github.io/api/#stdin */
stdin?: StdinOptions
/** Documentation: https://esbuild.github.io/plugins/ */
plugins?: Plugin[]
/** Documentation: https://esbuild.github.io/api/#working-directory */
absWorkingDir?: string
/** Documentation: https://esbuild.github.io/api/#node-paths */
nodePaths?: string[]; // The "NODE_PATH" variable from Node.js
}
export interface StdinOptions {
contents: string | Uint8Array
resolveDir?: string
sourcefile?: string
loader?: Loader
}
export interface Message {
id: string
pluginName: string
text: string
location: Location | null
notes: Note[]
/**
* Optional user-specified data that is passed through unmodified. You can
* use this to stash the original error, for example.
*/
detail: any
}
export interface Note {
text: string
location: Location | null
}
export interface Location {
file: string
namespace: string
/** 1-based */
line: number
/** 0-based, in bytes */
column: number
/** in bytes */
length: number
lineText: string
suggestion: string
}
export interface OutputFile {
path: string
contents: Uint8Array
hash: string
/** "contents" as text (changes automatically with "contents") */
readonly text: string
}
export interface BuildResult<ProvidedOptions extends BuildOptions = BuildOptions> {
errors: Message[]
warnings: Message[]
/** Only when "write: false" */
outputFiles: OutputFile[] | (ProvidedOptions['write'] extends false ? never : undefined)
/** Only when "metafile: true" */
metafile: Metafile | (ProvidedOptions['metafile'] extends true ? never : undefined)
/** Only when "mangleCache" is present */
mangleCache: Record<string, string | false> | (ProvidedOptions['mangleCache'] extends Object ? never : undefined)
}
export interface BuildFailure extends Error {
errors: Message[]
warnings: Message[]
}
/** Documentation: https://esbuild.github.io/api/#serve-arguments */
export interface ServeOptions {
port?: number
host?: string
servedir?: string
keyfile?: string
certfile?: string
fallback?: string
cors?: CORSOptions
onRequest?: (args: ServeOnRequestArgs) => void
}
/** Documentation: https://esbuild.github.io/api/#cors */
export interface CORSOptions {
origin?: string | string[]
}
export interface ServeOnRequestArgs {
remoteAddress: string
method: string
path: string
status: number
/** The time to generate the response, not to send it */
timeInMS: number
}
/** Documentation: https://esbuild.github.io/api/#serve-return-values */
export interface ServeResult {
port: number
hosts: string[]
}
export interface TransformOptions extends CommonOptions {
/** Documentation: https://esbuild.github.io/api/#sourcefile */
sourcefile?: string
/** Documentation: https://esbuild.github.io/api/#loader */
loader?: Loader
/** Documentation: https://esbuild.github.io/api/#banner */
banner?: string
/** Documentation: https://esbuild.github.io/api/#footer */
footer?: string
}
export interface TransformResult<ProvidedOptions extends TransformOptions = TransformOptions> {
code: string
map: string
warnings: Message[]
/** Only when "mangleCache" is present */
mangleCache: Record<string, string | false> | (ProvidedOptions['mangleCache'] extends Object ? never : undefined)
/** Only when "legalComments" is "external" */
legalComments: string | (ProvidedOptions['legalComments'] extends 'external' ? never : undefined)
}
export interface TransformFailure extends Error {
errors: Message[]
warnings: Message[]
}
export interface Plugin {
name: string
setup: (build: PluginBuild) => (void | Promise<void>)
}
export interface PluginBuild {
/** Documentation: https://esbuild.github.io/plugins/#build-options */
initialOptions: BuildOptions
/** Documentation: https://esbuild.github.io/plugins/#resolve */
resolve(path: string, options?: ResolveOptions): Promise<ResolveResult>
/** Documentation: https://esbuild.github.io/plugins/#on-start */
onStart(callback: () =>
(OnStartResult | null | void | Promise<OnStartResult | null | void>)): void
/** Documentation: https://esbuild.github.io/plugins/#on-end */
onEnd(callback: (result: BuildResult) =>
(OnEndResult | null | void | Promise<OnEndResult | null | void>)): void
/** Documentation: https://esbuild.github.io/plugins/#on-resolve */
onResolve(options: OnResolveOptions, callback: (args: OnResolveArgs) =>
(OnResolveResult | null | undefined | Promise<OnResolveResult | null | undefined>)): void
/** Documentation: https://esbuild.github.io/plugins/#on-load */
onLoad(options: OnLoadOptions, callback: (args: OnLoadArgs) =>
(OnLoadResult | null | undefined | Promise<OnLoadResult | null | undefined>)): void
/** Documentation: https://esbuild.github.io/plugins/#on-dispose */
onDispose(callback: () => void): void
// This is a full copy of the esbuild library in case you need it
esbuild: {
context: typeof context,
build: typeof build,
buildSync: typeof buildSync,
transform: typeof transform,
transformSync: typeof transformSync,
formatMessages: typeof formatMessages,
formatMessagesSync: typeof formatMessagesSync,
analyzeMetafile: typeof analyzeMetafile,
analyzeMetafileSync: typeof analyzeMetafileSync,
initialize: typeof initialize,
version: typeof version,
}
}
/** Documentation: https://esbuild.github.io/plugins/#resolve-options */
export interface ResolveOptions {
pluginName?: string
importer?: string
namespace?: string
resolveDir?: string
kind?: ImportKind
pluginData?: any
with?: Record<string, string>
}
/** Documentation: https://esbuild.github.io/plugins/#resolve-results */
export interface ResolveResult {
errors: Message[]
warnings: Message[]
path: string
external: boolean
sideEffects: boolean
namespace: string
suffix: string
pluginData: any
}
export interface OnStartResult {
errors?: PartialMessage[]
warnings?: PartialMessage[]
}
export interface OnEndResult {
errors?: PartialMessage[]
warnings?: PartialMessage[]
}
/** Documentation: https://esbuild.github.io/plugins/#on-resolve-options */
export interface OnResolveOptions {
filter: RegExp
namespace?: string
}
/** Documentation: https://esbuild.github.io/plugins/#on-resolve-arguments */
export interface OnResolveArgs {
path: string
importer: string
namespace: string
resolveDir: string
kind: ImportKind
pluginData: any
with: Record<string, string>
}
export type ImportKind =
| 'entry-point'
// JS
| 'import-statement'
| 'require-call'
| 'dynamic-import'
| 'require-resolve'
// CSS
| 'import-rule'
| 'composes-from'
| 'url-token'
/** Documentation: https://esbuild.github.io/plugins/#on-resolve-results */
export interface OnResolveResult {
pluginName?: string
errors?: PartialMessage[]
warnings?: PartialMessage[]
path?: string
external?: boolean
sideEffects?: boolean
namespace?: string
suffix?: string
pluginData?: any
watchFiles?: string[]
watchDirs?: string[]
}
/** Documentation: https://esbuild.github.io/plugins/#on-load-options */
export interface OnLoadOptions {
filter: RegExp
namespace?: string
}
/** Documentation: https://esbuild.github.io/plugins/#on-load-arguments */
export interface OnLoadArgs {
path: string
namespace: string
suffix: string
pluginData: any
with: Record<string, string>
}
/** Documentation: https://esbuild.github.io/plugins/#on-load-results */
export interface OnLoadResult {
pluginName?: string
errors?: PartialMessage[]
warnings?: PartialMessage[]
contents?: string | Uint8Array
resolveDir?: string
loader?: Loader
pluginData?: any
watchFiles?: string[]
watchDirs?: string[]
}
export interface PartialMessage {
id?: string
pluginName?: string
text?: string
location?: Partial<Location> | null
notes?: PartialNote[]
detail?: any
}
export interface PartialNote {
text?: string
location?: Partial<Location> | null
}
/** Documentation: https://esbuild.github.io/api/#metafile */
export interface Metafile {
inputs: {
[path: string]: {
bytes: number
imports: {
path: string
kind: ImportKind
external?: boolean
original?: string
with?: Record<string, string>
}[]
format?: 'cjs' | 'esm'
with?: Record<string, string>
}
}
outputs: {
[path: string]: {
bytes: number
inputs: {
[path: string]: {
bytesInOutput: number
}
}
imports: {
path: string
kind: ImportKind | 'file-loader'
external?: boolean
}[]
exports: string[]
entryPoint?: string
cssBundle?: string
}
}
}
export interface FormatMessagesOptions {
kind: 'error' | 'warning'
color?: boolean
terminalWidth?: number
}
export interface AnalyzeMetafileOptions {
color?: boolean
verbose?: boolean
}
/** Documentation: https://esbuild.github.io/api/#watch-arguments */
export interface WatchOptions {
delay?: number // In milliseconds
}
export interface BuildContext<ProvidedOptions extends BuildOptions = BuildOptions> {
/** Documentation: https://esbuild.github.io/api/#rebuild */
rebuild(): Promise<BuildResult<ProvidedOptions>>
/** Documentation: https://esbuild.github.io/api/#watch */
watch(options?: WatchOptions): Promise<void>
/** Documentation: https://esbuild.github.io/api/#serve */
serve(options?: ServeOptions): Promise<ServeResult>
cancel(): Promise<void>
dispose(): Promise<void>
}
// This is a TypeScript type-level function which replaces any keys in "In"
// that aren't in "Out" with "never". We use this to reject properties with
// typos in object literals. See: https://stackoverflow.com/questions/49580725
type SameShape<Out, In extends Out> = In & { [Key in Exclude<keyof In, keyof Out>]: never }
/**
* This function invokes the "esbuild" command-line tool for you. It returns a
* promise that either resolves with a "BuildResult" object or rejects with a
* "BuildFailure" object.
*
* - Works in node: yes
* - Works in browser: yes
*
* Documentation: https://esbuild.github.io/api/#build
*/
export declare function build<T extends BuildOptions>(options: SameShape<BuildOptions, T>): Promise<BuildResult<T>>
/**
* This is the advanced long-running form of "build" that supports additional
* features such as watch mode and a local development server.
*
* - Works in node: yes
* - Works in browser: no
*
* Documentation: https://esbuild.github.io/api/#build
*/
export declare function context<T extends BuildOptions>(options: SameShape<BuildOptions, T>): Promise<BuildContext<T>>
/**
* This function transforms a single JavaScript file. It can be used to minify
* JavaScript, convert TypeScript/JSX to JavaScript, or convert newer JavaScript
* to older JavaScript. It returns a promise that is either resolved with a
* "TransformResult" object or rejected with a "TransformFailure" object.
*
* - Works in node: yes
* - Works in browser: yes
*
* Documentation: https://esbuild.github.io/api/#transform
*/
export declare function transform<T extends TransformOptions>(input: string | Uint8Array, options?: SameShape<TransformOptions, T>): Promise<TransformResult<T>>
/**
* Converts log messages to formatted message strings suitable for printing in
* the terminal. This allows you to reuse the built-in behavior of esbuild's
* log message formatter. This is a batch-oriented API for efficiency.
*
* - Works in node: yes
* - Works in browser: yes
*/
export declare function formatMessages(messages: PartialMessage[], options: FormatMessagesOptions): Promise<string[]>
/**
* Pretty-prints an analysis of the metafile JSON to a string. This is just for
* convenience to be able to match esbuild's pretty-printing exactly. If you want
* to customize it, you can just inspect the data in the metafile yourself.
*
* - Works in node: yes
* - Works in browser: yes
*
* Documentation: https://esbuild.github.io/api/#analyze
*/
export declare function analyzeMetafile(metafile: Metafile | string, options?: AnalyzeMetafileOptions): Promise<string>
/**
* A synchronous version of "build".
*
* - Works in node: yes
* - Works in browser: no
*
* Documentation: https://esbuild.github.io/api/#build
*/
export declare function buildSync<T extends BuildOptions>(options: SameShape<BuildOptions, T>): BuildResult<T>
/**
* A synchronous version of "transform".
*
* - Works in node: yes
* - Works in browser: no
*
* Documentation: https://esbuild.github.io/api/#transform
*/
export declare function transformSync<T extends TransformOptions>(input: string | Uint8Array, options?: SameShape<TransformOptions, T>): TransformResult<T>
/**
* A synchronous version of "formatMessages".
*
* - Works in node: yes
* - Works in browser: no
*/
export declare function formatMessagesSync(messages: PartialMessage[], options: FormatMessagesOptions): string[]
/**
* A synchronous version of "analyzeMetafile".
*
* - Works in node: yes
* - Works in browser: no
*
* Documentation: https://esbuild.github.io/api/#analyze
*/
export declare function analyzeMetafileSync(metafile: Metafile | string, options?: AnalyzeMetafileOptions): string
/**
* This configures the browser-based version of esbuild. It is necessary to
* call this first and wait for the returned promise to be resolved before
* making other API calls when using esbuild in the browser.
*
* - Works in node: yes
* - Works in browser: yes ("options" is required)
*
* Documentation: https://esbuild.github.io/api/#browser
*/
export declare function initialize(options: InitializeOptions): Promise<void>
export interface InitializeOptions {
/**
* The URL of the "esbuild.wasm" file. This must be provided when running
* esbuild in the browser.
*/
wasmURL?: string | URL
/**
* The result of calling "new WebAssembly.Module(buffer)" where "buffer"
* is a typed array or ArrayBuffer containing the binary code of the
* "esbuild.wasm" file.
*
* You can use this as an alternative to "wasmURL" for environments where it's
* not possible to download the WebAssembly module.
*/
wasmModule?: WebAssembly.Module
/**
* By default esbuild runs the WebAssembly-based browser API in a web worker
* to avoid blocking the UI thread. This can be disabled by setting "worker"
* to false.
*/
worker?: boolean
}
export let version: string
// Call this function to terminate esbuild's child process. The child process
// is not terminated and re-created after each API call because it's more
// efficient to keep it around when there are multiple API calls.
//
// In node this happens automatically before the parent node process exits. So
// you only need to call this if you know you will not make any more esbuild
// API calls and you want to clean up resources.
//
// Unlike node, Deno lacks the necessary APIs to clean up child processes
// automatically. You must manually call stop() in Deno when you're done
// using esbuild or Deno will continue running forever.
//
// Another reason you might want to call this is if you are using esbuild from
// within a Deno test. Deno fails tests that create a child process without
// killing it before the test ends, so you have to call this function (and
// await the returned promise) in every Deno test that uses esbuild.
export declare function stop(): Promise<void>
// Note: These declarations exist to avoid type errors when you omit "dom" from
// "lib" in your "tsconfig.json" file. TypeScript confusingly declares the
// global "WebAssembly" type in "lib.dom.d.ts" even though it has nothing to do
// with the browser DOM and is present in many non-browser JavaScript runtimes
// (e.g. node and deno). Declaring it here allows esbuild's API to be used in
// these scenarios.
//
// There's an open issue about getting this problem corrected (although these
// declarations will need to remain even if this is fixed for backward
// compatibility with older TypeScript versions):
//
// https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/826
//
declare global {
namespace WebAssembly {
interface Module {
}
}
interface URL {
}
}
+2532
View File
File diff suppressed because it is too large Load Diff
+74
View File
@@ -0,0 +1,74 @@
{
"name": "esbuild",
"version": "0.28.1",
"description": "An extremely fast JavaScript and CSS bundler and minifier.",
"repository": {
"type": "git",
"url": "git+https://github.com/evanw/esbuild.git"
},
"scripts": {
"postinstall": "node install.js"
},
"main": "lib/main.js",
"types": "lib/main.d.ts",
"engines": {
"node": ">=18"
},
"bin": {
"esbuild": "bin/esbuild"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.28.1",
"@esbuild/android-arm": "0.28.1",
"@esbuild/android-arm64": "0.28.1",
"@esbuild/android-x64": "0.28.1",
"@esbuild/darwin-arm64": "0.28.1",
"@esbuild/darwin-x64": "0.28.1",
"@esbuild/freebsd-arm64": "0.28.1",
"@esbuild/freebsd-x64": "0.28.1",
"@esbuild/linux-arm": "0.28.1",
"@esbuild/linux-arm64": "0.28.1",
"@esbuild/linux-ia32": "0.28.1",
"@esbuild/linux-loong64": "0.28.1",
"@esbuild/linux-mips64el": "0.28.1",
"@esbuild/linux-ppc64": "0.28.1",
"@esbuild/linux-riscv64": "0.28.1",
"@esbuild/linux-s390x": "0.28.1",
"@esbuild/linux-x64": "0.28.1",
"@esbuild/netbsd-arm64": "0.28.1",
"@esbuild/netbsd-x64": "0.28.1",
"@esbuild/openbsd-arm64": "0.28.1",
"@esbuild/openbsd-x64": "0.28.1",
"@esbuild/openharmony-arm64": "0.28.1",
"@esbuild/sunos-x64": "0.28.1",
"@esbuild/win32-arm64": "0.28.1",
"@esbuild/win32-ia32": "0.28.1",
"@esbuild/win32-x64": "0.28.1"
},
"license": "MIT",
"esbuild.binaryHashes": {
"@esbuild/aix-ppc64/bin/esbuild": "0dd860154344f94b7a9367e64ffc2bc5b89a4313b4a399e5127cdc4ff5000303",
"@esbuild/android-arm64/bin/esbuild": "087671da02d323e7915fafc13567c0929192633ed544bd8adee9bc020fddf5b4",
"@esbuild/darwin-arm64/bin/esbuild": "e2dc9a52440a2a34f09434a2f4843cb1e30f84e40dcf238976ec61ef8cd7f36a",
"@esbuild/darwin-x64/bin/esbuild": "dd53ccf32f9b5b3ab30d41388ef1fc8f81c44ca57ee7a32a7364a1753308d009",
"@esbuild/freebsd-arm64/bin/esbuild": "5fef5a5ef24d9660d7711b756be5ddeba1fb3ca8dd62d703682ebb9fab3b68b0",
"@esbuild/freebsd-x64/bin/esbuild": "4427a8cbfa0661943ccfef2606a65b35f3411ac73e447e86f7732aace61e4609",
"@esbuild/linux-arm/bin/esbuild": "a2d93f7a8b1c9f91d47beec987888b4765c890501b6274f4bdff4061a5e0d9fd",
"@esbuild/linux-arm64/bin/esbuild": "51e829ba36f36be6d9aea6e329ddc4f9350302339b16aaca96a3cb97f64a8ebb",
"@esbuild/linux-ia32/bin/esbuild": "9cd7515a75d6f96b0aa055861cf987498315428088cd6d18de5082f904ae5794",
"@esbuild/linux-loong64/bin/esbuild": "73fa76af9b13f7a27fdb20673b8c2af927fe1511d14e51edeb4b7b71f7f03d0e",
"@esbuild/linux-mips64el/bin/esbuild": "d734787abc3c99d95242805047fe32da85a5822f04bf33d766a966bf5fd85488",
"@esbuild/linux-ppc64/bin/esbuild": "90709144617c2adf8f6c14937f03b114c259de0b9309666e3a9d89a1fb266d04",
"@esbuild/linux-riscv64/bin/esbuild": "86df35a46bedde8b756edb6565a1df7b5a832ad74dd0e179608cbf6509a2582a",
"@esbuild/linux-s390x/bin/esbuild": "f8cad0db35132e5ac3065c4345c36e7ffe18fdc98417a61bcf5a95a6c694e57c",
"@esbuild/linux-x64/bin/esbuild": "0c6588b092a2c291a72bab90659f3c9e0e25e0fe59c9ac12b4dae4d945e5548c",
"@esbuild/netbsd-arm64/bin/esbuild": "490cfdac2d96d5608d91cf55bdf4052bbde7013dafe87ec7adc7784778ad4d4c",
"@esbuild/netbsd-x64/bin/esbuild": "c61e0e4c553a4986fd0e9d63a0425e93be831ff7b13bfb8a564368fb7590f85d",
"@esbuild/openbsd-arm64/bin/esbuild": "f9d814698e26c09c3f90d4c103cbdf3832c9f2c841d64a93889d63d23da9b8cf",
"@esbuild/openbsd-x64/bin/esbuild": "2e30dce11f7236aa362c1c57212cc696f51472169aa417f30e9b641f3b7dcade",
"@esbuild/sunos-x64/bin/esbuild": "770e0d2bc930b1a1d19d3f43243ff8f393efddb599e7f5843160feacd253267d",
"@esbuild/win32-arm64/esbuild.exe": "bfb8798ab678f1ce4a723739f4a3eabab3244d7a04eeb12be2eb9f58095c13ef",
"@esbuild/win32-ia32/esbuild.exe": "8fa99b6e0945830fce8d7e208fdb21763aa4aea875751f4a0eec7f6e262af1dd",
"@esbuild/win32-x64/esbuild.exe": "ec02ee9b14ab332416fedd10614dfb80eed5304d94f67745067c011934a8c3c3"
}
}
+496
View File
@@ -0,0 +1,496 @@
{
"name": "markdown2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"devDependencies": {
"esbuild": "^0.28.1"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz",
"integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz",
"integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz",
"integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz",
"integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
"integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz",
"integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz",
"integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz",
"integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz",
"integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz",
"integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz",
"integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz",
"integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz",
"integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz",
"integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz",
"integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz",
"integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz",
"integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz",
"integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz",
"integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz",
"integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz",
"integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz",
"integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz",
"integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz",
"integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz",
"integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz",
"integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/esbuild": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
"integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.28.1",
"@esbuild/android-arm": "0.28.1",
"@esbuild/android-arm64": "0.28.1",
"@esbuild/android-x64": "0.28.1",
"@esbuild/darwin-arm64": "0.28.1",
"@esbuild/darwin-x64": "0.28.1",
"@esbuild/freebsd-arm64": "0.28.1",
"@esbuild/freebsd-x64": "0.28.1",
"@esbuild/linux-arm": "0.28.1",
"@esbuild/linux-arm64": "0.28.1",
"@esbuild/linux-ia32": "0.28.1",
"@esbuild/linux-loong64": "0.28.1",
"@esbuild/linux-mips64el": "0.28.1",
"@esbuild/linux-ppc64": "0.28.1",
"@esbuild/linux-riscv64": "0.28.1",
"@esbuild/linux-s390x": "0.28.1",
"@esbuild/linux-x64": "0.28.1",
"@esbuild/netbsd-arm64": "0.28.1",
"@esbuild/netbsd-x64": "0.28.1",
"@esbuild/openbsd-arm64": "0.28.1",
"@esbuild/openbsd-x64": "0.28.1",
"@esbuild/openharmony-arm64": "0.28.1",
"@esbuild/sunos-x64": "0.28.1",
"@esbuild/win32-arm64": "0.28.1",
"@esbuild/win32-ia32": "0.28.1",
"@esbuild/win32-x64": "0.28.1"
}
}
}
}
+5
View File
@@ -0,0 +1,5 @@
{
"devDependencies": {
"esbuild": "^0.28.1"
}
}
-8
View File
@@ -1,8 +0,0 @@
<script type="module" src="main.js"></script>
<div id="text"></div>
<style>
div p {
display: inline;
margin: 0;
}
</style>
-425
View File
@@ -1,425 +0,0 @@
-module(filepath).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([join/2, split_unix/1, directory_name/1, is_absolute/1, split_windows/1, split/1, base_name/1, extension/1, strip_extension/1, expand/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Work with file paths in Gleam!\n"
"\n"
" This library expects paths to be valid unicode. If you need to work with\n"
" non-unicode paths you will need to convert them to unicode before using\n"
" this library.\n"
).
-file("src/filepath.gleam", 49).
-spec relative(binary()) -> binary().
relative(Path) ->
case Path of
<<"/"/utf8, Path@1/binary>> ->
relative(Path@1);
_ ->
Path
end.
-file("src/filepath.gleam", 56).
-spec remove_trailing_slash(binary()) -> binary().
remove_trailing_slash(Path) ->
case gleam@string:ends_with(Path, <<"/"/utf8>>) of
true ->
gleam@string:drop_end(Path, 1);
false ->
Path
end.
-file("src/filepath.gleam", 35).
?DOC(
" Join two paths together.\n"
"\n"
" This function does not expand `..` or `.` segments, use the `expand`\n"
" function to do this.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" join(\"/usr/local\", \"bin\")\n"
" // -> \"/usr/local/bin\"\n"
" ```\n"
).
-spec join(binary(), binary()) -> binary().
join(Left, Right) ->
_pipe@2 = case {Left, Right} of
{_, <<"/"/utf8>>} ->
Left;
{<<""/utf8>>, _} ->
relative(Right);
{<<"/"/utf8>>, <<"/"/utf8, _/binary>>} ->
Right;
{<<"/"/utf8>>, _} ->
<<Left/binary, Right/binary>>;
{_, _} ->
_pipe = remove_trailing_slash(Left),
_pipe@1 = gleam@string:append(_pipe, <<"/"/utf8>>),
gleam@string:append(_pipe@1, relative(Right))
end,
remove_trailing_slash(_pipe@2).
-file("src/filepath.gleam", 97).
?DOC(
" Split a path into its segments, using `/` as the path separator.\n"
"\n"
" Typically you would want to use `split` instead of this function, but if you\n"
" want non-Windows path behaviour on a Windows system then you can use this\n"
" function.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" split(\"/usr/local/bin\", \"bin\")\n"
" // -> [\"/\", \"usr\", \"local\", \"bin\"]\n"
" ```\n"
).
-spec split_unix(binary()) -> list(binary()).
split_unix(Path) ->
_pipe = case gleam@string:split(Path, <<"/"/utf8>>) of
[<<""/utf8>>] ->
[];
[<<""/utf8>> | Rest] ->
[<<"/"/utf8>> | Rest];
Rest@1 ->
Rest@1
end,
gleam@list:filter(_pipe, fun(X) -> X /= <<""/utf8>> end).
-file("src/filepath.gleam", 267).
-spec get_directory_name(list(binary()), binary(), binary()) -> binary().
get_directory_name(Path, Acc, Segment) ->
case Path of
[<<"/"/utf8>> | Rest] ->
get_directory_name(
Rest,
<<Acc/binary, Segment/binary>>,
<<"/"/utf8>>
);
[First | Rest@1] ->
get_directory_name(Rest@1, Acc, <<Segment/binary, First/binary>>);
[] ->
Acc
end.
-file("src/filepath.gleam", 259).
?DOC(
" Get the directory name of a path, that is the path without the file name.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" directory_name(\"/usr/local/bin\")\n"
" // -> \"/usr/local\"\n"
" ```\n"
).
-spec directory_name(binary()) -> binary().
directory_name(Path) ->
Path@1 = remove_trailing_slash(Path),
case Path@1 of
<<"/"/utf8, Rest/binary>> ->
get_directory_name(
gleam@string:to_graphemes(Rest),
<<"/"/utf8>>,
<<""/utf8>>
);
_ ->
get_directory_name(
gleam@string:to_graphemes(Path@1),
<<""/utf8>>,
<<""/utf8>>
)
end.
-file("src/filepath.gleam", 294).
?DOC(
" Check if a path is absolute.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" is_absolute(\"/usr/local/bin\")\n"
" // -> True\n"
" ```\n"
"\n"
" ```gleam\n"
" is_absolute(\"usr/local/bin\")\n"
" // -> False\n"
" ```\n"
).
-spec is_absolute(binary()) -> boolean().
is_absolute(Path) ->
gleam@string:starts_with(Path, <<"/"/utf8>>).
-file("src/filepath.gleam", 339).
-spec expand_segments(list(binary()), list(binary())) -> {ok, binary()} |
{error, nil}.
expand_segments(Path, Base) ->
case {Base, Path} of
{[<<""/utf8>>], [<<".."/utf8>> | _]} ->
{error, nil};
{[], [<<".."/utf8>> | _]} ->
{error, nil};
{[_ | Base@1], [<<".."/utf8>> | Path@1]} ->
expand_segments(Path@1, Base@1);
{_, [<<"."/utf8>> | Path@2]} ->
expand_segments(Path@2, Base);
{_, [S | Path@3]} ->
expand_segments(Path@3, [S | Base]);
{_, []} ->
{ok, gleam@string:join(lists:reverse(Base), <<"/"/utf8>>)}
end.
-file("src/filepath.gleam", 364).
-spec root_slash_to_empty(list(binary())) -> list(binary()).
root_slash_to_empty(Segments) ->
case Segments of
[<<"/"/utf8>> | Rest] ->
[<<""/utf8>> | Rest];
_ ->
Segments
end.
-file("src/filepath.gleam", 153).
-spec pop_windows_drive_specifier(binary()) -> {gleam@option:option(binary()),
binary()}.
pop_windows_drive_specifier(Path) ->
Start = gleam@string:slice(Path, 0, 3),
Codepoints = gleam@string:to_utf_codepoints(Start),
case gleam@list:map(Codepoints, fun gleam@string:utf_codepoint_to_int/1) of
[Drive, Colon, Slash] when (((Slash =:= 47) orelse (Slash =:= 92)) andalso (Colon =:= 58)) andalso (((Drive >= 65) andalso (Drive =< 90)) orelse ((Drive >= 97) andalso (Drive =< 122))) ->
Drive_letter = gleam@string:slice(Path, 0, 1),
Drive@1 = <<(gleam@string:lowercase(Drive_letter))/binary,
":/"/utf8>>,
Path@1 = gleam@string:drop_start(Path, 3),
{{some, Drive@1}, Path@1};
_ ->
{none, Path}
end.
-file("src/filepath.gleam", 120).
?DOC(
" Split a path into its segments, using `/` and `\\` as the path separators. If\n"
" there is a drive letter at the start of the path then it is lowercased.\n"
"\n"
" Typically you would want to use `split` instead of this function, but if you\n"
" want Windows path behaviour on a non-Windows system then you can use this\n"
" function.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" split(\"/usr/local/bin\", \"bin\")\n"
" // -> [\"/\", \"usr\", \"local\", \"bin\"]\n"
" ```\n"
).
-spec split_windows(binary()) -> list(binary()).
split_windows(Path) ->
{Drive, Path@1} = pop_windows_drive_specifier(Path),
Segments = begin
_pipe = gleam@string:split(Path@1, <<"/"/utf8>>),
gleam@list:flat_map(
_pipe,
fun(_capture) -> gleam@string:split(_capture, <<"\\"/utf8>>) end
)
end,
Segments@1 = case Drive of
{some, Drive@1} ->
[Drive@1 | Segments];
none ->
Segments
end,
case Segments@1 of
[<<""/utf8>>] ->
[];
[<<""/utf8>> | Rest] ->
[<<"/"/utf8>> | Rest];
Rest@1 ->
Rest@1
end.
-file("src/filepath.gleam", 77).
?DOC(
" Split a path into its segments.\n"
"\n"
" When running on Windows both `/` and `\\` are treated as path separators, and \n"
" if the path starts with a drive letter then the drive letter then it is\n"
" lowercased.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" split(\"/usr/local/bin\", \"bin\")\n"
" // -> [\"/\", \"usr\", \"local\", \"bin\"]\n"
" ```\n"
).
-spec split(binary()) -> list(binary()).
split(Path) ->
case filepath_ffi:is_windows() of
true ->
split_windows(Path);
false ->
split_unix(Path)
end.
-file("src/filepath.gleam", 240).
?DOC(
" Get the base name of a path, that is the name of the file without the\n"
" containing directory.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" base_name(\"/usr/local/bin\")\n"
" // -> \"bin\"\n"
" ```\n"
).
-spec base_name(binary()) -> binary().
base_name(Path) ->
gleam@bool:guard(Path =:= <<"/"/utf8>>, <<""/utf8>>, fun() -> _pipe = Path,
_pipe@1 = split(_pipe),
_pipe@2 = gleam@list:last(_pipe@1),
gleam@result:unwrap(_pipe@2, <<""/utf8>>) end).
-file("src/filepath.gleam", 190).
?DOC(
" Get the file extension of a path.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" extension(\"src/main.gleam\")\n"
" // -> Ok(\"gleam\")\n"
" ```\n"
"\n"
" ```gleam\n"
" extension(\"package.tar.gz\")\n"
" // -> Ok(\"gz\")\n"
" ```\n"
).
-spec extension(binary()) -> {ok, binary()} | {error, nil}.
extension(Path) ->
File = base_name(Path),
case gleam@string:split(File, <<"."/utf8>>) of
[<<""/utf8>>, _] ->
{error, nil};
[_, Extension] ->
{ok, Extension};
[_ | Rest] ->
gleam@list:last(Rest);
_ ->
{error, nil}
end.
-file("src/filepath.gleam", 219).
?DOC(
" Remove the extension from a file, if it has any.\n"
" \n"
" ## Examples\n"
" \n"
" ```gleam\n"
" strip_extension(\"src/main.gleam\")\n"
" // -> \"src/main\"\n"
" ```\n"
" \n"
" ```gleam\n"
" strip_extension(\"package.tar.gz\")\n"
" // -> \"package.tar\"\n"
" ```\n"
" \n"
" ```gleam\n"
" strip_extension(\"src/gleam\")\n"
" // -> \"src/gleam\"\n"
" ```\n"
).
-spec strip_extension(binary()) -> binary().
strip_extension(Path) ->
case extension(Path) of
{ok, Extension} ->
gleam@string:drop_end(Path, gleam@string:length(Extension) + 1);
{error, nil} ->
Path
end.
-file("src/filepath.gleam", 324).
?DOC(
" Expand `..` and `.` segments in a path.\n"
"\n"
" If the path has a `..` segment that would go up past the root of the path\n"
" then an error is returned. This may be useful to example to ensure that a\n"
" path specified by a user does not go outside of a directory.\n"
"\n"
" If the path is absolute then the result will always be absolute.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" expand(\"/usr/local/../bin\")\n"
" // -> Ok(\"/usr/bin\")\n"
" ```\n"
"\n"
" ```gleam\n"
" expand(\"/tmp/../..\")\n"
" // -> Error(Nil)\n"
" ```\n"
"\n"
" ```gleam\n"
" expand(\"src/../..\")\n"
" // -> Error(\"..\")\n"
" ```\n"
).
-spec expand(binary()) -> {ok, binary()} | {error, nil}.
expand(Path) ->
Is_absolute = is_absolute(Path),
Result = begin
_pipe = Path,
_pipe@1 = split(_pipe),
_pipe@2 = root_slash_to_empty(_pipe@1),
_pipe@3 = expand_segments(_pipe@2, []),
gleam@result:map(_pipe@3, fun remove_trailing_slash/1)
end,
case Is_absolute andalso (Result =:= {ok, <<""/utf8>>}) of
true ->
{ok, <<"/"/utf8>>};
false ->
Result
end.
-527
View File
@@ -1,527 +0,0 @@
import * as $bool from "../gleam_stdlib/gleam/bool.mjs";
import * as $list from "../gleam_stdlib/gleam/list.mjs";
import * as $option from "../gleam_stdlib/gleam/option.mjs";
import { None, Some } from "../gleam_stdlib/gleam/option.mjs";
import * as $result from "../gleam_stdlib/gleam/result.mjs";
import * as $string from "../gleam_stdlib/gleam/string.mjs";
import { is_windows } from "./filepath_ffi.mjs";
import { Ok, Error, toList, Empty as $Empty, prepend as listPrepend, isEqual } from "./gleam.mjs";
const codepoint_z_up = 122;
const codepoint_a_up = 97;
const codepoint_z = 90;
const codepoint_a = 65;
const codepoint_colon = 58;
const codepoint_backslash = 92;
const codepoint_slash = 47;
function remove_trailing_slash(path) {
let $ = $string.ends_with(path, "/");
if ($) {
return $string.drop_end(path, 1);
} else {
return path;
}
}
function relative(loop$path) {
while (true) {
let path = loop$path;
if (path.charCodeAt(0) === 47) {
let path$1 = path.slice(1);
loop$path = path$1;
} else {
return path;
}
}
}
/**
* Join two paths together.
*
* This function does not expand `..` or `.` segments, use the `expand`
* function to do this.
*
* ## Examples
*
* ```gleam
* join("/usr/local", "bin")
* // -> "/usr/local/bin"
* ```
*/
export function join(left, right) {
let _block;
if (right === "/") {
_block = left;
} else if (right.charCodeAt(0) === 47) {
if (left === "") {
_block = relative(right);
} else if (left === "/") {
_block = right;
} else {
let _pipe = remove_trailing_slash(left);
let _pipe$1 = $string.append(_pipe, "/");
_block = $string.append(_pipe$1, relative(right));
}
} else if (left === "") {
_block = relative(right);
} else if (left === "/") {
_block = left + right;
} else {
let _pipe = remove_trailing_slash(left);
let _pipe$1 = $string.append(_pipe, "/");
_block = $string.append(_pipe$1, relative(right));
}
let _pipe = _block;
return remove_trailing_slash(_pipe);
}
/**
* Split a path into its segments, using `/` as the path separator.
*
* Typically you would want to use `split` instead of this function, but if you
* want non-Windows path behaviour on a Windows system then you can use this
* function.
*
* ## Examples
*
* ```gleam
* split("/usr/local/bin", "bin")
* // -> ["/", "usr", "local", "bin"]
* ```
*/
export function split_unix(path) {
let _block;
let $ = $string.split(path, "/");
if ($ instanceof $Empty) {
_block = $;
} else {
let $1 = $.tail;
if ($1 instanceof $Empty) {
let $2 = $.head;
if ($2 === "") {
_block = toList([]);
} else {
_block = $;
}
} else {
let $2 = $.head;
if ($2 === "") {
let rest = $1;
_block = listPrepend("/", rest);
} else {
_block = $;
}
}
}
let _pipe = _block;
return $list.filter(_pipe, (x) => { return x !== ""; });
}
function pop_windows_drive_specifier(path) {
let start = $string.slice(path, 0, 3);
let codepoints = $string.to_utf_codepoints(start);
let $ = $list.map(codepoints, $string.utf_codepoint_to_int);
if ($ instanceof $Empty) {
return [new None(), path];
} else {
let $1 = $.tail;
if ($1 instanceof $Empty) {
return [new None(), path];
} else {
let $2 = $1.tail;
if ($2 instanceof $Empty) {
return [new None(), path];
} else {
let $3 = $2.tail;
if ($3 instanceof $Empty) {
let drive = $.head;
let colon = $1.head;
let slash = $2.head;
if (
(((slash === 47) || (slash === 92)) && (colon === 58)) && (((drive >= 65) && (drive <= 90)) || ((drive >= 97) && (drive <= 122)))
) {
let drive_letter = $string.slice(path, 0, 1);
let drive$1 = $string.lowercase(drive_letter) + ":/";
let path$1 = $string.drop_start(path, 3);
return [new Some(drive$1), path$1];
} else {
return [new None(), path];
}
} else {
return [new None(), path];
}
}
}
}
}
/**
* Split a path into its segments, using `/` and `\` as the path separators. If
* there is a drive letter at the start of the path then it is lowercased.
*
* Typically you would want to use `split` instead of this function, but if you
* want Windows path behaviour on a non-Windows system then you can use this
* function.
*
* ## Examples
*
* ```gleam
* split("/usr/local/bin", "bin")
* // -> ["/", "usr", "local", "bin"]
* ```
*/
export function split_windows(path) {
let $ = pop_windows_drive_specifier(path);
let drive = $[0];
let path$1 = $[1];
let _block;
let _pipe = $string.split(path$1, "/");
_block = $list.flat_map(
_pipe,
(_capture) => { return $string.split(_capture, "\\"); },
);
let segments = _block;
let _block$1;
if (drive instanceof Some) {
let drive$1 = drive[0];
_block$1 = listPrepend(drive$1, segments);
} else {
_block$1 = segments;
}
let segments$1 = _block$1;
if (segments$1 instanceof $Empty) {
return segments$1;
} else {
let $1 = segments$1.tail;
if ($1 instanceof $Empty) {
let $2 = segments$1.head;
if ($2 === "") {
return toList([]);
} else {
return segments$1;
}
} else {
let $2 = segments$1.head;
if ($2 === "") {
let rest = $1;
return listPrepend("/", rest);
} else {
return segments$1;
}
}
}
}
/**
* Split a path into its segments.
*
* When running on Windows both `/` and `\` are treated as path separators, and
* if the path starts with a drive letter then the drive letter then it is
* lowercased.
*
* ## Examples
*
* ```gleam
* split("/usr/local/bin", "bin")
* // -> ["/", "usr", "local", "bin"]
* ```
*/
export function split(path) {
let $ = is_windows();
if ($) {
return split_windows(path);
} else {
return split_unix(path);
}
}
/**
* Get the base name of a path, that is the name of the file without the
* containing directory.
*
* ## Examples
*
* ```gleam
* base_name("/usr/local/bin")
* // -> "bin"
* ```
*/
export function base_name(path) {
return $bool.guard(
path === "/",
"",
() => {
let _pipe = path;
let _pipe$1 = split(_pipe);
let _pipe$2 = $list.last(_pipe$1);
return $result.unwrap(_pipe$2, "");
},
);
}
/**
* Get the file extension of a path.
*
* ## Examples
*
* ```gleam
* extension("src/main.gleam")
* // -> Ok("gleam")
* ```
*
* ```gleam
* extension("package.tar.gz")
* // -> Ok("gz")
* ```
*/
export function extension(path) {
let file = base_name(path);
let $ = $string.split(file, ".");
if ($ instanceof $Empty) {
return new Error(undefined);
} else {
let $1 = $.tail;
if ($1 instanceof $Empty) {
let rest = $1;
return $list.last(rest);
} else {
let $2 = $1.tail;
if ($2 instanceof $Empty) {
let $3 = $.head;
if ($3 === "") {
return new Error(undefined);
} else {
let extension$1 = $1.head;
return new Ok(extension$1);
}
} else {
let rest = $1;
return $list.last(rest);
}
}
}
}
/**
* Remove the extension from a file, if it has any.
*
* ## Examples
*
* ```gleam
* strip_extension("src/main.gleam")
* // -> "src/main"
* ```
*
* ```gleam
* strip_extension("package.tar.gz")
* // -> "package.tar"
* ```
*
* ```gleam
* strip_extension("src/gleam")
* // -> "src/gleam"
* ```
*/
export function strip_extension(path) {
let $ = extension(path);
if ($ instanceof Ok) {
let extension$1 = $[0];
return $string.drop_end(path, $string.length(extension$1) + 1);
} else {
return path;
}
}
function get_directory_name(loop$path, loop$acc, loop$segment) {
while (true) {
let path = loop$path;
let acc = loop$acc;
let segment = loop$segment;
if (path instanceof $Empty) {
return acc;
} else {
let $ = path.head;
if ($ === "/") {
let rest = path.tail;
loop$path = rest;
loop$acc = acc + segment;
loop$segment = "/";
} else {
let first = $;
let rest = path.tail;
loop$path = rest;
loop$acc = acc;
loop$segment = segment + first;
}
}
}
}
/**
* Get the directory name of a path, that is the path without the file name.
*
* ## Examples
*
* ```gleam
* directory_name("/usr/local/bin")
* // -> "/usr/local"
* ```
*/
export function directory_name(path) {
let path$1 = remove_trailing_slash(path);
if (path$1.charCodeAt(0) === 47) {
let rest = path$1.slice(1);
return get_directory_name($string.to_graphemes(rest), "/", "");
} else {
return get_directory_name($string.to_graphemes(path$1), "", "");
}
}
/**
* Check if a path is absolute.
*
* ## Examples
*
* ```gleam
* is_absolute("/usr/local/bin")
* // -> True
* ```
*
* ```gleam
* is_absolute("usr/local/bin")
* // -> False
* ```
*/
export function is_absolute(path) {
return $string.starts_with(path, "/");
}
function expand_segments(loop$path, loop$base) {
while (true) {
let path = loop$path;
let base = loop$base;
if (path instanceof $Empty) {
return new Ok($string.join($list.reverse(base), "/"));
} else if (base instanceof $Empty) {
let $ = path.head;
if ($ === "..") {
return new Error(undefined);
} else if ($ === ".") {
let path$1 = path.tail;
loop$path = path$1;
loop$base = base;
} else {
let s = $;
let path$1 = path.tail;
loop$path = path$1;
loop$base = listPrepend(s, base);
}
} else {
let $ = base.tail;
if ($ instanceof $Empty) {
let $1 = path.head;
if ($1 === "..") {
let $2 = base.head;
if ($2 === "") {
return new Error(undefined);
} else {
let path$1 = path.tail;
let base$1 = $;
loop$path = path$1;
loop$base = base$1;
}
} else if ($1 === ".") {
let path$1 = path.tail;
loop$path = path$1;
loop$base = base;
} else {
let s = $1;
let path$1 = path.tail;
loop$path = path$1;
loop$base = listPrepend(s, base);
}
} else {
let $1 = path.head;
if ($1 === "..") {
let path$1 = path.tail;
let base$1 = $;
loop$path = path$1;
loop$base = base$1;
} else if ($1 === ".") {
let path$1 = path.tail;
loop$path = path$1;
loop$base = base;
} else {
let s = $1;
let path$1 = path.tail;
loop$path = path$1;
loop$base = listPrepend(s, base);
}
}
}
}
}
function root_slash_to_empty(segments) {
if (segments instanceof $Empty) {
return segments;
} else {
let $ = segments.head;
if ($ === "/") {
let rest = segments.tail;
return listPrepend("", rest);
} else {
return segments;
}
}
}
/**
* Expand `..` and `.` segments in a path.
*
* If the path has a `..` segment that would go up past the root of the path
* then an error is returned. This may be useful to example to ensure that a
* path specified by a user does not go outside of a directory.
*
* If the path is absolute then the result will always be absolute.
*
* ## Examples
*
* ```gleam
* expand("/usr/local/../bin")
* // -> Ok("/usr/bin")
* ```
*
* ```gleam
* expand("/tmp/../..")
* // -> Error(Nil)
* ```
*
* ```gleam
* expand("src/../..")
* // -> Error("..")
* ```
*/
export function expand(path) {
let is_absolute$1 = is_absolute(path);
let _block;
let _pipe = path;
let _pipe$1 = split(_pipe);
let _pipe$2 = root_slash_to_empty(_pipe$1);
let _pipe$3 = expand_segments(_pipe$2, toList([]));
_block = $result.map(_pipe$3, remove_trailing_slash);
let result = _block;
let $ = is_absolute$1 && (isEqual(result, new Ok("")));
if ($) {
return new Ok("/");
} else {
return result;
}
}
-9
View File
@@ -1,9 +0,0 @@
-module(filepath_ffi).
-export([is_windows/0]).
is_windows() ->
case os:type() of
{win32, _} -> true;
_ -> false
end.
-6
View File
@@ -1,6 +0,0 @@
export function is_windows() {
return (
globalThis?.process?.platform === "win32" ||
globalThis?.Deno?.build?.os === "windows"
);
}
-1
View File
@@ -1 +0,0 @@
export * from "../prelude.mjs";
-1
View File
@@ -1 +0,0 @@
1.17.0 0
-1
View File
@@ -1 +0,0 @@
export * from "../prelude.mjs";
-325
View File
@@ -1,325 +0,0 @@
import * as $bit_array from "../../gleam_stdlib/gleam/bit_array.mjs";
import * as $dict from "../../gleam_stdlib/gleam/dict.mjs";
import * as $dynamic from "../../gleam_stdlib/gleam/dynamic.mjs";
import * as $decode from "../../gleam_stdlib/gleam/dynamic/decode.mjs";
import * as $list from "../../gleam_stdlib/gleam/list.mjs";
import * as $option from "../../gleam_stdlib/gleam/option.mjs";
import { None, Some } from "../../gleam_stdlib/gleam/option.mjs";
import * as $result from "../../gleam_stdlib/gleam/result.mjs";
import * as $string_tree from "../../gleam_stdlib/gleam/string_tree.mjs";
import { Ok, Error, toList, prepend as listPrepend, CustomType as $CustomType } from "../gleam.mjs";
import {
decode as decode_string,
json_to_string as do_to_string,
json_to_string as to_string_tree,
identity as do_string,
identity as do_bool,
identity as do_int,
identity as do_float,
do_null,
object as do_object,
array as do_preprocessed_array,
} from "../gleam_json_ffi.mjs";
export { to_string_tree };
export class UnexpectedEndOfInput extends $CustomType {}
export const DecodeError$UnexpectedEndOfInput = () =>
new UnexpectedEndOfInput();
export const DecodeError$isUnexpectedEndOfInput = (value) =>
value instanceof UnexpectedEndOfInput;
export class UnexpectedByte extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
export const DecodeError$UnexpectedByte = ($0) => new UnexpectedByte($0);
export const DecodeError$isUnexpectedByte = (value) =>
value instanceof UnexpectedByte;
export const DecodeError$UnexpectedByte$0 = (value) => value[0];
export class UnexpectedSequence extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
export const DecodeError$UnexpectedSequence = ($0) =>
new UnexpectedSequence($0);
export const DecodeError$isUnexpectedSequence = (value) =>
value instanceof UnexpectedSequence;
export const DecodeError$UnexpectedSequence$0 = (value) => value[0];
export class UnableToDecode extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
export const DecodeError$UnableToDecode = ($0) => new UnableToDecode($0);
export const DecodeError$isUnableToDecode = (value) =>
value instanceof UnableToDecode;
export const DecodeError$UnableToDecode$0 = (value) => value[0];
function do_parse(json, decoder) {
return $result.try$(
decode_string(json),
(dynamic_value) => {
let _pipe = $decode.run(dynamic_value, decoder);
return $result.map_error(
_pipe,
(var0) => { return new UnableToDecode(var0); },
);
},
);
}
/**
* Decode a JSON string into dynamically typed data which can be decoded into
* typed data with the `gleam/dynamic` module.
*
* ## Examples
*
* ```gleam
* > parse("[1,2,3]", decode.list(of: decode.int))
* Ok([1, 2, 3])
* ```
*
* ```gleam
* > parse("[", decode.list(of: decode.int))
* Error(UnexpectedEndOfInput)
* ```
*
* ```gleam
* > parse("1", decode.string)
* Error(UnableToDecode([decode.DecodeError("String", "Int", [])]))
* ```
*/
export function parse(json, decoder) {
return do_parse(json, decoder);
}
function decode_to_dynamic(json) {
let $ = $bit_array.to_string(json);
if ($ instanceof Ok) {
let string$1 = $[0];
return decode_string(string$1);
} else {
return new Error(new UnexpectedByte(""));
}
}
/**
* Decode a JSON bit string into dynamically typed data which can be decoded
* into typed data with the `gleam/dynamic` module.
*
* ## Examples
*
* ```gleam
* > parse_bits(<<"[1,2,3]">>, decode.list(of: decode.int))
* Ok([1, 2, 3])
* ```
*
* ```gleam
* > parse_bits(<<"[">>, decode.list(of: decode.int))
* Error(UnexpectedEndOfInput)
* ```
*
* ```gleam
* > parse_bits(<<"1">>, decode.string)
* Error(UnableToDecode([decode.DecodeError("String", "Int", [])])),
* ```
*/
export function parse_bits(json, decoder) {
return $result.try$(
decode_to_dynamic(json),
(dynamic_value) => {
let _pipe = $decode.run(dynamic_value, decoder);
return $result.map_error(
_pipe,
(var0) => { return new UnableToDecode(var0); },
);
},
);
}
/**
* Convert a JSON value into a string.
*
* Where possible prefer the `to_string_tree` function as it is faster than
* this function, and BEAM VM IO is optimised for sending `StringTree` data.
*
* ## Examples
*
* ```gleam
* > to_string(array([1, 2, 3], of: int))
* "[1,2,3]"
* ```
*/
export function to_string(json) {
return do_to_string(json);
}
/**
* Encode a string into JSON, using normal JSON escaping.
*
* ## Examples
*
* ```gleam
* > to_string(string("Hello!"))
* "\"Hello!\""
* ```
*/
export function string(input) {
return do_string(input);
}
/**
* Encode a bool into JSON.
*
* ## Examples
*
* ```gleam
* > to_string(bool(False))
* "false"
* ```
*/
export function bool(input) {
return do_bool(input);
}
/**
* Encode an int into JSON.
*
* ## Examples
*
* ```gleam
* > to_string(int(50))
* "50"
* ```
*/
export function int(input) {
return do_int(input);
}
/**
* Encode a float into JSON.
*
* ## Examples
*
* ```gleam
* > to_string(float(4.7))
* "4.7"
* ```
*/
export function float(input) {
return do_float(input);
}
/**
* The JSON value null.
*
* ## Examples
*
* ```gleam
* > to_string(null())
* "null"
* ```
*/
export function null$() {
return do_null();
}
/**
* Encode an optional value into JSON, using null if it is the `None` variant.
*
* ## Examples
*
* ```gleam
* > to_string(nullable(Some(50), of: int))
* "50"
* ```
*
* ```gleam
* > to_string(nullable(None, of: int))
* "null"
* ```
*/
export function nullable(input, inner_type) {
if (input instanceof Some) {
let value = input[0];
return inner_type(value);
} else {
return null$();
}
}
/**
* Encode a list of key-value pairs into a JSON object.
*
* ## Examples
*
* ```gleam
* > to_string(object([
* #("game", string("Pac-Man")),
* #("score", int(3333360)),
* ]))
* "{\"game\":\"Pac-Mac\",\"score\":3333360}"
* ```
*/
export function object(entries) {
return do_object(entries);
}
/**
* Encode a list of JSON values into a JSON array.
*
* ## Examples
*
* ```gleam
* > to_string(preprocessed_array([int(1), float(2.0), string("3")]))
* "[1, 2.0, \"3\"]"
* ```
*/
export function preprocessed_array(from) {
return do_preprocessed_array(from);
}
/**
* Encode a list into a JSON array.
*
* ## Examples
*
* ```gleam
* > to_string(array([1, 2, 3], of: int))
* "[1, 2, 3]"
* ```
*/
export function array(entries, inner_type) {
let _pipe = entries;
let _pipe$1 = $list.map(_pipe, inner_type);
return preprocessed_array(_pipe$1);
}
/**
* Encode a Dict into a JSON object using the supplied functions to encode
* the keys and the values respectively.
*
* ## Examples
*
* ```gleam
* > to_string(dict(dict.from_list([ #(3, 3.0), #(4, 4.0)]), int.to_string, float)
* "{\"3\": 3.0, \"4\": 4.0}"
* ```
*/
export function dict(dict, keys, values) {
return object(
$dict.fold(
dict,
toList([]),
(acc, k, v) => { return listPrepend([keys(k), values(v)], acc); },
),
);
}
-304
View File
@@ -1,304 +0,0 @@
-module(gleam@json).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleam/json.gleam").
-export([parse_bits/2, parse/2, to_string/1, to_string_tree/1, string/1, bool/1, int/1, float/1, null/0, nullable/2, object/1, preprocessed_array/1, array/2, dict/3]).
-export_type([json/0, decode_error/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type json() :: any().
-type decode_error() :: unexpected_end_of_input |
{unexpected_byte, binary()} |
{unexpected_sequence, binary()} |
{unable_to_decode, list(gleam@dynamic@decode:decode_error())}.
-file("src/gleam/json.gleam", 88).
?DOC(
" Decode a JSON bit string into dynamically typed data which can be decoded\n"
" into typed data with the `gleam/dynamic` module.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > parse_bits(<<\"[1,2,3]\">>, decode.list(of: decode.int))\n"
" Ok([1, 2, 3])\n"
" ```\n"
"\n"
" ```gleam\n"
" > parse_bits(<<\"[\">>, decode.list(of: decode.int))\n"
" Error(UnexpectedEndOfInput)\n"
" ```\n"
"\n"
" ```gleam\n"
" > parse_bits(<<\"1\">>, decode.string)\n"
" Error(UnableToDecode([decode.DecodeError(\"String\", \"Int\", [])])),\n"
" ```\n"
).
-spec parse_bits(bitstring(), gleam@dynamic@decode:decoder(DNO)) -> {ok, DNO} |
{error, decode_error()}.
parse_bits(Json, Decoder) ->
gleam@result:'try'(
gleam_json_ffi:decode(Json),
fun(Dynamic_value) ->
_pipe = gleam@dynamic@decode:run(Dynamic_value, Decoder),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {unable_to_decode, Field@0} end
)
end
).
-file("src/gleam/json.gleam", 47).
-spec do_parse(binary(), gleam@dynamic@decode:decoder(DNI)) -> {ok, DNI} |
{error, decode_error()}.
do_parse(Json, Decoder) ->
Bits = gleam_stdlib:identity(Json),
parse_bits(Bits, Decoder).
-file("src/gleam/json.gleam", 39).
?DOC(
" Decode a JSON string into dynamically typed data which can be decoded into\n"
" typed data with the `gleam/dynamic` module.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > parse(\"[1,2,3]\", decode.list(of: decode.int))\n"
" Ok([1, 2, 3])\n"
" ```\n"
"\n"
" ```gleam\n"
" > parse(\"[\", decode.list(of: decode.int))\n"
" Error(UnexpectedEndOfInput)\n"
" ```\n"
"\n"
" ```gleam\n"
" > parse(\"1\", decode.string)\n"
" Error(UnableToDecode([decode.DecodeError(\"String\", \"Int\", [])]))\n"
" ```\n"
).
-spec parse(binary(), gleam@dynamic@decode:decoder(DNE)) -> {ok, DNE} |
{error, decode_error()}.
parse(Json, Decoder) ->
do_parse(Json, Decoder).
-file("src/gleam/json.gleam", 117).
?DOC(
" Convert a JSON value into a string.\n"
"\n"
" Where possible prefer the `to_string_tree` function as it is faster than\n"
" this function, and BEAM VM IO is optimised for sending `StringTree` data.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string(array([1, 2, 3], of: int))\n"
" \"[1,2,3]\"\n"
" ```\n"
).
-spec to_string(json()) -> binary().
to_string(Json) ->
gleam_json_ffi:json_to_string(Json).
-file("src/gleam/json.gleam", 140).
?DOC(
" Convert a JSON value into a string tree.\n"
"\n"
" Where possible prefer this function to the `to_string` function as it is\n"
" slower than this function, and BEAM VM IO is optimised for sending\n"
" `StringTree` data.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string_tree(array([1, 2, 3], of: int))\n"
" string_tree.from_string(\"[1,2,3]\")\n"
" ```\n"
).
-spec to_string_tree(json()) -> gleam@string_tree:string_tree().
to_string_tree(Json) ->
gleam_json_ffi:json_to_iodata(Json).
-file("src/gleam/json.gleam", 151).
?DOC(
" Encode a string into JSON, using normal JSON escaping.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string(string(\"Hello!\"))\n"
" \"\\\"Hello!\\\"\"\n"
" ```\n"
).
-spec string(binary()) -> json().
string(Input) ->
gleam_json_ffi:string(Input).
-file("src/gleam/json.gleam", 168).
?DOC(
" Encode a bool into JSON.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string(bool(False))\n"
" \"false\"\n"
" ```\n"
).
-spec bool(boolean()) -> json().
bool(Input) ->
gleam_json_ffi:bool(Input).
-file("src/gleam/json.gleam", 185).
?DOC(
" Encode an int into JSON.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string(int(50))\n"
" \"50\"\n"
" ```\n"
).
-spec int(integer()) -> json().
int(Input) ->
gleam_json_ffi:int(Input).
-file("src/gleam/json.gleam", 202).
?DOC(
" Encode a float into JSON.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string(float(4.7))\n"
" \"4.7\"\n"
" ```\n"
).
-spec float(float()) -> json().
float(Input) ->
gleam_json_ffi:float(Input).
-file("src/gleam/json.gleam", 219).
?DOC(
" The JSON value null.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string(null())\n"
" \"null\"\n"
" ```\n"
).
-spec null() -> json().
null() ->
gleam_json_ffi:null().
-file("src/gleam/json.gleam", 241).
?DOC(
" Encode an optional value into JSON, using null if it is the `None` variant.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string(nullable(Some(50), of: int))\n"
" \"50\"\n"
" ```\n"
"\n"
" ```gleam\n"
" > to_string(nullable(None, of: int))\n"
" \"null\"\n"
" ```\n"
).
-spec nullable(gleam@option:option(DNU), fun((DNU) -> json())) -> json().
nullable(Input, Inner_type) ->
case Input of
{some, Value} ->
Inner_type(Value);
none ->
null()
end.
-file("src/gleam/json.gleam", 260).
?DOC(
" Encode a list of key-value pairs into a JSON object.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string(object([\n"
" #(\"game\", string(\"Pac-Man\")),\n"
" #(\"score\", int(3333360)),\n"
" ]))\n"
" \"{\\\"game\\\":\\\"Pac-Mac\\\",\\\"score\\\":3333360}\"\n"
" ```\n"
).
-spec object(list({binary(), json()})) -> json().
object(Entries) ->
gleam_json_ffi:object(Entries).
-file("src/gleam/json.gleam", 292).
?DOC(
" Encode a list of JSON values into a JSON array.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string(preprocessed_array([int(1), float(2.0), string(\"3\")]))\n"
" \"[1, 2.0, \\\"3\\\"]\"\n"
" ```\n"
).
-spec preprocessed_array(list(json())) -> json().
preprocessed_array(From) ->
gleam_json_ffi:array(From).
-file("src/gleam/json.gleam", 277).
?DOC(
" Encode a list into a JSON array.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string(array([1, 2, 3], of: int))\n"
" \"[1, 2, 3]\"\n"
" ```\n"
).
-spec array(list(DNY), fun((DNY) -> json())) -> json().
array(Entries, Inner_type) ->
_pipe = Entries,
_pipe@1 = gleam@list:map(_pipe, Inner_type),
preprocessed_array(_pipe@1).
-file("src/gleam/json.gleam", 310).
?DOC(
" Encode a Dict into a JSON object using the supplied functions to encode\n"
" the keys and the values respectively.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" > to_string(dict(dict.from_list([ #(3, 3.0), #(4, 4.0)]), int.to_string, float)\n"
" \"{\\\"3\\\": 3.0, \\\"4\\\": 4.0}\"\n"
" ```\n"
).
-spec dict(
gleam@dict:dict(DOC, DOD),
fun((DOC) -> binary()),
fun((DOD) -> json())
) -> json().
dict(Dict, Keys, Values) ->
object(
gleam@dict:fold(
Dict,
[],
fun(Acc, K, V) -> [{Keys(K), Values(V)} | Acc] end
)
).
@@ -1,66 +0,0 @@
-module(gleam_json_ffi).
-export([
decode/1, json_to_iodata/1, json_to_string/1, int/1, float/1, string/1,
bool/1, null/0, array/1, object/1
]).
-if(?OTP_RELEASE < 27).
-define(bad_version,
error({erlang_otp_27_required, << "Insufficient Erlang/OTP version.
`gleam_json` uses the Erlang `json` module introduced in Erlang/OTP 27.
You are using Erlang/OTP "/utf8, (integer_to_binary(?OTP_RELEASE))/binary, "
Please upgrade your Erlang install or downgrade to `gleam_json` v1.0.1.
"/utf8>>})).
decode(_) -> ?bad_version.
json_to_iodata(_) -> ?bad_version.
json_to_string(_) -> ?bad_version.
int(_) -> ?bad_version.
float(_) -> ?bad_version.
string(_) -> ?bad_version.
bool(_) -> ?bad_version.
array(_) -> ?bad_version.
object(_) -> ?bad_version.
null() -> ?bad_version.
-else.
decode(Json) ->
try
{ok, json:decode(Json)}
catch
error:unexpected_end -> {error, unexpected_end_of_input};
error:{invalid_byte, Byte} -> {error, {unexpected_byte, hex(Byte)}};
error:{unexpected_sequence, Byte} -> {error, {unexpected_sequence, Byte}}
end.
hex(I) ->
H = list_to_binary(integer_to_list(I, 16)),
<<"0x"/utf8, H/binary>>.
json_to_iodata(Json) ->
Json.
json_to_string(Json) when is_binary(Json) ->
Json;
json_to_string(Json) when is_list(Json) ->
list_to_binary(Json).
null() -> <<"null">>.
bool(true) -> <<"true">>;
bool(false) -> <<"false">>.
int(X) -> json:encode_integer(X).
float(X) -> json:encode_float(X).
string(X) -> json:encode_binary(X).
array([]) -> <<"[]">>;
array([First | Rest]) -> [$[, First | array_loop(Rest)].
array_loop([]) -> "]";
array_loop([Elem | Rest]) -> [$,, Elem | array_loop(Rest)].
object(List) -> encode_object([[$,, string(Key), $: | Value] || {Key, Value} <- List]).
encode_object([]) -> <<"{}">>;
encode_object([[_Comma | Entry] | Rest]) -> ["{", Entry, Rest, "}"].
-endif.
-201
View File
@@ -1,201 +0,0 @@
import {
Result$Ok,
Result$Error,
List$isNonEmpty,
List$NonEmpty$first,
List$NonEmpty$rest,
} from "./gleam.mjs";
import {
DecodeError$UnexpectedByte,
DecodeError$UnexpectedEndOfInput,
} from "./gleam/json.mjs";
export function json_to_string(json) {
return JSON.stringify(json);
}
export function object(entries) {
return Object.fromEntries(entries);
}
export function identity(x) {
return x;
}
export function array(list) {
const array = [];
while (List$isNonEmpty(list)) {
array.push(List$NonEmpty$first(list));
list = List$NonEmpty$rest(list);
}
return array;
}
export function do_null() {
return null;
}
export function decode(string) {
try {
const result = JSON.parse(string);
return Result$Ok(result);
} catch (err) {
return Result$Error(getJsonDecodeError(err, string));
}
}
export function getJsonDecodeError(stdErr, json) {
if (isUnexpectedEndOfInput(stdErr)) return DecodeError$UnexpectedEndOfInput();
return toUnexpectedByteError(stdErr, json);
}
/**
* Matches unexpected end of input messages in:
* - Chromium (edge, chrome, node)
* - Spidermonkey (firefox)
* - JavascriptCore (safari)
*
* Note that Spidermonkey and JavascriptCore will both incorrectly report some
* UnexpectedByte errors as UnexpectedEndOfInput errors. For example:
*
* @example
* // in JavascriptCore
* JSON.parse('{"a"]: "b"})
* // => JSON Parse error: Expected ':' before value
*
* JSON.parse('{"a"')
* // => JSON Parse error: Expected ':' before value
*
* // in Chromium (correct)
* JSON.parse('{"a"]: "b"})
* // => Unexpected token ] in JSON at position 4
*
* JSON.parse('{"a"')
* // => Unexpected end of JSON input
*/
function isUnexpectedEndOfInput(err) {
const unexpectedEndOfInputRegex =
/((unexpected (end|eof))|(end of data)|(unterminated string)|(json( parse error|\.parse)\: expected '(\:|\}|\])'))/i;
return unexpectedEndOfInputRegex.test(err.message);
}
/**
* Converts a SyntaxError to an UnexpectedByte error based on the JS runtime.
*
* For Chromium, the unexpected byte and position are reported by the runtime.
*
* For JavascriptCore, only the unexpected byte is reported by the runtime, so
* there is no way to know which position that character is in unless we then
* parse the string again ourselves. So instead, the position is reported as 0.
*
* For Spidermonkey, the position is reported by the runtime as a line and column number
* and the unexpected byte is found using those coordinates.
*/
function toUnexpectedByteError(err, json) {
let converters = [
v8UnexpectedByteError,
oldV8UnexpectedByteError,
jsCoreUnexpectedByteError,
spidermonkeyUnexpectedByteError,
];
for (let converter of converters) {
let result = converter(err, json);
if (result) return result;
}
return DecodeError$UnexpectedByte("");
}
/**
* Matches unexpected byte messages in:
* - V8 (edge, chrome, node)
*
* Matches the character but not the position as this is no longer reported by
* V8. Boo!
*/
function v8UnexpectedByteError(err) {
const regex = /unexpected token '(.)', ".+" is not valid JSON/i;
const match = regex.exec(err.message);
if (!match) return null;
const byte = toHex(match[1]);
return DecodeError$UnexpectedByte(byte);
}
/**
* Matches unexpected byte messages in:
* - V8 (edge, chrome, node)
*
* No longer works in current versions of V8.
*
* Matches the character and its position.
*/
function oldV8UnexpectedByteError(err) {
const regex = /unexpected token (.) in JSON at position (\d+)/i;
const match = regex.exec(err.message);
if (!match) return null;
const byte = toHex(match[1]);
return DecodeError$UnexpectedByte(byte);
}
/**
* Matches unexpected byte messages in:
* - Spidermonkey (firefox)
*
* Matches the position in a 2d grid only and not the character.
*/
function spidermonkeyUnexpectedByteError(err, json) {
const regex =
/(unexpected character|expected .*) at line (\d+) column (\d+)/i;
const match = regex.exec(err.message);
if (!match) return null;
const line = Number(match[2]);
const column = Number(match[3]);
const position = getPositionFromMultiline(line, column, json);
const byte = toHex(json[position]);
return DecodeError$UnexpectedByte(byte);
}
/**
* Matches unexpected byte messages in:
* - JavascriptCore (safari)
*
* JavascriptCore only reports what the character is and not its position.
*/
function jsCoreUnexpectedByteError(err) {
const regex = /unexpected (identifier|token) "(.)"/i;
const match = regex.exec(err.message);
if (!match) return null;
const byte = toHex(match[2]);
return DecodeError$UnexpectedByte(byte);
}
function toHex(char) {
return "0x" + char.charCodeAt(0).toString(16).toUpperCase();
}
/**
* Gets the position of a character in a flattened (i.e. single line) string
* from a line and column number. Note that the position is 0-indexed and
* the line and column numbers are 1-indexed.
*
* @param {number} line
* @param {number} column
* @param {string} string
*/
function getPositionFromMultiline(line, column, string) {
if (line === 1) return column - 1;
let currentLn = 1;
let position = 0;
string.split("").find((char, idx) => {
if (char === "\n") currentLn += 1;
if (currentLn === line) {
position = idx + column;
return true;
}
return false;
});
return position;
}
-710
View File
@@ -1,710 +0,0 @@
/**
* This file uses jsdoc to annotate types.
* These types can be checked using the typescript compiler with "checkjs" option.
*/
import { isEqual, Result$Error, Result$Ok } from "./gleam.mjs";
// -- HASH --------------------------------------------------------------------
const referenceMap = /* @__PURE__ */ new WeakMap();
const tempDataView = /* @__PURE__ */ new DataView(
/* @__PURE__ */ new ArrayBuffer(8),
);
let referenceUID = 0;
/**
* hash the object by reference using a weak map and incrementing uid
* @param {any} o
* @returns {number}
*/
function hashByReference(o) {
const known = referenceMap.get(o);
if (known !== undefined) {
return known;
}
const hash = referenceUID++;
if (referenceUID === 0x7fffffff) {
referenceUID = 0;
}
referenceMap.set(o, hash);
return hash;
}
/**
* merge two hashes in an order sensitive way
* @param {number} a
* @param {number} b
* @returns {number}
*/
function hashMerge(a, b) {
return (a ^ (b + 0x9e3779b9 + (a << 6) + (a >> 2))) | 0;
}
/**
* standard string hash popularised by Java
* @param {string} s
* @returns {number}
*/
function hashString(s) {
let hash = 0;
const len = s.length;
for (let i = 0; i < len; i++) {
hash = (Math.imul(31, hash) + s.charCodeAt(i)) | 0;
}
return hash;
}
/**
* hash a number by converting to two integers and do some jumbling
* @param {number} n
* @returns {number}
*/
function hashNumber(n) {
tempDataView.setFloat64(0, n);
const i = tempDataView.getInt32(0);
const j = tempDataView.getInt32(4);
return Math.imul(0x45d9f3b, (i >> 16) ^ i) ^ j;
}
/**
* hash a BigInt by converting it to a string and hashing that
* @param {BigInt} n
* @returns {number}
*/
function hashBigInt(n) {
return hashString(n.toString());
}
/**
* hash any js object
* @param {any} o
* @returns {number}
*/
function hashObject(o) {
const proto = Object.getPrototypeOf(o);
if (proto !== null && typeof proto.hashCode === "function") {
try {
const code = o.hashCode(o);
if (typeof code === "number") {
return code;
}
} catch {}
}
if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) {
return hashByReference(o);
}
if (o instanceof Date) {
return hashNumber(o.getTime());
}
let h = 0;
if (o instanceof ArrayBuffer) {
o = new Uint8Array(o);
}
if (Array.isArray(o) || o instanceof Uint8Array) {
for (let i = 0; i < o.length; i++) {
h = (Math.imul(31, h) + getHash(o[i])) | 0;
}
} else if (o instanceof Set) {
o.forEach((v) => {
h = (h + getHash(v)) | 0;
});
} else if (o instanceof Map) {
o.forEach((v, k) => {
h = (h + hashMerge(getHash(v), getHash(k))) | 0;
});
} else {
const keys = Object.keys(o);
for (let i = 0; i < keys.length; i++) {
const k = keys[i];
const v = o[k];
h = (h + hashMerge(getHash(v), hashString(k))) | 0;
}
}
return h;
}
/**
* hash any js value
* @param {any} u
* @returns {number}
*/
export function getHash(u) {
if (u === null) return 0x42108422;
if (u === undefined) return 0x42108423;
if (u === true) return 0x42108421;
if (u === false) return 0x42108420;
switch (typeof u) {
case "number":
return hashNumber(u);
case "string":
return hashString(u);
case "bigint":
return hashBigInt(u);
case "object":
return hashObject(u);
case "symbol":
return hashByReference(u);
case "function":
return hashByReference(u);
default:
return 0; // should be unreachable
}
}
// -- DICT --------------------------------------------------------------------
/**
* An implementation of the CHAMP data structure, an optimised HAMT.
*
* See: M. J. Steindorfer, J.J. Vinju (2015). Optimizing Hash-Array Mapped Tries for
Fast and Lean Immutable JVM Collections. Available: https://michael.steindorfer.name/publications/oopsla15.pdf
*/
export default class Dict {
constructor(size, root) {
this.size = size;
this.root = root;
}
}
/// The power-of-2 branching factor for the dict. For example, a value of `5` indicates a 32-ary tree.
const bits = 5;
const mask = (1 << bits) - 1;
/// This symbol is used internally to avoid constructing results.
const noElementMarker = Symbol();
/// This symbol is used to store the "generation" on a node.
/// Using a symbol makes the property not enumerable, which means the generation
/// will be ignored during equality checks.
const generationKey = Symbol();
// Some commonly used constants throughout the code.
const emptyNode = /* @__PURE__ */ newNode(0);
const emptyDict = /* @__PURE__ */ new Dict(0, emptyNode);
const errorNil = /* @__PURE__ */ Result$Error(undefined);
function makeNode(generation, datamap, nodemap, data) {
// The order of fields is important, as they define the order `isEqual` will
// compare our fields. Putting the bitmaps first means that equality can
// early-out if the bitmaps are not equal.
return {
// A node is a high-arity (32 in practice) hybrid tree node.
// Hybrid means that it stores data directly as well as pointers to child nodes.
//
// Each node contains 2 bitmaps:
// - The datamap has a bit set if that slot in the node contains direct data
// - The nodemap has a bit set if that slot in the node contains another node.
//
// Both are exclusive to on another, so datamap & nodemap == 0.
//
// Every key/hash value directly correlates to a specific bit by using a trie
// suffix (least significant bits first) encoding.
// For example, if the last 5 bits of the hash are 1101, the bit to check for
// that value is the 13th bit.
datamap,
nodemap,
// The slots itself are stored in a single contiguous array that contains
// both direct k/v-pairs and child nodes.
//
// The direct children come first, followed by the child nodes in _reverse order_:
//
// 7654321
// datamap: 1000100
// nodemap: 10011
// data: [key3, value3, key7, value7, child5, child2, child1]
// -------------------------> <---------------------
// datamap nodemap
//
// Every `1` bit in the datamap corresponds to a pair of [key, value] entries,
// and every `1` bit in the nodemap corresponds to a child node entry.
//
// Children are stored in reverse order to avoid having to store or calculate an
// "offset" value to skip over the direct children.
data,
// The generation is used to track which nodes need to be copied during transient updates.
// Using a symbol here makes `isEqual` ignore this field.
[generationKey]: generation,
};
}
function newNode(generation) {
return makeNode(generation, 0, 0, []);
}
/**
* Copies a node and its data array if it's from another generation, making it safe
* to mutate the node.
*/
function copyNode(node, generation) {
if (node[generationKey] === generation) {
return node;
}
const newData = node.data.slice(0);
return makeNode(generation, node.datamap, node.nodemap, newData);
}
/**
* Copies a node if needed and sets a new value.
*/
function copyAndSet(node, generation, idx, val) {
if (node.data[idx] === val) {
return node;
}
// Using copyNode is faster than a specialised implementation.
node = copyNode(node, generation);
node.data[idx] = val;
return node;
}
/**
* Copies a node if needed, and then inserts a new key-value pair.
*/
function copyAndInsertPair(node, generation, bit, idx, key, val) {
const data = node.data;
const length = data.length;
// the fastest way to insert a pair is to always copy.
const newData = new Array(length + 2);
let readIndex = 0;
let writeIndex = 0;
while (readIndex < idx) newData[writeIndex++] = data[readIndex++];
newData[writeIndex++] = key;
newData[writeIndex++] = val;
while (readIndex < length) newData[writeIndex++] = data[readIndex++];
return makeNode(generation, node.datamap | bit, node.nodemap, newData);
}
function copyAndRemovePair(node, generation, bit, idx) {
node = copyNode(node, generation);
const data = node.data;
const length = data.length;
for (let w = idx, r = idx + 2; r < length; ++r, ++w) {
data[w] = data[r];
}
data.pop();
data.pop();
node.datamap ^= bit;
return node;
}
export function make() {
return emptyDict;
}
export function from(iterable) {
let transient = toTransient(emptyDict);
for (const [key, value] of iterable) {
transient = destructiveTransientInsert(key, value, transient);
}
return fromTransient(transient);
}
export function size(dict) {
return dict.size;
}
export function get(dict, key) {
const result = lookup(dict.root, key, getHash(key));
return result !== noElementMarker ? Result$Ok(result) : errorNil;
}
export function has(dict, key) {
return lookup(dict.root, key, getHash(key)) !== noElementMarker;
}
function lookup(node, key, hash) {
for (let shift = 0; shift < 32; shift += bits) {
const data = node.data;
const bit = hashbit(hash, shift);
if (node.nodemap & bit) {
// we found our hash inside the nodemap, so we can continue our search there.
node = data[data.length - 1 - index(node.nodemap, bit)];
} else if (node.datamap & bit) {
// we store this hash directly!
//
// this also means that there are no other values with the same
// hash prefix in this dict.
//
// We still need to check if the key matches, but if it does we know for
// sure that this is the correct value, and if it doesn't that we don't
// contain the value in question.
const dataidx = Math.imul(index(node.datamap, bit), 2);
return isEqual(key, data[dataidx]) ? data[dataidx + 1] : noElementMarker;
} else {
// if the hash bit is not set in neither bitmaps, we immediately know that
// this key cannot be inside this dict.
return noElementMarker;
}
}
// our shift has exceeded 32 bits. Everything that follows is
// implicitely an overflow node and only contains direct children.
const overflow = node.data;
for (let i = 0; i < overflow.length; i += 2) {
if (isEqual(key, overflow[i])) {
return overflow[i + 1];
}
}
return noElementMarker;
}
/**
* We use "transient" values to allow for safer internal mutations of the data
* structure. This is an optimisation only. No mutable API is exposed to the user.
*
* Transients are to be treated as having a linear (single-use, think rust) type.
* A transient value becomes invalid as soon as it's passed to one of the functions.
*
* Internally, we track a "generation" value on each node. If the generation
* doesn't match the one for the current transient, we have to copy - the node
* could still be referenced by another dict instance!
* After that, no other references than the transient one exists, so it's safe
* to mutate in place.
*/
export function toTransient(dict) {
return {
generation: nextGeneration(dict),
root: dict.root,
size: dict.size,
dict: dict,
};
}
/**
* Consume a transient, producing a normal Dict again.
*/
export function fromTransient(transient) {
if (transient.root === transient.dict.root) {
return transient.dict;
}
return new Dict(transient.size, transient.root);
}
/**
* Find and allocate the next generation id.
*
* @template K,V
* @param {Dict<K,V>} dict
* @returns {number}
*/
function nextGeneration(dict) {
const root = dict.root;
if (root[generationKey] < Number.MAX_SAFE_INTEGER) {
return root[generationKey] + 1;
}
// we have reached MAX_SAFE_INTEGER generations -
// at this point, we have to walk the dictionary once to reset the counter
// on every node. This is safe since it's part of the contract for transient
// that only one of them exists at any given time.
//
const queue = [root];
while (queue.length) {
// order doesn't matter, so we can use push/pop for faster array usage.
const node = queue.pop();
// reset the generation to 0
node[generationKey] = 0;
// queue all other referenced nodes
// We need to query the length from the nodemap, as we don't know if this
// is an overflow node or not! if it is, it will never have datamap set!
const nodeStart = data.length - popcount(node.nodemap);
for (let i = nodeStart; i < node.data.length; ++i) {
queue.push(node.data[i]);
}
}
return 1;
}
/// Insert is the second-most performance-sensitive operation.
/// We use a global "transient" value here to avoid doing a memory allocation.
const globalTransient = /* @__PURE__ */ toTransient(emptyDict);
export function insert(dict, key, value) {
globalTransient.generation = nextGeneration(dict);
globalTransient.size = dict.size;
const hash = getHash(key);
const root = insertIntoNode(globalTransient, dict.root, key, value, hash, 0);
if (root === dict.root) {
return dict;
}
return new Dict(globalTransient.size, root);
}
/**
* Consume a transient, writing a new key/value pair into the dictionary it
* represents. If the key already exists, it will be overwritten.
*
* Returns a new transient.
*/
export function destructiveTransientInsert(key, value, transient) {
const hash = getHash(key);
transient.root = insertIntoNode(transient, transient.root, key, value, hash, 0);
return transient;
}
/**
* Consume a transient, writing a new key/value pair if the key doesn't exist or updating
* the existing value with a function if it does.
*
* Returns a new transient.
*/
export function destructiveTransientUpdateWith(key, fun, value, transient) {
const hash = getHash(key);
const existing = lookup(transient.root, key, hash);
if (existing !== noElementMarker) {
value = fun(existing);
}
transient.root = insertIntoNode(transient, transient.root, key, value, hash, 0);
return transient;
}
function insertIntoNode(transient, node, key, value, hash, shift) {
const data = node.data;
const generation = transient.generation;
// 1. Overflow Node
// overflow nodes only contain key/value-pairs. we walk the data linearly trying to find a match.
if (shift > 32) {
for (let i = 0; i < data.length; i += 2) {
if (isEqual(key, data[i])) {
return copyAndSet(node, generation, i + 1, value);
}
}
transient.size += 1;
return copyAndInsertPair(node, generation, 0, data.length, key, value);
}
const bit = hashbit(hash, shift);
// 2. Child Node
// We have to check first if there is already a child node we have to traverse to.
if (node.nodemap & bit) {
const nodeidx = data.length - 1 - index(node.nodemap, bit);
let child = data[nodeidx];
child = insertIntoNode(transient, child, key, value, hash, shift + bits);
return copyAndSet(node, generation, nodeidx, child);
}
// 3. New Data Node
// No child node and no data node exists yet, so we can potentially just insert a new value.
const dataidx = Math.imul(index(node.datamap, bit), 2);
if ((node.datamap & bit) === 0) {
transient.size += 1;
return copyAndInsertPair(node, generation, bit, dataidx, key, value);
}
// 4. Existing Data Node
// We have a match that we can update, or remove.
if (isEqual(key, data[dataidx])) {
return copyAndSet(node, generation, dataidx + 1, value);
}
// 5. Collision
// There is no child node, but a data node with the same hash, but with a different key.
// To resolve this, we push both nodes down one level.
const childShift = shift + bits;
let child = emptyNode;
child = insertIntoNode(transient, child, key, value, hash, childShift);
const key2 = data[dataidx];
const value2 = data[dataidx + 1];
const hash2 = getHash(key2);
child = insertIntoNode(transient, child, key2, value2, hash2, childShift);
// we inserted 2 elements, but implicitely deleted the one we pushed down from the datamap.
transient.size -= 1;
// remove the old data pair, and insert the new child node.
const length = data.length;
const nodeidx = length - 1 - index(node.nodemap, bit);
// writing these loops in javascript instead of a combination of splices
// turns out to be faster. Copying always turned out to be faster.
const newData = new Array(length - 1);
let readIndex = 0;
let writeIndex = 0;
// [0..dataidx, skip 2 elements, ..nodeidx, newChild, ..rest]
while (readIndex < dataidx) newData[writeIndex++] = data[readIndex++];
readIndex += 2;
while (readIndex <= nodeidx) newData[writeIndex++] = data[readIndex++];
newData[writeIndex++] = child;
while (readIndex < length) newData[writeIndex++] = data[readIndex++];
return makeNode(generation, node.datamap ^ bit, node.nodemap | bit, newData);
}
/**
* Consume a transient, removing a key if it exists.
* Returns a new transient.
*/
export function destructiveTransientDelete(key, transient) {
const hash = getHash(key);
transient.root = deleteFromNode(transient, transient.root, key, hash, 0);
return transient;
}
function deleteFromNode(transient, node, key, hash, shift) {
const data = node.data;
const generation = transient.generation;
// 1. Overflow Node
// overflow nodes only contain key/value-pairs. we walk the data linearly trying to find a match.
if (shift > 32) {
for (let i = 0; i < data.length; i += 2) {
if (isEqual(key, data[i])) {
transient.size -= 1;
return copyAndRemovePair(node, generation, 0, i);
}
}
return node;
}
const bit = hashbit(hash, shift);
const dataidx = Math.imul(index(node.datamap, bit), 2);
// 2. Child Node
// We have to check first if there is already a child node we have to traverse to.
if ((node.nodemap & bit) !== 0) {
const nodeidx = data.length - 1 - index(node.nodemap, bit);
let child = data[nodeidx];
child = deleteFromNode(transient, child, key, hash, shift + bits);
// the node did change, so let's copy to incorporate that change.
if (child.nodemap !== 0 || child.data.length > 2) {
return copyAndSet(node, generation, nodeidx, child);
}
// this node only has a single data (k/v-pair) child.
// to restore the CHAMP invariant, we "pull" that pair up into ourselves.
// this ensures that every tree stays in its single optimal representation,
// and allows dicts to be structurally compared.
const length = data.length;
const newData = new Array(length + 1);
let readIndex = 0;
let writeIndex = 0;
while (readIndex < dataidx) newData[writeIndex++] = data[readIndex++];
newData[writeIndex++] = child.data[0];
newData[writeIndex++] = child.data[1];
while (readIndex < nodeidx) newData[writeIndex++] = data[readIndex++];
readIndex++;
while (readIndex < length) newData[writeIndex++] = data[readIndex++];
return makeNode(generation, node.datamap | bit, node.nodemap ^ bit, newData);
}
// 3. Data Node
// There is no data entry here, or it is a prefix for a different key
if ((node.datamap & bit) === 0 || !isEqual(key, data[dataidx])) {
return node;
}
// we found a data entry that we can delete.
transient.size -= 1;
return copyAndRemovePair(node, generation, bit, dataidx);
}
export function map(dict, fun) {
// map can never modify the structure, so we can walk the dictionary directly,
// but still move to a new generation to make sure we get a new copy of every node.
const generation = nextGeneration(dict);
const root = copyNode(dict.root, generation);
const queue = [root];
while (queue.length) {
// order doesn't matter, so we can use push/pop for faster array usage.
const node = queue.pop();
const data = node.data;
// every node contains popcount(datamap) direct entries
// We need to query the length from the nodemap, as we don't know if this
// is an overflow node or not! if it is, it will never have datamap set!
const edgesStart = data.length - popcount(node.nodemap);
for (let i = 0; i < edgesStart; i += 2) {
// we copied the node while queueing it, so direct mutation here is safe.
data[i + 1] = fun(data[i], data[i + 1]);
}
// the remaining entries are other nodes we can queue
for (let i = edgesStart; i < data.length; ++i) {
// copy the node first to make it safe to mutate
data[i] = copyNode(data[i], generation);
queue.push(data[i]);
}
}
return new Dict(dict.size, root);
}
export function fold(dict, state, fun) {
const queue = [dict.root];
while (queue.length) {
// order doesn't matter, so we can use push/pop for faster array usage.
const node = queue.pop();
const data = node.data;
// every node contains popcount(datamap) direct entries
// We need to query the length from the nodemap, as we don't know if this
// is an overflow node or not! if it is, it will never have datamap set!
const edgesStart = data.length - popcount(node.nodemap);
for (let i = 0; i < edgesStart; i += 2) {
state = fun(state, data[i], data[i + 1]);
}
// the remaining entries are child nodes we can queue.
for (let i = edgesStart; i < data.length; ++i) {
queue.push(data[i]);
}
}
return state;
}
/**
* How many `1` bits are set in a 32-bit integer.
*/
function popcount(n) {
n -= (n >>> 1) & 0x55555555;
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
return Math.imul((n + (n >>> 4)) & 0x0f0f0f0f, 0x01010101) >>> 24;
}
/**
* Given a population bitmap and a bit selected from that map, returns
* how many less significant 1 bits there are.
*
* For example, index(10101, 100) returns 1, since there is a single less
* significant `1` bit. This translates to the 0-based "index" of that bit.
*/
function index(bitmap, bit) {
return popcount(bitmap & (bit - 1));
}
/**
* Extracts a single slice of the hash, and returns a bitmask for the resulting value.
* For example, if the slice returns 5, this function returns 10000 = 1 << 5.
*/
function hashbit(hash, shift) {
return 1 << ((hash >>> shift) & mask);
}
-1
View File
@@ -1 +0,0 @@
export * from "../prelude.mjs";
@@ -1,286 +0,0 @@
import { Ok, toList, bitArraySlice, bitArraySliceToInt } from "../gleam.mjs";
import * as $int from "../gleam/int.mjs";
import * as $order from "../gleam/order.mjs";
import * as $string from "../gleam/string.mjs";
import {
bit_array_from_string as from_string,
bit_array_bit_size as bit_size,
bit_array_byte_size as byte_size,
bit_array_pad_to_bytes as pad_to_bytes,
bit_array_concat as concat,
bit_array_slice as slice,
bit_array_to_string as to_string,
base64_encode,
base64_decode as decode64,
base16_encode,
base16_decode,
bit_array_to_int_and_size,
bit_array_starts_with as starts_with,
} from "../gleam_stdlib.mjs";
export {
base16_decode,
base16_encode,
base64_encode,
bit_size,
byte_size,
concat,
from_string,
pad_to_bytes,
slice,
starts_with,
to_string,
};
/**
* Creates a new bit array by joining two bit arrays.
*
* ## Examples
*
* ```gleam
* assert append(to: from_string("butter"), suffix: from_string("fly"))
* == from_string("butterfly")
* ```
*/
export function append(first, second) {
return concat(toList([first, second]));
}
function is_utf8_loop(bits) {
let $ = to_string(bits);
if ($ instanceof Ok) {
return true;
} else {
return false;
}
}
/**
* Tests to see whether a bit array is valid UTF-8.
*/
export function is_utf8(bits) {
return is_utf8_loop(bits);
}
/**
* Decodes a base 64 encoded string into a `BitArray`.
*/
export function base64_decode(encoded) {
let _block;
let $ = byte_size(from_string(encoded)) % 4;
if ($ === 0) {
_block = encoded;
} else {
let n = $;
_block = $string.append(encoded, $string.repeat("=", 4 - n));
}
let padded = _block;
return decode64(padded);
}
/**
* Encodes a `BitArray` into a base 64 encoded string with URL and filename
* safe alphabet.
*
* If the bit array does not contain a whole number of bytes then it is padded
* with zero bits prior to being encoded.
*/
export function base64_url_encode(input, padding) {
let _pipe = input;
let _pipe$1 = base64_encode(_pipe, padding);
let _pipe$2 = $string.replace(_pipe$1, "+", "-");
return $string.replace(_pipe$2, "/", "_");
}
/**
* Decodes a base 64 encoded string with URL and filename safe alphabet into a
* `BitArray`.
*/
export function base64_url_decode(encoded) {
let _pipe = encoded;
let _pipe$1 = $string.replace(_pipe, "-", "+");
let _pipe$2 = $string.replace(_pipe$1, "_", "/");
return base64_decode(_pipe$2);
}
function inspect_loop(loop$input, loop$accumulator) {
while (true) {
let input = loop$input;
let accumulator = loop$accumulator;
if (input.bitSize === 0) {
return accumulator;
} else if (input.bitSize === 1) {
let x = bitArraySliceToInt(input, 0, 1, true, false);
return (accumulator + $int.to_string(x)) + ":size(1)";
} else if (input.bitSize === 2) {
let x = bitArraySliceToInt(input, 0, 2, true, false);
return (accumulator + $int.to_string(x)) + ":size(2)";
} else if (input.bitSize === 3) {
let x = bitArraySliceToInt(input, 0, 3, true, false);
return (accumulator + $int.to_string(x)) + ":size(3)";
} else if (input.bitSize === 4) {
let x = bitArraySliceToInt(input, 0, 4, true, false);
return (accumulator + $int.to_string(x)) + ":size(4)";
} else if (input.bitSize === 5) {
let x = bitArraySliceToInt(input, 0, 5, true, false);
return (accumulator + $int.to_string(x)) + ":size(5)";
} else if (input.bitSize === 6) {
let x = bitArraySliceToInt(input, 0, 6, true, false);
return (accumulator + $int.to_string(x)) + ":size(6)";
} else if (input.bitSize === 7) {
let x = bitArraySliceToInt(input, 0, 7, true, false);
return (accumulator + $int.to_string(x)) + ":size(7)";
} else if (input.bitSize >= 8) {
let x = input.byteAt(0);
let rest = bitArraySlice(input, 8);
let _block;
if (rest.bitSize === 0) {
_block = "";
} else {
_block = ", ";
}
let suffix = _block;
let accumulator$1 = (accumulator + $int.to_string(x)) + suffix;
loop$input = rest;
loop$accumulator = accumulator$1;
} else {
return accumulator;
}
}
}
/**
* Converts a bit array to a string containing the decimal value of each byte.
*
* Use this over `string.inspect` when you have a bit array you want printed
* in the array syntax even if it is valid UTF-8.
*
* ## Examples
*
* ```gleam
* assert inspect(<<0, 20, 0x20, 255>>) == "<<0, 20, 32, 255>>"
* ```
*
* ```gleam
* assert inspect(<<100, 5:3>>) == "<<100, 5:size(3)>>"
* ```
*/
export function inspect(input) {
return inspect_loop(input, "<<") + ">>";
}
/**
* Compare two bit arrays as sequences of bytes.
*
* ## Examples
*
* ```gleam
* assert compare(<<1>>, <<2>>) == Lt
* ```
*
* ```gleam
* assert compare(<<"AB":utf8>>, <<"AA":utf8>>) == Gt
* ```
*
* ```gleam
* assert compare(<<1, 2:size(2)>>, with: <<1, 2:size(2)>>) == Eq
* ```
*/
export function compare(loop$a, loop$b) {
while (true) {
let a = loop$a;
let b = loop$b;
if (a.bitSize >= 8) {
if (b.bitSize >= 8) {
let first_byte = a.byteAt(0);
let first_rest = bitArraySlice(a, 8);
let second_byte = b.byteAt(0);
let second_rest = bitArraySlice(b, 8);
let f = first_byte;
let s = second_byte;
if (f > s) {
return new $order.Gt();
} else {
let f = first_byte;
let s = second_byte;
if (f < s) {
return new $order.Lt();
} else {
loop$a = first_rest;
loop$b = second_rest;
}
}
} else if (b.bitSize === 0) {
return new $order.Gt();
} else {
let first = a;
let second = b;
let $ = bit_array_to_int_and_size(first);
let $1 = bit_array_to_int_and_size(second);
let a$1 = $[0];
let b$1 = $1[0];
if (a$1 > b$1) {
return new $order.Gt();
} else {
let a$1 = $[0];
let b$1 = $1[0];
if (a$1 < b$1) {
return new $order.Lt();
} else {
let size_a = $[1];
let size_b = $1[1];
if (size_a > size_b) {
return new $order.Gt();
} else {
let size_a = $[1];
let size_b = $1[1];
if (size_a < size_b) {
return new $order.Lt();
} else {
return new $order.Eq();
}
}
}
}
}
} else if (b.bitSize === 0) {
if (a.bitSize === 0) {
return new $order.Eq();
} else {
return new $order.Gt();
}
} else if (a.bitSize === 0) {
return new $order.Lt();
} else {
let first = a;
let second = b;
let $ = bit_array_to_int_and_size(first);
let $1 = bit_array_to_int_and_size(second);
let a$1 = $[0];
let b$1 = $1[0];
if (a$1 > b$1) {
return new $order.Gt();
} else {
let a$1 = $[0];
let b$1 = $1[0];
if (a$1 < b$1) {
return new $order.Lt();
} else {
let size_a = $[1];
let size_b = $1[1];
if (size_a > size_b) {
return new $order.Gt();
} else {
let size_a = $[1];
let size_b = $1[1];
if (size_a < size_b) {
return new $order.Lt();
} else {
return new $order.Eq();
}
}
}
}
}
}
}
-295
View File
@@ -1,295 +0,0 @@
/**
* Returns the and of two bools, but it evaluates both arguments.
*
* It's the function equivalent of the `&&` operator.
* This function is useful in higher order functions or pipes.
*
* ## Examples
*
* ```gleam
* assert and(True, True)
* ```
*
* ```gleam
* assert !and(False, True)
* ```
*
* ```gleam
* assert !and(False, True)
* ```
*
* ```gleam
* assert !and(False, False)
* ```
*/
export function and(a, b) {
return a && b;
}
/**
* Returns the or of two bools, but it evaluates both arguments.
*
* It's the function equivalent of the `||` operator.
* This function is useful in higher order functions or pipes.
*
* ## Examples
*
* ```gleam
* assert or(True, True)
* ```
*
* ```gleam
* assert or(False, True)
* ```
*
* ```gleam
* assert or(True, False)
* ```
*
* ```gleam
* assert !or(False, False)
* ```
*/
export function or(a, b) {
return a || b;
}
/**
* Returns the opposite bool value.
*
* This is the same as the `!` or `not` operators in some other languages.
*
* ## Examples
*
* ```gleam
* assert !negate(True)
* ```
*
* ```gleam
* assert negate(False)
* ```
*/
export function negate(bool) {
return !bool;
}
/**
* Returns the nor of two bools.
*
* ## Examples
*
* ```gleam
* assert nor(False, False)
* ```
*
* ```gleam
* assert !nor(False, True)
* ```
*
* ```gleam
* assert !nor(True, False)
* ```
*
* ```gleam
* assert !nor(True, True)
* ```
*/
export function nor(a, b) {
return !(a || b);
}
/**
* Returns the nand of two bools.
*
* ## Examples
*
* ```gleam
* assert nand(False, False)
* ```
*
* ```gleam
* assert nand(False, True)
* ```
*
* ```gleam
* assert nand(True, False)
* ```
*
* ```gleam
* assert !nand(True, True)
* ```
*/
export function nand(a, b) {
return !(a && b);
}
/**
* Returns the exclusive or of two bools.
*
* ## Examples
*
* ```gleam
* assert !exclusive_or(False, False)
* ```
*
* ```gleam
* assert exclusive_or(False, True)
* ```
*
* ```gleam
* assert exclusive_or(True, False)
* ```
*
* ```gleam
* assert !exclusive_or(True, True)
* ```
*/
export function exclusive_or(a, b) {
return a !== b;
}
/**
* Returns the exclusive nor of two bools.
*
* ## Examples
*
* ```gleam
* assert exclusive_nor(False, False)
* ```
*
* ```gleam
* assert !exclusive_nor(False, True)
* ```
*
* ```gleam
* assert !exclusive_nor(True, False)
* ```
*
* ```gleam
* assert exclusive_nor(True, True)
* ```
*/
export function exclusive_nor(a, b) {
return a === b;
}
/**
* Returns a string representation of the given bool.
*
* ## Examples
*
* ```gleam
* assert to_string(True) == "True"
* ```
*
* ```gleam
* assert to_string(False) == "False"
* ```
*/
export function to_string(bool) {
if (bool) {
return "True";
} else {
return "False";
}
}
/**
* Run a callback function if the given bool is `False`, otherwise return a
* default value.
*
* With a `use` expression this function can simulate the early-return pattern
* found in some other programming languages.
*
* In a procedural language:
*
* ```js
* if (predicate) return value;
* // ...
* ```
*
* In Gleam with a `use` expression:
*
* ```gleam
* use <- guard(when: predicate, return: value)
* // ...
* ```
*
* Like everything in Gleam `use` is an expression, so it short circuits the
* current block, not the entire function. As a result you can assign the value
* to a variable:
*
* ```gleam
* let x = {
* use <- guard(when: predicate, return: value)
* // ...
* }
* ```
*
* Note that unlike in procedural languages the `return` value is evaluated
* even when the predicate is `False`, so it is advisable not to perform
* expensive computation nor side-effects there.
*
*
* ## Examples
*
* ```gleam
* let name = ""
* use <- guard(when: name == "", return: "Welcome!")
* "Hello, " <> name
* // -> "Welcome!"
* ```
*
* ```gleam
* let name = "Kamaka"
* use <- guard(when: name == "", return: "Welcome!")
* "Hello, " <> name
* // -> "Hello, Kamaka"
* ```
*/
export function guard(requirement, consequence, alternative) {
if (requirement) {
return consequence;
} else {
return alternative();
}
}
/**
* Runs a callback function if the given bool is `True`, otherwise runs an
* alternative callback function.
*
* Useful when further computation should be delayed regardless of the given
* bool's value.
*
* See [`guard`](#guard) for more info.
*
* ## Examples
*
* ```gleam
* let name = "Kamaka"
* let inquiry = fn() { "How may we address you?" }
* use <- lazy_guard(when: name == "", return: inquiry)
* "Hello, " <> name
* // -> "Hello, Kamaka"
* ```
*
* ```gleam
* import gleam/int
*
* let name = ""
* let greeting = fn() { "Hello, " <> name }
* use <- lazy_guard(when: name == "", otherwise: greeting)
* let number = int.random(99)
* let name = "User " <> int.to_string(number)
* "Welcome, " <> name
* // -> "Welcome, User 54"
* ```
*/
export function lazy_guard(requirement, consequence, alternative) {
if (requirement) {
return consequence();
} else {
return alternative();
}
}
@@ -1,225 +0,0 @@
import {
toList,
Empty as $Empty,
prepend as listPrepend,
CustomType as $CustomType,
} from "../gleam.mjs";
import * as $bit_array from "../gleam/bit_array.mjs";
import * as $list from "../gleam/list.mjs";
import * as $string_tree from "../gleam/string_tree.mjs";
class Bytes extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
class Text extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
class Many extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
/**
* Joins a list of bytes trees into a single one.
*
* Runs in constant time.
*/
export function concat(trees) {
return new Many(trees);
}
/**
* Create an empty `BytesTree`. Useful as the start of a pipe chaining many
* trees together.
*/
export function new$() {
return concat(toList([]));
}
function wrap_list(bits) {
return new Bytes(bits);
}
/**
* Creates a new bytes tree from a bit array.
*
* Runs in constant time.
*/
export function from_bit_array(bits) {
let _pipe = bits;
let _pipe$1 = $bit_array.pad_to_bytes(_pipe);
return wrap_list(_pipe$1);
}
/**
* Appends a bytes tree onto the end of another.
*
* Runs in constant time.
*/
export function append_tree(first, second) {
if (second instanceof Bytes) {
return new Many(toList([first, second]));
} else if (second instanceof Text) {
return new Many(toList([first, second]));
} else {
let trees = second[0];
return new Many(listPrepend(first, trees));
}
}
/**
* Prepends a bit array to the start of a bytes tree.
*
* Runs in constant time.
*/
export function prepend(second, first) {
return append_tree(from_bit_array(first), second);
}
/**
* Appends a bit array to the end of a bytes tree.
*
* Runs in constant time.
*/
export function append(first, second) {
return append_tree(first, from_bit_array(second));
}
/**
* Prepends a bytes tree onto the start of another.
*
* Runs in constant time.
*/
export function prepend_tree(second, first) {
return append_tree(first, second);
}
/**
* Creates a new bytes tree from a string.
*
* Runs in constant time when running on Erlang.
* Runs in linear time otherwise.
*/
export function from_string(string) {
return new Text($string_tree.from_string(string));
}
/**
* Prepends a string onto the start of a bytes tree.
*
* Runs in constant time when running on Erlang.
* Runs in linear time with the length of the string otherwise.
*/
export function prepend_string(second, first) {
return append_tree(from_string(first), second);
}
/**
* Appends a string onto the end of a bytes tree.
*
* Runs in constant time when running on Erlang.
* Runs in linear time with the length of the string otherwise.
*/
export function append_string(first, second) {
return append_tree(first, from_string(second));
}
/**
* Joins a list of bit arrays into a single bytes tree.
*
* Runs in constant time.
*/
export function concat_bit_arrays(bits) {
let _pipe = bits;
let _pipe$1 = $list.map(_pipe, from_bit_array);
return concat(_pipe$1);
}
/**
* Creates a new bytes tree from a string tree.
*
* Runs in constant time when running on Erlang.
* Runs in linear time otherwise.
*/
export function from_string_tree(tree) {
return new Text(tree);
}
function to_list(loop$stack, loop$acc) {
while (true) {
let stack = loop$stack;
let acc = loop$acc;
if (stack instanceof $Empty) {
return acc;
} else {
let $ = stack.head;
if ($ instanceof $Empty) {
let remaining_stack = stack.tail;
loop$stack = remaining_stack;
loop$acc = acc;
} else {
let $1 = $.head;
if ($1 instanceof Bytes) {
let remaining_stack = stack.tail;
let rest = $.tail;
let bits = $1[0];
loop$stack = listPrepend(rest, remaining_stack);
loop$acc = listPrepend(bits, acc);
} else if ($1 instanceof Text) {
let remaining_stack = stack.tail;
let rest = $.tail;
let tree = $1[0];
let bits = $bit_array.from_string($string_tree.to_string(tree));
loop$stack = listPrepend(rest, remaining_stack);
loop$acc = listPrepend(bits, acc);
} else {
let remaining_stack = stack.tail;
let rest = $.tail;
let trees = $1[0];
loop$stack = listPrepend(trees, listPrepend(rest, remaining_stack));
loop$acc = acc;
}
}
}
}
}
/**
* Turns a bytes tree into a bit array.
*
* Runs in linear time.
*
* When running on Erlang this function is implemented natively by the
* virtual machine and is highly optimised.
*/
export function to_bit_array(tree) {
let _pipe = toList([toList([tree])]);
let _pipe$1 = to_list(_pipe, toList([]));
let _pipe$2 = $list.reverse(_pipe$1);
return $bit_array.concat(_pipe$2);
}
/**
* Returns the size of the bytes tree's content in bytes.
*
* Runs in linear time.
*/
export function byte_size(tree) {
let _pipe = toList([toList([tree])]);
let _pipe$1 = to_list(_pipe, toList([]));
return $list.fold(
_pipe$1,
0,
(acc, bits) => { return $bit_array.byte_size(bits) + acc; },
);
}
-452
View File
@@ -1,452 +0,0 @@
import {
toTransient as to_transient,
fromTransient as from_transient,
size,
fold,
make as new$,
destructiveTransientInsert as transient_insert,
has as has_key,
get,
insert,
map as map_values,
destructiveTransientUpdateWith as transient_update_with,
destructiveTransientDelete as transient_delete,
} from "../dict.mjs";
import { Ok, toList, Empty as $Empty, prepend as listPrepend } from "../gleam.mjs";
import * as $option from "../gleam/option.mjs";
export { fold, get, has_key, insert, map_values, new$, size };
/**
* Determines whether or not the dict is empty.
*
* ## Examples
*
* ```gleam
* assert new() |> is_empty
* ```
*
* ```gleam
* assert !{ new() |> insert("b", 1) |> is_empty }
* ```
*/
export function is_empty(dict) {
return size(dict) === 0;
}
/**
* Converts the dict to a list of 2-element tuples `#(key, value)`, one for
* each key-value pair in the dict.
*
* The tuples in the list have no specific order.
*
* ## Examples
*
* Calling `to_list` on an empty `dict` returns an empty list.
*
* ```gleam
* assert new() |> to_list == []
* ```
*
* The ordering of elements in the resulting list is an implementation detail
* that should not be relied upon.
*
* ```gleam
* assert new()
* |> insert("b", 1)
* |> insert("a", 0)
* |> insert("c", 2)
* |> to_list
* == [#("a", 0), #("b", 1), #("c", 2)]
* ```
*/
export function to_list(dict) {
return fold(
dict,
toList([]),
(acc, key, value) => { return listPrepend([key, value], acc); },
);
}
function from_list_loop(loop$transient, loop$list) {
while (true) {
let transient = loop$transient;
let list = loop$list;
if (list instanceof $Empty) {
return from_transient(transient);
} else {
let rest = list.tail;
let key = list.head[0];
let value = list.head[1];
loop$transient = transient_insert(key, value, transient);
loop$list = rest;
}
}
}
/**
* Converts a list of 2-element tuples `#(key, value)` to a dict.
*
* If two tuples have the same key the last one in the list will be the one
* that is present in the dict.
*/
export function from_list(list) {
return from_list_loop(to_transient(new$()), list);
}
/**
* Gets a list of all keys in a given dict.
*
* Dicts are not ordered so the keys are not returned in any specific order. Do
* not write code that relies on the order keys are returned by this function
* as it may change in later versions of Gleam or Erlang.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> keys == ["a", "b"]
* ```
*/
export function keys(dict) {
return fold(
dict,
toList([]),
(acc, key, _) => { return listPrepend(key, acc); },
);
}
/**
* Gets a list of all values in a given dict.
*
* Dicts are not ordered so the values are not returned in any specific order. Do
* not write code that relies on the order values are returned by this function
* as it may change in later versions of Gleam or Erlang.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> values == [0, 1]
* ```
*/
export function values(dict) {
return fold(
dict,
toList([]),
(acc, _, value) => { return listPrepend(value, acc); },
);
}
function do_filter(f, dict) {
let _pipe = to_transient(new$());
let _pipe$1 = fold(
dict,
_pipe,
(transient, key, value) => {
let $ = f(key, value);
if ($) {
return transient_insert(key, value, transient);
} else {
return transient;
}
},
);
return from_transient(_pipe$1);
}
/**
* Creates a new dict from a given dict, minus any entries that a given function
* returns `False` for.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)])
* |> filter(fn(key, value) { value != 0 })
* == from_list([#("b", 1)])
* ```
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)])
* |> filter(fn(key, value) { True })
* == from_list([#("a", 0), #("b", 1)])
* ```
*/
export function filter(dict, predicate) {
return do_filter(predicate, dict);
}
function do_take_loop(loop$dict, loop$desired_keys, loop$acc) {
while (true) {
let dict = loop$dict;
let desired_keys = loop$desired_keys;
let acc = loop$acc;
if (desired_keys instanceof $Empty) {
return from_transient(acc);
} else {
let key = desired_keys.head;
let rest = desired_keys.tail;
let $ = get(dict, key);
if ($ instanceof Ok) {
let value = $[0];
loop$dict = dict;
loop$desired_keys = rest;
loop$acc = transient_insert(key, value, acc);
} else {
loop$dict = dict;
loop$desired_keys = rest;
loop$acc = acc;
}
}
}
}
function do_take(desired_keys, dict) {
return do_take_loop(dict, desired_keys, to_transient(new$()));
}
/**
* Creates a new dict from a given dict, only including any entries for which the
* keys are in a given list.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)])
* |> take(["b"])
* == from_list([#("b", 1)])
* ```
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)])
* |> take(["a", "b", "c"])
* == from_list([#("a", 0), #("b", 1)])
* ```
*/
export function take(dict, desired_keys) {
return do_take(desired_keys, dict);
}
function do_combine(combine, left, right) {
let _block;
let $1 = size(left) >= size(right);
if ($1) {
_block = [left, right, combine];
} else {
_block = [right, left, (k, l, r) => { return combine(k, r, l); }];
}
let $ = _block;
let big = $[0];
let small = $[1];
let combine$1 = $[2];
let _pipe = to_transient(big);
let _pipe$1 = fold(
small,
_pipe,
(transient, key, value) => {
let update = (existing) => { return combine$1(key, existing, value); };
return transient_update_with(key, update, value, transient);
},
);
return from_transient(_pipe$1);
}
/**
* Creates a new dict from a pair of given dicts by combining their entries.
*
* If there are entries with the same keys in both dicts the given function is
* used to determine the new value to use in the resulting dict.
*
* ## Examples
*
* ```gleam
* let a = from_list([#("a", 0), #("b", 1)])
* let b = from_list([#("a", 2), #("c", 3)])
* assert combine(a, b, fn(one, other) { one + other })
* == from_list([#("a", 2), #("b", 1), #("c", 3)])
* ```
*/
export function combine(dict, other, fun) {
return do_combine((_, l, r) => { return fun(l, r); }, dict, other);
}
/**
* Creates a new dict from a pair of given dicts by combining their entries.
*
* If there are entries with the same keys in both dicts the entry from the
* second dict takes precedence.
*
* ## Examples
*
* ```gleam
* let a = from_list([#("a", 0), #("b", 1)])
* let b = from_list([#("b", 2), #("c", 3)])
* assert merge(a, b) == from_list([#("a", 0), #("b", 2), #("c", 3)])
* ```
*/
export function merge(dict, new_entries) {
return combine(dict, new_entries, (_, new_entry) => { return new_entry; });
}
/**
* Creates a new dict from a given dict with all the same entries except for the
* one with a given key, if it exists.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> delete("a")
* == from_list([#("b", 1)])
* ```
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> delete("c")
* == from_list([#("a", 0), #("b", 1)])
* ```
*/
export function delete$(dict, key) {
let _pipe = to_transient(dict);
let _pipe$1 = ((_capture) => { return transient_delete(key, _capture); })(
_pipe,
);
return from_transient(_pipe$1);
}
function drop_loop(loop$transient, loop$disallowed_keys) {
while (true) {
let transient = loop$transient;
let disallowed_keys = loop$disallowed_keys;
if (disallowed_keys instanceof $Empty) {
return from_transient(transient);
} else {
let key = disallowed_keys.head;
let rest = disallowed_keys.tail;
loop$transient = transient_delete(key, transient);
loop$disallowed_keys = rest;
}
}
}
function do_drop(disallowed_keys, dict) {
return drop_loop(to_transient(dict), disallowed_keys);
}
/**
* Creates a new dict from a given dict with all the same entries except any with
* keys found in a given list.
*
* ## Examples
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> drop(["a"])
* == from_list([#("b", 1)])
* ```
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> drop(["c"])
* == from_list([#("a", 0), #("b", 1)])
* ```
*
* ```gleam
* assert from_list([#("a", 0), #("b", 1)]) |> drop(["a", "b", "c"])
* == from_list([])
* ```
*/
export function drop(dict, disallowed_keys) {
return do_drop(disallowed_keys, dict);
}
/**
* Creates a new dict with one entry inserted or updated using a given function.
*
* If there was not an entry in the dict for the given key then the function
* gets `None` as its argument, otherwise it gets `Some(value)`.
*
* ## Examples
*
* ```gleam
* let dict = from_list([#("a", 0)])
* let increment = fn(x) {
* case x {
* Some(i) -> i + 1
* None -> 0
* }
* }
*
* assert upsert(dict, "a", increment) == from_list([#("a", 1)])
* ```
*
* ```gleam
* assert upsert(dict, "b", increment) == from_list([#("a", 0), #("b", 0)])
* ```
*/
export function upsert(dict, key, fun) {
let $ = get(dict, key);
if ($ instanceof Ok) {
let value = $[0];
return insert(dict, key, fun(new $option.Some(value)));
} else {
return insert(dict, key, fun(new $option.None()));
}
}
/**
* Calls a function for each key and value in a dict, discarding the return
* value.
*
* Useful for producing a side effect for every item of a dict.
*
* ```gleam
* import gleam/io
*
* let dict = from_list([#("a", "apple"), #("b", "banana"), #("c", "cherry")])
*
* assert
* each(dict, fn(k, v) {
* io.println(k <> " => " <> v)
* })
* == Nil
* // a => apple
* // b => banana
* // c => cherry
* ```
*
* The order of elements in the iteration is an implementation detail that
* should not be relied upon.
*/
export function each(dict, fun) {
return fold(
dict,
undefined,
(nil, k, v) => {
fun(k, v);
return nil;
},
);
}
function group_loop(loop$transient, loop$to_key, loop$list) {
while (true) {
let transient = loop$transient;
let to_key = loop$to_key;
let list = loop$list;
if (list instanceof $Empty) {
return from_transient(transient);
} else {
let value = list.head;
let rest = list.tail;
let key = to_key(value);
let update = (existing) => { return listPrepend(value, existing); };
let _pipe = transient;
let _pipe$1 = ((_capture) => {
return transient_update_with(key, update, toList([value]), _capture);
})(_pipe);
loop$transient = _pipe$1;
loop$to_key = to_key;
loop$list = rest;
}
}
}
export function group(key, list) {
return group_loop(to_transient(new$()), key, list);
}
@@ -1,35 +0,0 @@
import * as $dict from "../gleam/dict.mjs";
import {
classify_dynamic as classify,
identity as bool,
identity as string,
identity as float,
identity as int,
identity as bit_array,
identity as list,
list_to_array as array,
identity as cast,
} from "../gleam_stdlib.mjs";
export { array, bit_array, bool, classify, float, int, list, string };
/**
* Create a dynamic value made of an unordered series of keys and values, where
* the keys are unique.
*
* On Erlang this will be a map, on JavaScript this will be a Gleam dict
* object.
*/
export function properties(entries) {
return cast($dict.from_list(entries));
}
/**
* A dynamic value representing nothing.
*
* On Erlang this will be the atom `nil`, on JavaScript this will be
* `undefined`.
*/
export function nil() {
return cast(undefined);
}
@@ -1,963 +0,0 @@
import {
Ok,
Error,
toList,
Empty as $Empty,
prepend as listPrepend,
CustomType as $CustomType,
isEqual,
} from "../../gleam.mjs";
import * as $bit_array from "../../gleam/bit_array.mjs";
import * as $dict from "../../gleam/dict.mjs";
import * as $dynamic from "../../gleam/dynamic.mjs";
import * as $float from "../../gleam/float.mjs";
import * as $int from "../../gleam/int.mjs";
import * as $list from "../../gleam/list.mjs";
import * as $option from "../../gleam/option.mjs";
import { None, Some } from "../../gleam/option.mjs";
import {
float as dynamic_float,
int as dynamic_int,
bit_array as dynamic_bit_array,
string as dynamic_string,
identity as cast,
list as decode_list,
index as bare_index,
dict as decode_dict,
is_null,
} from "../../gleam_stdlib.mjs";
export class DecodeError extends $CustomType {
constructor(expected, found, path) {
super();
this.expected = expected;
this.found = found;
this.path = path;
}
}
export const DecodeError$DecodeError = (expected, found, path) =>
new DecodeError(expected, found, path);
export const DecodeError$isDecodeError = (value) =>
value instanceof DecodeError;
export const DecodeError$DecodeError$expected = (value) => value.expected;
export const DecodeError$DecodeError$0 = (value) => value.expected;
export const DecodeError$DecodeError$found = (value) => value.found;
export const DecodeError$DecodeError$1 = (value) => value.found;
export const DecodeError$DecodeError$path = (value) => value.path;
export const DecodeError$DecodeError$2 = (value) => value.path;
class Decoder extends $CustomType {
constructor(function$) {
super();
this.function = function$;
}
}
/**
* A decoder that decodes `Dynamic` values. This decoder never returns an error.
*
* ## Examples
*
* ```gleam
* let result = decode.run(dynamic.float(3.14), decode.dynamic)
* assert result == Ok(dynamic.float(3.14))
* ```
*/
export const dynamic = /* @__PURE__ */ new Decoder(decode_dynamic);
/**
* A decoder that decodes `Float` values.
*
* This will not coerse int values into float values, so on platforms with
* distinct runtime int and float types (Erlang, not JavaScript) it will fail
* for ints. One time this may happen is when decoding JSON data.
*
* If you want to decode both ints and floats you may want to use the `one_of`
* function.
*
* ## Examples
*
* ```gleam
* let result = decode.run(dynamic.float(3.14), decode.float)
* assert result == Ok(3.14)
* ```
*/
export const float = /* @__PURE__ */ new Decoder(decode_float);
/**
* A decoder that decodes `Int` values.
*
* This will not coerse float values into int values, so on platforms with
* distinct runtime int and float types (Erlang, not JavaScript) it will fail,
* even if the float is a whole number (e.g. 1.0).
*
* If you want to decode both ints and floats you may want to use the `one_of`
* function.
*
* ## Examples
*
* ```gleam
* let result = decode.run(dynamic.int(147), decode.int)
* assert result == Ok(147)
* ```
*/
export const int = /* @__PURE__ */ new Decoder(decode_int);
/**
* A decoder that decodes `BitArray` values. This decoder never returns an error.
*
* ## Examples
*
* ```gleam
* let result = decode.run(dynamic.bit_array(<<5, 7>>), decode.bit_array)
* assert result == Ok(<<5, 7>>)
* ```
*/
export const bit_array = /* @__PURE__ */ new Decoder(decode_bit_array);
/**
* A decoder that decodes `String` values.
*
* ## Examples
*
* ```gleam
* let result = decode.run(dynamic.string("Hello!"), decode.string)
* assert result == Ok("Hello!")
* ```
*/
export const string = /* @__PURE__ */ new Decoder(decode_string);
/**
* A decoder that decodes `Bool` values.
*
* ## Examples
*
* ```gleam
* let result = decode.run(dynamic.bool(True), decode.bool)
* assert result == Ok(True)
* ```
*/
export const bool = /* @__PURE__ */ new Decoder(decode_bool);
function decode_dynamic(data) {
return [data, toList([])];
}
/**
* Run a decoder on a `Dynamic` value, decoding the value if it is of the
* desired type, or returning errors.
*
* ## Examples
*
* ```gleam
* let decoder = {
* use name <- decode.field("name", decode.string)
* use email <- decode.field("email", decode.string)
* decode.success(SignUp(name: name, email: email))
* }
*
* decode.run(data, decoder)
* ```
*/
export function run(data, decoder) {
let $ = decoder.function(data);
let maybe_invalid_data = $[0];
let errors = $[1];
if (errors instanceof $Empty) {
return new Ok(maybe_invalid_data);
} else {
return new Error(errors);
}
}
function run_dynamic_function(data, name, f) {
let $ = f(data);
if ($ instanceof Ok) {
let data$1 = $[0];
return [data$1, toList([])];
} else {
let placeholder = $[0];
return [
placeholder,
toList([new DecodeError(name, $dynamic.classify(data), toList([]))]),
];
}
}
function decode_float(data) {
return run_dynamic_function(data, "Float", dynamic_float);
}
/**
* Apply a transformation function to any value decoded by the decoder.
*
* ## Examples
*
* ```gleam
* let decoder = decode.int |> decode.map(int.to_string)
* let result = decode.run(dynamic.int(1000), decoder)
* assert result == Ok("1000")
* ```
*/
export function map(decoder, transformer) {
return new Decoder(
(d) => {
let $ = decoder.function(d);
let data = $[0];
let errors = $[1];
return [transformer(data), errors];
},
);
}
function decode_int(data) {
return run_dynamic_function(data, "Int", dynamic_int);
}
function decode_bit_array(data) {
return run_dynamic_function(data, "BitArray", dynamic_bit_array);
}
function decode_string(data) {
return run_dynamic_function(data, "String", dynamic_string);
}
function run_decoders(loop$data, loop$failure, loop$decoders) {
while (true) {
let data = loop$data;
let failure = loop$failure;
let decoders = loop$decoders;
if (decoders instanceof $Empty) {
return failure;
} else {
let decoder = decoders.head;
let decoders$1 = decoders.tail;
let $ = decoder.function(data);
let layer = $;
let errors = $[1];
if (errors instanceof $Empty) {
return layer;
} else {
loop$data = data;
loop$failure = failure;
loop$decoders = decoders$1;
}
}
}
}
/**
* Create a new decoder from several other decoders. Each of the inner
* decoders is run in turn, and the value from the first to succeed is used.
*
* If no decoder succeeds then the errors from the first decoder are used.
* If you wish for different errors then you may wish to use the
* `collapse_errors` or `map_errors` functions.
*
* ## Examples
*
* ```gleam
* let decoder = decode.one_of(decode.string, or: [
* decode.int |> decode.map(int.to_string),
* decode.float |> decode.map(float.to_string),
* ])
* assert decode.run(dynamic.int(1000), decoder) == Ok("1000")
* ```
*/
export function one_of(first, alternatives) {
return new Decoder(
(dynamic_data) => {
let $ = first.function(dynamic_data);
let layer = $;
let errors = $[1];
if (errors instanceof $Empty) {
return layer;
} else {
return run_decoders(dynamic_data, layer, alternatives);
}
},
);
}
function path_segment_to_string(key) {
let decoder = one_of(
string,
toList([
(() => {
let _pipe = int;
return map(_pipe, $int.to_string);
})(),
(() => {
let _pipe = float;
return map(_pipe, $float.to_string);
})(),
]),
);
let $ = run(key, decoder);
if ($ instanceof Ok) {
let key$1 = $[0];
return key$1;
} else {
return ("<" + $dynamic.classify(key)) + ">";
}
}
function push_path(layer, path) {
let path$1 = $list.map(
path,
(key) => {
let _pipe = key;
let _pipe$1 = cast(_pipe);
return path_segment_to_string(_pipe$1);
},
);
let errors = $list.map(
layer[1],
(error) => {
return new DecodeError(
error.expected,
error.found,
$list.append(path$1, error.path),
);
},
);
return [layer[0], errors];
}
/**
* A decoder that decodes lists where all elements are decoded with a given
* decoder.
*
* ## Examples
*
* ```gleam
* let result =
* [1, 2, 3]
* |> list.map(dynamic.int)
* |> dynamic.list
* |> decode.run(decode.list(of: decode.int))
* assert result == Ok([1, 2, 3])
* ```
*/
export function list(inner) {
return new Decoder(
(data) => {
return decode_list(
data,
inner.function,
(p, k) => { return push_path(p, toList([k])); },
0,
toList([]),
);
},
);
}
function index(
loop$path,
loop$position,
loop$inner,
loop$data,
loop$handle_miss
) {
while (true) {
let path = loop$path;
let position = loop$position;
let inner = loop$inner;
let data = loop$data;
let handle_miss = loop$handle_miss;
if (path instanceof $Empty) {
let _pipe = data;
let _pipe$1 = inner(_pipe);
return push_path(_pipe$1, $list.reverse(position));
} else {
let key = path.head;
let path$1 = path.tail;
let $ = bare_index(data, key);
if ($ instanceof Ok) {
let $1 = $[0];
if ($1 instanceof Some) {
let data$1 = $1[0];
loop$path = path$1;
loop$position = listPrepend(key, position);
loop$inner = inner;
loop$data = data$1;
loop$handle_miss = handle_miss;
} else {
return handle_miss(data, listPrepend(key, position));
}
} else {
let kind = $[0];
let $1 = inner(data);
let default$ = $1[0];
let _pipe = [
default$,
toList([new DecodeError(kind, $dynamic.classify(data), toList([]))]),
];
return push_path(_pipe, $list.reverse(position));
}
}
}
}
/**
* The same as [`field`](#field), except taking a path to the value rather
* than a field name.
*
* This function will index into dictionaries with any key type, and if the key is
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
* the first eight elements of Gleam lists.
*
* ## Examples
*
* ```gleam
* let data = dynamic.properties([
* #(dynamic.string("data"), dynamic.properties([
* #(dynamic.string("email"), dynamic.string("lucy@example.com")),
* #(dynamic.string("name"), dynamic.string("Lucy")),
* ])
* ])
*
* let decoder = {
* use name <- decode.subfield(["data", "name"], decode.string)
* use email <- decode.subfield(["data", "email"], decode.string)
* decode.success(SignUp(name: name, email: email))
* }
* let result = decode.run(data, decoder)
* assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com"))
* ```
*/
export function subfield(field_path, field_decoder, next) {
return new Decoder(
(data) => {
let $ = index(
field_path,
toList([]),
field_decoder.function,
data,
(data, position) => {
let $1 = field_decoder.function(data);
let default$ = $1[0];
let _pipe = [
default$,
toList([new DecodeError("Field", "Nothing", toList([]))]),
];
return push_path(_pipe, $list.reverse(position));
},
);
let out = $[0];
let errors1 = $[1];
let $1 = next(out).function(data);
let out$1 = $1[0];
let errors2 = $1[1];
return [out$1, $list.append(errors1, errors2)];
},
);
}
/**
* A decoder that decodes a value that is nested within other values. For
* example, decoding a value that is within some deeply nested JSON objects.
*
* This function will index into dictionaries with any key type, and if the key is
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
* the first eight elements of Gleam lists.
*
* ## Examples
*
* ```gleam
* let decoder = decode.at(["one", "two"], decode.int)
*
* let data = dynamic.properties([
* #(dynamic.string("one"), dynamic.properties([
* #(dynamic.string("two"), dynamic.int(1000)),
* ]),
* ])
*
* assert decode.run(data, decoder) == Ok(1000)
* ```
*
* ```gleam
* assert dynamic.nil()
* |> decode.run(decode.optional(decode.int))
* == Ok(option.None)
* ```
*/
export function at(path, inner) {
return new Decoder(
(data) => {
return index(
path,
toList([]),
inner.function,
data,
(data, position) => {
let $ = inner.function(data);
let default$ = $[0];
let _pipe = [
default$,
toList([new DecodeError("Field", "Nothing", toList([]))]),
];
return push_path(_pipe, $list.reverse(position));
},
);
},
);
}
/**
* Finalise a decoder having successfully extracted a value.
*
* ## Examples
*
* ```gleam
* let data = dynamic.properties([
* #(dynamic.string("email"), dynamic.string("lucy@example.com")),
* #(dynamic.string("name"), dynamic.string("Lucy")),
* ])
*
* let decoder = {
* use name <- decode.field("name", string)
* use email <- decode.field("email", string)
* decode.success(SignUp(name: name, email: email))
* }
*
* let result = decode.run(data, decoder)
* assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com"))
* ```
*/
export function success(data) {
return new Decoder((_) => { return [data, toList([])]; });
}
/**
* Construct a decode error for some unexpected dynamic data.
*/
export function decode_error(expected, found) {
return toList([
new DecodeError(expected, $dynamic.classify(found), toList([])),
]);
}
/**
* Run a decoder on a field of a `Dynamic` value, decoding the value if it is
* of the desired type, or returning errors. An error is returned if there is
* no field for the specified key.
*
* This function will index into dictionaries with any key type, and if the key is
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
* the first eight elements of Gleam lists.
*
* ## Examples
*
* ```gleam
* let data = dynamic.properties([
* #(dynamic.string("email"), dynamic.string("lucy@example.com")),
* #(dynamic.string("name"), dynamic.string("Lucy")),
* ])
*
* let decoder = {
* use name <- decode.field("name", string)
* use email <- decode.field("email", string)
* decode.success(SignUp(name: name, email: email))
* }
*
* let result = decode.run(data, decoder)
* assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com"))
* ```
*
* If you wish to decode a value that is more deeply nested within the dynamic
* data, see [`subfield`](#subfield) and [`at`](#at).
*
* If you wish to return a default in the event that a field is not present,
* see [`optional_field`](#optional_field) and / [`optionally_at`](#optionally_at).
*/
export function field(field_name, field_decoder, next) {
return subfield(toList([field_name]), field_decoder, next);
}
/**
* Run a decoder on a field of a `Dynamic` value, decoding the value if it is
* of the desired type, or returning errors. The given default value is
* returned if there is no field for the specified key.
*
* This function will index into dictionaries with any key type, and if the key is
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
* the first eight elements of Gleam lists.
*
* ## Examples
*
* ```gleam
* let data = dynamic.properties([
* #(dynamic.string("name"), dynamic.string("Lucy")),
* ])
*
* let decoder = {
* use name <- decode.field("name", string)
* use email <- decode.optional_field("email", "n/a", string)
* decode.success(SignUp(name: name, email: email))
* }
*
* let result = decode.run(data, decoder)
* assert result == Ok(SignUp(name: "Lucy", email: "n/a"))
* ```
*/
export function optional_field(key, default$, field_decoder, next) {
return new Decoder(
(data) => {
let _block;
let _block$1;
let $1 = bare_index(data, key);
if ($1 instanceof Ok) {
let $2 = $1[0];
if ($2 instanceof Some) {
let data$1 = $2[0];
_block$1 = field_decoder.function(data$1);
} else {
_block$1 = [default$, toList([])];
}
} else {
let kind = $1[0];
_block$1 = [
default$,
toList([new DecodeError(kind, $dynamic.classify(data), toList([]))]),
];
}
let _pipe = _block$1;
_block = push_path(_pipe, toList([key]));
let $ = _block;
let out = $[0];
let errors1 = $[1];
let $2 = next(out).function(data);
let out$1 = $2[0];
let errors2 = $2[1];
return [out$1, $list.append(errors1, errors2)];
},
);
}
/**
* A decoder that decodes a value that is nested within other values. For
* example, decoding a value that is within some deeply nested JSON objects.
*
* This function will index into dictionaries with any key type, and if the key is
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
* the first eight elements of Gleam lists.
*
* ## Examples
*
* ```gleam
* let decoder = decode.optionally_at(["one", "two"], 100, decode.int)
*
* let data = dynamic.properties([
* #(dynamic.string("one"), dynamic.properties([])),
* ])
*
* assert decode.run(data, decoder) == Ok(100)
* ```
*/
export function optionally_at(path, default$, inner) {
return new Decoder(
(data) => {
return index(
path,
toList([]),
inner.function,
data,
(_, _1) => { return [default$, toList([])]; },
);
},
);
}
function decode_bool(data) {
let $ = isEqual(cast(true), data);
if ($) {
return [true, toList([])];
} else {
let $1 = isEqual(cast(false), data);
if ($1) {
return [false, toList([])];
} else {
return [false, decode_error("Bool", data)];
}
}
}
function fold_dict(acc, key, value, key_decoder, value_decoder) {
let $ = key_decoder(key);
let $1 = $[1];
if ($1 instanceof $Empty) {
let key_decoded = $[0];
let $2 = value_decoder(value);
let $3 = $2[1];
if ($3 instanceof $Empty) {
let value$1 = $2[0];
let dict$1 = $dict.insert(acc[0], key_decoded, value$1);
return [dict$1, acc[1]];
} else {
let errors = $3;
let key_identifier = path_segment_to_string(key);
return push_path([$dict.new$(), errors], toList([key_identifier]));
}
} else {
let errors = $1;
return push_path([$dict.new$(), errors], toList(["keys"]));
}
}
/**
* A decoder that decodes dicts where all keys and values are decoded with
* given decoders.
*
* ## Examples
*
* ```gleam
* let values = dynamic.properties([
* #(dynamic.string("one"), dynamic.int(1)),
* #(dynamic.string("two"), dynamic.int(2)),
* ])
*
* let result =
* decode.run(values, decode.dict(decode.string, decode.int))
* assert result == Ok(values)
* ```
*/
export function dict(key, value) {
return new Decoder(
(data) => {
let $ = decode_dict(data);
if ($ instanceof Ok) {
let dict$1 = $[0];
return $dict.fold(
dict$1,
[$dict.new$(), toList([])],
(a, k, v) => {
let $1 = a[1];
if ($1 instanceof $Empty) {
return fold_dict(a, k, v, key.function, value.function);
} else {
return a;
}
},
);
} else {
return [$dict.new$(), decode_error("Dict", data)];
}
},
);
}
/**
* A decoder that decodes nullable values of a type decoded by with a given
* decoder.
*
* This function can handle common representations of null on all runtimes, such as
* `nil`, `null`, and `undefined` on Erlang, and `undefined` and `null` on
* JavaScript.
*
* ## Examples
*
* ```gleam
* let result = decode.run(dynamic.int(100), decode.optional(decode.int))
* assert result == Ok(option.Some(100))
* ```
*
* ```gleam
* let result = decode.run(dynamic.nil(), decode.optional(decode.int))
* assert result == Ok(option.None)
* ```
*/
export function optional(inner) {
return new Decoder(
(data) => {
let $ = is_null(data);
if ($) {
return [new $option.None(), toList([])];
} else {
let $1 = inner.function(data);
let data$1 = $1[0];
let errors = $1[1];
return [new $option.Some(data$1), errors];
}
},
);
}
/**
* Apply a transformation function to any errors returned by the decoder.
*/
export function map_errors(decoder, transformer) {
return new Decoder(
(d) => {
let $ = decoder.function(d);
let data = $[0];
let errors = $[1];
return [data, transformer(errors)];
},
);
}
/**
* Replace all errors produced by a decoder with one single error for a named
* expected type.
*
* This function may be useful if you wish to simplify errors before
* presenting them to a user, particularly when using the `one_of` function.
*
* ## Examples
*
* ```gleam
* let decoder = decode.string |> decode.collapse_errors("MyThing")
* let result = decode.run(dynamic.int(1000), decoder)
* assert result == Error([DecodeError("MyThing", "Int", [])])
* ```
*/
export function collapse_errors(decoder, name) {
return new Decoder(
(dynamic_data) => {
let $ = decoder.function(dynamic_data);
let layer = $;
let data = $[0];
let errors = $[1];
if (errors instanceof $Empty) {
return layer;
} else {
return [data, decode_error(name, dynamic_data)];
}
},
);
}
/**
* Create a new decoder based upon the value of a previous decoder.
*
* This may be useful to run one previous decoder to use in further decoding.
*/
export function then$(decoder, next) {
return new Decoder(
(dynamic_data) => {
let $ = decoder.function(dynamic_data);
let data = $[0];
let errors = $[1];
let decoder$1 = next(data);
let $1 = decoder$1.function(dynamic_data);
let layer = $1;
let data$1 = $1[0];
if (errors instanceof $Empty) {
return layer;
} else {
return [data$1, errors];
}
},
);
}
/**
* Define a decoder that always fails.
*
* The first parameter is a "placeholder" value, which is some default value that the
* decoder uses internally in place of the value that would have been produced
* if the decoder was successful. It doesn't matter what this value is, it is
* never returned by the decoder or shown to the user, so pick some arbitrary
* value. If it is an int you might pick `0`, if it is a list you might pick
* `[]`.
*
* The second parameter is the name of the type that has failed to decode.
*
* ```gleam
* decode.failure(User(name: "", score: 0, tags: []), expected: "User")
* ```
*/
export function failure(placeholder, name) {
return new Decoder((d) => { return [placeholder, decode_error(name, d)]; });
}
/**
* Create a decoder for a new data type from a decoding function.
*
* This function is used for new primitive types. For example, you might
* define a decoder for Erlang's pid type.
*
* A default "placeholder" value is also required to make a decoder. When this
* decoder is used as part of a larger decoder this placeholder value is used
* so that the rest of the decoder can continue to run and
* collect all decoding errors. It doesn't matter what this value is, it is
* never returned by the decoder or shown to the user, so pick some arbitrary
* value. If it is an int you might pick `0`, if it is a list you might pick
* `[]`.
*
* If you were to make a decoder for the `Int` type (rather than using the
* built-in `Int` decoder) you would define it like so:
*
* ```gleam
* pub fn int_decoder() -> decode.Decoder(Int) {
* let default = ""
* decode.new_primitive_decoder("Int", int_from_dynamic)
* }
*
* @external(erlang, "my_module", "int_from_dynamic")
* fn int_from_dynamic(data: Int) -> Result(Int, Int)
* ```
*
* ```erlang
* -module(my_module).
* -export([int_from_dynamic/1]).
*
* int_from_dynamic(Data) ->
* case is_integer(Data) of
* true -> {ok, Data};
* false -> {error, 0}
* end.
* ```
*/
export function new_primitive_decoder(name, decoding_function) {
return new Decoder(
(d) => {
let $ = decoding_function(d);
if ($ instanceof Ok) {
let t = $[0];
return [t, toList([])];
} else {
let placeholder = $[0];
return [
placeholder,
toList([new DecodeError(name, $dynamic.classify(d), toList([]))]),
];
}
},
);
}
/**
* Create a decoder that can refer to itself, useful for decoding deeply
* nested data.
*
* Attempting to create a recursive decoder without this function could result
* in an infinite loop. If you are using `field` or other `use`able functions
* then you may not need to use this function.
*
* ## Examples
*
* ```gleam
* type Nested {
* Nested(List(Nested))
* Value(String)
* }
*
* fn nested_decoder() -> decode.Decoder(Nested) {
* use <- decode.recursive
* decode.one_of(decode.string |> decode.map(Value), [
* decode.list(nested_decoder()) |> decode.map(Nested),
* ])
* }
* ```
*/
export function recursive(inner) {
return new Decoder(
(data) => {
let decoder = inner();
return decoder.function(data);
},
);
}
-528
View File
@@ -1,528 +0,0 @@
import { Ok, Error, Empty as $Empty, divideFloat } from "../gleam.mjs";
import * as $order from "../gleam/order.mjs";
import {
parse_float as parse,
float_to_string as to_string,
ceiling,
floor,
round as js_round,
truncate,
identity as do_to_float,
power as do_power,
random_uniform as random,
log as do_log,
exp as exponential,
} from "../gleam_stdlib.mjs";
export { ceiling, exponential, floor, parse, random, to_string, truncate };
/**
* Compares two `Float`s, returning the larger of the two.
*
* ## Examples
*
* ```gleam
* assert max(2.0, 2.3) == 2.3
* ```
*/
export function max(a, b) {
let $ = a > b;
if ($) {
return a;
} else {
return b;
}
}
/**
* Compares two `Float`s, returning the smaller of the two.
*
* ## Examples
*
* ```gleam
* assert min(2.0, 2.3) == 2.0
* ```
*/
export function min(a, b) {
let $ = a < b;
if ($) {
return a;
} else {
return b;
}
}
/**
* Restricts a float between two bounds.
*
* Note: If the `min` argument is larger than the `max` argument then they
* will be swapped, so the minimum bound is always lower than the maximum
* bound.
*
*
* ## Examples
*
* ```gleam
* assert clamp(1.2, min: 1.4, max: 1.6) == 1.4
* ```
*
* ```gleam
* assert clamp(1.2, min: 1.4, max: 0.6) == 1.2
* ```
*/
export function clamp(x, min_bound, max_bound) {
let $ = min_bound >= max_bound;
if ($) {
let _pipe = x;
let _pipe$1 = min(_pipe, min_bound);
return max(_pipe$1, max_bound);
} else {
let _pipe = x;
let _pipe$1 = min(_pipe, max_bound);
return max(_pipe$1, min_bound);
}
}
/**
* Compares two `Float`s, returning an `Order`:
* `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.
*
* ## Examples
*
* ```gleam
* assert compare(2.0, 2.3) == Lt
* ```
*
* To handle
* [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems)
* you may use [`loosely_compare`](#loosely_compare) instead.
*/
export function compare(a, b) {
let $ = a === b;
if ($) {
return new $order.Eq();
} else {
let $1 = a < b;
if ($1) {
return new $order.Lt();
} else {
return new $order.Gt();
}
}
}
/**
* Returns the absolute value of the input as a `Float`.
*
* ## Examples
*
* ```gleam
* assert absolute_value(-12.5) == 12.5
* ```
*
* ```gleam
* assert absolute_value(10.2) == 10.2
* ```
*/
export function absolute_value(x) {
let $ = x >= 0.0;
if ($) {
return x;
} else {
return 0.0 - x;
}
}
/**
* Compares two `Float`s within a tolerance, returning an `Order`:
* `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.
*
* This function allows Float comparison while handling
* [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).
*
* Notice: For `Float`s the tolerance won't be exact:
* `5.3 - 5.0` is not exactly `0.3`.
*
* ## Examples
*
* ```gleam
* assert loosely_compare(5.0, with: 5.3, tolerating: 0.5) == Eq
* ```
*
* If you want to check only for equality you may use
* [`loosely_equals`](#loosely_equals) instead.
*/
export function loosely_compare(a, b, tolerance) {
let difference = absolute_value(a - b);
let $ = difference <= tolerance;
if ($) {
return new $order.Eq();
} else {
return compare(a, b);
}
}
/**
* Checks for equality of two `Float`s within a tolerance,
* returning a `Bool`.
*
* This function allows Float comparison while handling
* [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).
*
* Notice: For `Float`s the tolerance won't be exact:
* `5.3 - 5.0` is not exactly `0.3`.
*
* ## Examples
*
* ```gleam
* assert loosely_equals(5.0, with: 5.3, tolerating: 0.5)
* ```
*
* ```gleam
* assert !loosely_equals(5.0, with: 5.1, tolerating: 0.1)
* ```
*/
export function loosely_equals(a, b, tolerance) {
let difference = absolute_value(a - b);
return difference <= tolerance;
}
/**
* Returns the negative of the value provided.
*
* ## Examples
*
* ```gleam
* assert negate(1.0) == -1.0
* ```
*/
export function negate(x) {
return -1.0 * x;
}
/**
* Rounds the value to the nearest whole number as an `Int`.
*
* ## Examples
*
* ```gleam
* assert round(2.3) == 2
* ```
*
* ```gleam
* assert round(2.5) == 3
* ```
*/
export function round(x) {
let $ = x >= 0.0;
if ($) {
return js_round(x);
} else {
return 0 - js_round(negate(x));
}
}
/**
* Converts the value to a given precision as a `Float`.
* The precision is the number of allowed decimal places.
* Negative precisions are allowed and force rounding
* to the nearest tenth, hundredth, thousandth etc.
*
* ## Examples
*
* ```gleam
* assert to_precision(2.43434348473, 2) == 2.43
* ```
*
* ```gleam
* assert to_precision(547890.453444, -3) == 548000.0
* ```
*/
export function to_precision(x, precision) {
let $ = precision <= 0;
if ($) {
let factor = do_power(10.0, do_to_float(- precision));
return do_to_float(round(divideFloat(x, factor))) * factor;
} else {
let factor = do_power(10.0, do_to_float(precision));
return divideFloat(do_to_float(round(x * factor)), factor);
}
}
/**
* Returns the result of the base being raised to the power of the
* exponent, as a `Float`.
*
* ## Examples
*
* ```gleam
* assert power(2.0, -1.0) == Ok(0.5)
* ```
*
* ```gleam
* assert power(2.0, 2.0) == Ok(4.0)
* ```
*
* ```gleam
* assert power(8.0, 1.5) == Ok(22.627416997969522)
* ```
*
* ```gleam
* assert 4.0 |> power(of: 2.0) == Ok(16.0)
* ```
*
* ```gleam
* assert power(-1.0, 0.5) == Error(Nil)
* ```
*/
export function power(base, exponent) {
let fractional = (ceiling(exponent) - exponent) > 0.0;
let $ = ((base < 0.0) && fractional) || ((base === 0.0) && (exponent < 0.0));
if ($) {
return new Error(undefined);
} else {
return new Ok(do_power(base, exponent));
}
}
/**
* Returns the square root of the input as a `Float`.
*
* ## Examples
*
* ```gleam
* assert square_root(4.0) == Ok(2.0)
* ```
*
* ```gleam
* assert square_root(-16.0) == Error(Nil)
* ```
*/
export function square_root(x) {
return power(x, 0.5);
}
function sum_loop(loop$numbers, loop$initial) {
while (true) {
let numbers = loop$numbers;
let initial = loop$initial;
if (numbers instanceof $Empty) {
return initial;
} else {
let first = numbers.head;
let rest = numbers.tail;
loop$numbers = rest;
loop$initial = first + initial;
}
}
}
/**
* Sums a list of `Float`s.
*
* ## Example
*
* ```gleam
* assert sum([1.0, 2.2, 3.3]) == 6.5
* ```
*/
export function sum(numbers) {
return sum_loop(numbers, 0.0);
}
function product_loop(loop$numbers, loop$initial) {
while (true) {
let numbers = loop$numbers;
let initial = loop$initial;
if (numbers instanceof $Empty) {
return initial;
} else {
let first = numbers.head;
let rest = numbers.tail;
loop$numbers = rest;
loop$initial = first * initial;
}
}
}
/**
* Multiplies a list of `Float`s and returns the product.
*
* ## Example
*
* ```gleam
* assert product([2.5, 3.2, 4.2]) == 33.6
* ```
*/
export function product(numbers) {
return product_loop(numbers, 1.0);
}
/**
* Computes the modulo of a float division of inputs as a `Result`.
*
* Returns division of the inputs as a `Result`: If the given divisor equals
* `0`, this function returns an `Error`.
*
* The computed value will always have the same sign as the `divisor`.
*
* ## Examples
*
* ```gleam
* assert modulo(13.3, by: 3.3) == Ok(0.1)
* ```
*
* ```gleam
* assert modulo(-13.3, by: 3.3) == Ok(3.2)
* ```
*
* ```gleam
* assert modulo(13.3, by: -3.3) == Ok(-3.2)
* ```
*
* ```gleam
* assert modulo(-13.3, by: -3.3) == Ok(-0.1)
* ```
*/
export function modulo(dividend, divisor) {
if (divisor === 0.0) {
return new Error(undefined);
} else {
return new Ok(dividend - (floor(divideFloat(dividend, divisor)) * divisor));
}
}
/**
* Returns division of the inputs as a `Result`.
*
* ## Examples
*
* ```gleam
* assert divide(0.0, 1.0) == Ok(0.0)
* ```
*
* ```gleam
* assert divide(1.0, 0.0) == Error(Nil)
* ```
*/
export function divide(a, b) {
if (b === 0.0) {
return new Error(undefined);
} else {
let b$1 = b;
return new Ok(divideFloat(a, b$1));
}
}
/**
* Adds two floats together.
*
* It's the function equivalent of the `+.` operator.
* This function is useful in higher order functions or pipes.
*
* ## Examples
*
* ```gleam
* assert add(1.0, 2.0) == 3.0
* ```
*
* ```gleam
* import gleam/list
*
* assert list.fold([1.0, 2.0, 3.0], 0.0, add) == 6.0
* ```
*
* ```gleam
* assert 3.0 |> add(2.0) == 5.0
* ```
*/
export function add(a, b) {
return a + b;
}
/**
* Multiplies two floats together.
*
* It's the function equivalent of the `*.` operator.
* This function is useful in higher order functions or pipes.
*
* ## Examples
*
* ```gleam
* assert multiply(2.0, 4.0) == 8.0
* ```
*
* ```gleam
* import gleam/list
*
* assert list.fold([2.0, 3.0, 4.0], 1.0, multiply) == 24.0
* ```
*
* ```gleam
* assert 3.0 |> multiply(2.0) == 6.0
* ```
*/
export function multiply(a, b) {
return a * b;
}
/**
* Subtracts one float from another.
*
* It's the function equivalent of the `-.` operator.
* This function is useful in higher order functions or pipes.
*
* ## Examples
*
* ```gleam
* assert subtract(3.0, 1.0) == 2.0
* ```
*
* ```gleam
* import gleam/list
*
* assert list.fold([1.0, 2.0, 3.0], 10.0, subtract) == 4.0
* ```
*
* ```gleam
* assert 3.0 |> subtract(_, 2.0) == 1.0
* ```
*
* ```gleam
* assert 3.0 |> subtract(2.0, _) == -1.0
* ```
*/
export function subtract(a, b) {
return a - b;
}
/**
* Returns the natural logarithm (base e) of the given `Float` as a `Result`. If the
* input is less than or equal to 0, returns `Error(Nil)`.
*
* ## Examples
*
* ```gleam
* assert logarithm(1.0) == Ok(0.0)
* ```
*
* ```gleam
* assert logarithm(2.718281828459045) == Ok(1.0)
* ```
*
* ```gleam
* assert logarithm(0.0) == Error(Nil)
* ```
*
* ```gleam
* assert logarithm(-1.0) == Error(Nil)
* ```
*/
export function logarithm(x) {
let $ = x <= 0.0;
if ($) {
return new Error(undefined);
} else {
return new Ok(do_log(x));
}
}
@@ -1,6 +0,0 @@
/**
* Takes a single argument and always returns its input value.
*/
export function identity(x) {
return x;
}
-764
View File
@@ -1,764 +0,0 @@
import { Ok, Error, Empty as $Empty, remainderInt, divideInt } from "../gleam.mjs";
import * as $float from "../gleam/float.mjs";
import * as $order from "../gleam/order.mjs";
import {
identity as to_float,
parse_int as parse,
int_from_base_string as do_base_parse,
to_string,
int_to_base_string as do_to_base_string,
bitwise_and,
bitwise_not,
bitwise_or,
bitwise_exclusive_or,
bitwise_shift_left,
bitwise_shift_right,
} from "../gleam_stdlib.mjs";
export {
bitwise_and,
bitwise_exclusive_or,
bitwise_not,
bitwise_or,
bitwise_shift_left,
bitwise_shift_right,
parse,
to_float,
to_string,
};
/**
* Returns the absolute value of the input.
*
* ## Examples
*
* ```gleam
* assert absolute_value(-12) == 12
* ```
*
* ```gleam
* assert absolute_value(10) == 10
* ```
*/
export function absolute_value(x) {
let $ = x >= 0;
if ($) {
return x;
} else {
return x * -1;
}
}
/**
* Returns the result of the base being raised to the power of the
* exponent, as a `Float`.
*
* ## Examples
*
* ```gleam
* assert power(2, -1.0) == Ok(0.5)
* ```
*
* ```gleam
* assert power(2, 2.0) == Ok(4.0)
* ```
*
* ```gleam
* assert power(8, 1.5) == Ok(22.627416997969522)
* ```
*
* ```gleam
* assert 4 |> power(of: 2.0) == Ok(16.0)
* ```
*
* ```gleam
* assert power(-1, 0.5) == Error(Nil)
* ```
*/
export function power(base, exponent) {
let _pipe = base;
let _pipe$1 = to_float(_pipe);
return $float.power(_pipe$1, exponent);
}
/**
* Returns the square root of the input as a `Float`.
*
* ## Examples
*
* ```gleam
* assert square_root(4) == Ok(2.0)
* ```
*
* ```gleam
* assert square_root(-16) == Error(Nil)
* ```
*/
export function square_root(x) {
let _pipe = x;
let _pipe$1 = to_float(_pipe);
return $float.square_root(_pipe$1);
}
/**
* Parses a given string as an int in a given base if possible.
* Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.
*
* ## Examples
*
* ```gleam
* assert base_parse("10", 2) == Ok(2)
* ```
*
* ```gleam
* assert base_parse("30", 16) == Ok(48)
* ```
*
* ```gleam
* assert base_parse("1C", 36) == Ok(48)
* ```
*
* ```gleam
* assert base_parse("48", 1) == Error(Nil)
* ```
*
* ```gleam
* assert base_parse("48", 37) == Error(Nil)
* ```
*/
export function base_parse(string, base) {
let $ = (base >= 2) && (base <= 36);
if ($) {
return do_base_parse(string, base);
} else {
return new Error(undefined);
}
}
/**
* Prints a given int to a string using the base number provided.
* Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.
* For common bases (2, 8, 16, 36), use the `to_baseN` functions.
*
* ## Examples
*
* ```gleam
* assert to_base_string(2, 2) == Ok("10")
* ```
*
* ```gleam
* assert to_base_string(48, 16) == Ok("30")
* ```
*
* ```gleam
* assert to_base_string(48, 36) == Ok("1C")
* ```
*
* ```gleam
* assert to_base_string(48, 1) == Error(Nil)
* ```
*
* ```gleam
* assert to_base_string(48, 37) == Error(Nil)
* ```
*/
export function to_base_string(x, base) {
let $ = (base >= 2) && (base <= 36);
if ($) {
return new Ok(do_to_base_string(x, base));
} else {
return new Error(undefined);
}
}
/**
* Prints a given int to a string using base-2.
*
* ## Examples
*
* ```gleam
* assert to_base2(2) == "10"
* ```
*/
export function to_base2(x) {
return do_to_base_string(x, 2);
}
/**
* Prints a given int to a string using base-8.
*
* ## Examples
*
* ```gleam
* assert to_base8(15) == "17"
* ```
*/
export function to_base8(x) {
return do_to_base_string(x, 8);
}
/**
* Prints a given int to a string using base-16.
*
* ## Examples
*
* ```gleam
* assert to_base16(48) == "30"
* ```
*/
export function to_base16(x) {
return do_to_base_string(x, 16);
}
/**
* Prints a given int to a string using base-36.
*
* ## Examples
*
* ```gleam
* assert to_base36(48) == "1C"
* ```
*/
export function to_base36(x) {
return do_to_base_string(x, 36);
}
/**
* Compares two ints, returning the larger of the two.
*
* ## Examples
*
* ```gleam
* assert max(2, 3) == 3
* ```
*/
export function max(a, b) {
let $ = a > b;
if ($) {
return a;
} else {
return b;
}
}
/**
* Compares two ints, returning the smaller of the two.
*
* ## Examples
*
* ```gleam
* assert min(2, 3) == 2
* ```
*/
export function min(a, b) {
let $ = a < b;
if ($) {
return a;
} else {
return b;
}
}
/**
* Restricts an int between two bounds.
*
* Note: If the `min` argument is larger than the `max` argument then they
* will be swapped, so the minimum bound is always lower than the maximum
* bound.
*
* ## Examples
*
* ```gleam
* assert clamp(40, min: 50, max: 60) == 50
* ```
*
* ```gleam
* assert clamp(40, min: 50, max: 30) == 40
* ```
*/
export function clamp(x, min_bound, max_bound) {
let $ = min_bound >= max_bound;
if ($) {
let _pipe = x;
let _pipe$1 = min(_pipe, min_bound);
return max(_pipe$1, max_bound);
} else {
let _pipe = x;
let _pipe$1 = min(_pipe, max_bound);
return max(_pipe$1, min_bound);
}
}
/**
* Compares two ints, returning an order.
*
* ## Examples
*
* ```gleam
* assert compare(2, 3) == Lt
* ```
*
* ```gleam
* assert compare(4, 3) == Gt
* ```
*
* ```gleam
* assert compare(3, 3) == Eq
* ```
*/
export function compare(a, b) {
let $ = a === b;
if ($) {
return new $order.Eq();
} else {
let $1 = a < b;
if ($1) {
return new $order.Lt();
} else {
return new $order.Gt();
}
}
}
/**
* Returns whether the value provided is even.
*
* ## Examples
*
* ```gleam
* assert is_even(2)
* ```
*
* ```gleam
* assert !is_even(3)
* ```
*/
export function is_even(x) {
return (x % 2) === 0;
}
/**
* Returns whether the value provided is odd.
*
* ## Examples
*
* ```gleam
* assert is_odd(3)
* ```
*
* ```gleam
* assert !is_odd(2)
* ```
*/
export function is_odd(x) {
return (x % 2) !== 0;
}
/**
* Returns the negative of the value provided.
*
* ## Examples
*
* ```gleam
* assert negate(1) == -1
* ```
*/
export function negate(x) {
return -1 * x;
}
function sum_loop(loop$numbers, loop$initial) {
while (true) {
let numbers = loop$numbers;
let initial = loop$initial;
if (numbers instanceof $Empty) {
return initial;
} else {
let first = numbers.head;
let rest = numbers.tail;
loop$numbers = rest;
loop$initial = first + initial;
}
}
}
/**
* Sums a list of ints.
*
* ## Example
*
* ```gleam
* assert sum([1, 2, 3]) == 6
* ```
*/
export function sum(numbers) {
return sum_loop(numbers, 0);
}
function product_loop(loop$numbers, loop$initial) {
while (true) {
let numbers = loop$numbers;
let initial = loop$initial;
if (numbers instanceof $Empty) {
return initial;
} else {
let first = numbers.head;
let rest = numbers.tail;
loop$numbers = rest;
loop$initial = first * initial;
}
}
}
/**
* Multiplies a list of ints and returns the product.
*
* ## Example
*
* ```gleam
* assert product([2, 3, 4]) == 24
* ```
*/
export function product(numbers) {
return product_loop(numbers, 1);
}
/**
* Generates a random int between zero and the given maximum.
*
* The lower number is inclusive, the upper number is exclusive.
*
* ## Examples
*
* ```gleam
* random(10)
* // -> 4
* ```
*
* ```gleam
* random(1)
* // -> 0
* ```
*
* ```gleam
* random(-1)
* // -> -1
* ```
*/
export function random(max) {
let _pipe = ($float.random() * to_float(max));
let _pipe$1 = $float.floor(_pipe);
return $float.round(_pipe$1);
}
/**
* Performs a truncated integer division.
*
* Returns division of the inputs as a `Result`: If the given divisor equals
* `0`, this function returns an `Error`.
*
* ## Examples
*
* ```gleam
* assert divide(0, 1) == Ok(0)
* ```
*
* ```gleam
* assert divide(1, 0) == Error(Nil)
* ```
*
* ```gleam
* assert divide(5, 2) == Ok(2)
* ```
*
* ```gleam
* assert divide(-99, 2) == Ok(-49)
* ```
*/
export function divide(dividend, divisor) {
if (divisor === 0) {
return new Error(undefined);
} else {
let divisor$1 = divisor;
return new Ok(divideInt(dividend, divisor$1));
}
}
/**
* Computes the remainder of an integer division of inputs as a `Result`.
*
* Returns division of the inputs as a `Result`: If the given divisor equals
* `0`, this function returns an `Error`.
*
* Most of the time you will want to use the `%` operator instead of this
* function.
*
* ## Examples
*
* ```gleam
* assert remainder(3, 2) == Ok(1)
* ```
*
* ```gleam
* assert remainder(1, 0) == Error(Nil)
* ```
*
* ```gleam
* assert remainder(10, -1) == Ok(0)
* ```
*
* ```gleam
* assert remainder(13, by: 3) == Ok(1)
* ```
*
* ```gleam
* assert remainder(-13, by: 3) == Ok(-1)
* ```
*
* ```gleam
* assert remainder(13, by: -3) == Ok(1)
* ```
*
* ```gleam
* assert remainder(-13, by: -3) == Ok(-1)
* ```
*/
export function remainder(dividend, divisor) {
if (divisor === 0) {
return new Error(undefined);
} else {
let divisor$1 = divisor;
return new Ok(remainderInt(dividend, divisor$1));
}
}
/**
* Computes the modulo of an integer division of inputs as a `Result`.
*
* Returns division of the inputs as a `Result`: If the given divisor equals
* `0`, this function returns an `Error`.
*
* Note that this is different from `int.remainder` and `%` in that the
* computed value will always have the same sign as the `divisor`.
*
* ## Examples
*
* ```gleam
* assert modulo(3, 2) == Ok(1)
* ```
*
* ```gleam
* assert modulo(1, 0) == Error(Nil)
* ```
*
* ```gleam
* assert modulo(10, -1) == Ok(0)
* ```
*
* ```gleam
* assert modulo(13, by: 3) == Ok(1)
* ```
*
* ```gleam
* assert modulo(-13, by: 3) == Ok(2)
* ```
*
* ```gleam
* assert modulo(13, by: -3) == Ok(-2)
* ```
*/
export function modulo(dividend, divisor) {
if (divisor === 0) {
return new Error(undefined);
} else {
let remainder$1 = remainderInt(dividend, divisor);
let $ = remainder$1 * divisor < 0;
if ($) {
return new Ok(remainder$1 + divisor);
} else {
return new Ok(remainder$1);
}
}
}
/**
* Performs a *floored* integer division, which means that the result will
* always be rounded towards negative infinity.
*
* If you want to perform truncated integer division (rounding towards zero),
* use `int.divide()` or the `/` operator instead.
*
* Returns division of the inputs as a `Result`: If the given divisor equals
* `0`, this function returns an `Error`.
*
* ## Examples
*
* ```gleam
* assert floor_divide(1, 0) == Error(Nil)
* ```
*
* ```gleam
* assert floor_divide(5, 2) == Ok(2)
* ```
*
* ```gleam
* assert floor_divide(6, -4) == Ok(-2)
* ```
*
* ```gleam
* assert floor_divide(-99, 2) == Ok(-50)
* ```
*/
export function floor_divide(dividend, divisor) {
if (divisor === 0) {
return new Error(undefined);
} else {
let divisor$1 = divisor;
let $ = (dividend * divisor$1 < 0) && ((remainderInt(dividend, divisor$1)) !== 0);
if ($) {
return new Ok((divideInt(dividend, divisor$1)) - 1);
} else {
return new Ok(divideInt(dividend, divisor$1));
}
}
}
/**
* Adds two integers together.
*
* It's the function equivalent of the `+` operator.
* This function is useful in higher order functions or pipes.
*
* ## Examples
*
* ```gleam
* assert add(1, 2) == 3
* ```
*
* ```gleam
* import gleam/list
* assert list.fold([1, 2, 3], 0, add) == 6
* ```
*
* ```gleam
* assert 3 |> add(2) == 5
* ```
*/
export function add(a, b) {
return a + b;
}
/**
* Multiplies two integers together.
*
* It's the function equivalent of the `*` operator.
* This function is useful in higher order functions or pipes.
*
* ## Examples
*
* ```gleam
* assert multiply(2, 4) == 8
* ```
*
* ```gleam
* import gleam/list
*
* assert list.fold([2, 3, 4], 1, multiply) == 24
* ```
*
* ```gleam
* assert 3 |> multiply(2) == 6
* ```
*/
export function multiply(a, b) {
return a * b;
}
/**
* Subtracts one int from another.
*
* It's the function equivalent of the `-` operator.
* This function is useful in higher order functions or pipes.
*
* ## Examples
*
* ```gleam
* assert subtract(3, 1) == 2
* ```
*
* ```gleam
* import gleam/list
*
* assert list.fold([1, 2, 3], 10, subtract) == 4
* ```
*
* ```gleam
* assert 3 |> subtract(2) == 1
* ```
*
* ```gleam
* assert 3 |> subtract(2, _) == -1
* ```
*/
export function subtract(a, b) {
return a - b;
}
function range_loop(
loop$current,
loop$stop,
loop$increment,
loop$acc,
loop$reducer
) {
while (true) {
let current = loop$current;
let stop = loop$stop;
let increment = loop$increment;
let acc = loop$acc;
let reducer = loop$reducer;
let $ = current === stop;
if ($) {
return acc;
} else {
let acc$1 = reducer(acc, current);
let current$1 = current + increment;
loop$current = current$1;
loop$stop = stop;
loop$increment = increment;
loop$acc = acc$1;
loop$reducer = reducer;
}
}
}
/**
* Run a function for each int between ints `from` and `to`.
*
* `from` is inclusive, and `to` is exclusive.
*
* ## Examples
*
* ```gleam
* assert
* range(from: 0, to: 3, with: "", run: fn(acc, i) {
* acc <> to_string(i)
* })
* == "012"
* ```
*
* ```gleam
* assert range(from: 1, to: -2, with: [], run: list.prepend) == [-1, 0, 1]
* ```
*/
export function range(start, stop, acc, reducer) {
let _block;
let $ = start < stop;
if ($) {
_block = 1;
} else {
_block = -1;
}
let increment = _block;
return range_loop(start, stop, increment, acc, reducer);
}
-8
View File
@@ -1,8 +0,0 @@
import {
print,
print_error,
console_log as println,
console_error as println_error,
} from "../gleam_stdlib.mjs";
export { print, print_error, println, println_error };
File diff suppressed because it is too large Load Diff
-386
View File
@@ -1,386 +0,0 @@
import {
Ok,
Error,
toList,
Empty as $Empty,
prepend as listPrepend,
CustomType as $CustomType,
} from "../gleam.mjs";
export class Some extends $CustomType {
constructor($0) {
super();
this[0] = $0;
}
}
export const Option$Some = ($0) => new Some($0);
export const Option$isSome = (value) => value instanceof Some;
export const Option$Some$0 = (value) => value[0];
export class None extends $CustomType {}
export const Option$None = () => new None();
export const Option$isNone = (value) => value instanceof None;
function reverse_and_prepend(loop$prefix, loop$suffix) {
while (true) {
let prefix = loop$prefix;
let suffix = loop$suffix;
if (prefix instanceof $Empty) {
return suffix;
} else {
let first = prefix.head;
let rest = prefix.tail;
loop$prefix = rest;
loop$suffix = listPrepend(first, suffix);
}
}
}
function reverse(list) {
return reverse_and_prepend(list, toList([]));
}
function all_loop(loop$list, loop$acc) {
while (true) {
let list = loop$list;
let acc = loop$acc;
if (list instanceof $Empty) {
return new Some(reverse(acc));
} else {
let $ = list.head;
if ($ instanceof Some) {
let rest = list.tail;
let first = $[0];
loop$list = rest;
loop$acc = listPrepend(first, acc);
} else {
return new None();
}
}
}
}
/**
* Combines a list of `Option`s into a single `Option`.
* If all elements in the list are `Some` then returns a `Some` holding the list of values.
* If any element is `None` then returns `None`.
*
* ## Examples
*
* ```gleam
* assert all([Some(1), Some(2)]) == Some([1, 2])
* ```
*
* ```gleam
* assert all([Some(1), None]) == None
* ```
*/
export function all(list) {
return all_loop(list, toList([]));
}
/**
* Checks whether the `Option` is a `Some` value.
*
* ## Examples
*
* ```gleam
* assert is_some(Some(1))
* ```
*
* ```gleam
* assert !is_some(None)
* ```
*/
export function is_some(option) {
return !(option instanceof None);
}
/**
* Checks whether the `Option` is a `None` value.
*
* ## Examples
*
* ```gleam
* assert !is_none(Some(1))
* ```
*
* ```gleam
* assert is_none(None)
* ```
*/
export function is_none(option) {
return option instanceof None;
}
/**
* Converts an `Option` type to a `Result` type.
*
* ## Examples
*
* ```gleam
* assert to_result(Some(1), "some_error") == Ok(1)
* ```
*
* ```gleam
* assert to_result(None, "some_error") == Error("some_error")
* ```
*/
export function to_result(option, e) {
if (option instanceof Some) {
let a = option[0];
return new Ok(a);
} else {
return new Error(e);
}
}
/**
* Converts a `Result` type to an `Option` type.
*
* ## Examples
*
* ```gleam
* assert from_result(Ok(1)) == Some(1)
* ```
*
* ```gleam
* assert from_result(Error("some_error")) == None
* ```
*/
export function from_result(result) {
if (result instanceof Ok) {
let a = result[0];
return new Some(a);
} else {
return new None();
}
}
/**
* Extracts the value from an `Option`, returning a default value if there is none.
*
* ## Examples
*
* ```gleam
* assert unwrap(Some(1), 0) == 1
* ```
*
* ```gleam
* assert unwrap(None, 0) == 0
* ```
*/
export function unwrap(option, default$) {
if (option instanceof Some) {
let x = option[0];
return x;
} else {
return default$;
}
}
/**
* Extracts the value from an `Option`, evaluating the default function if the option is `None`.
*
* ## Examples
*
* ```gleam
* assert lazy_unwrap(Some(1), fn() { 0 }) == 1
* ```
*
* ```gleam
* assert lazy_unwrap(None, fn() { 0 }) == 0
* ```
*/
export function lazy_unwrap(option, default$) {
if (option instanceof Some) {
let x = option[0];
return x;
} else {
return default$();
}
}
/**
* Updates a value held within the `Some` of an `Option` by calling a given function
* on it.
*
* If the `Option` is a `None` rather than `Some`, the function is not called and the
* `Option` stays the same.
*
* ## Examples
*
* ```gleam
* assert map(over: Some(1), with: fn(x) { x + 1 }) == Some(2)
* ```
*
* ```gleam
* assert map(over: None, with: fn(x) { x + 1 }) == None
* ```
*/
export function map(option, fun) {
if (option instanceof Some) {
let x = option[0];
return new Some(fun(x));
} else {
return option;
}
}
/**
* Merges a nested `Option` into a single layer.
*
* ## Examples
*
* ```gleam
* assert flatten(Some(Some(1))) == Some(1)
* ```
*
* ```gleam
* assert flatten(Some(None)) == None
* ```
*
* ```gleam
* assert flatten(None) == None
* ```
*/
export function flatten(option) {
if (option instanceof Some) {
let x = option[0];
return x;
} else {
return option;
}
}
/**
* Updates a value held within the `Some` of an `Option` by calling a given function
* on it, where the given function also returns an `Option`. The two options are
* then merged together into one `Option`.
*
* If the `Option` is a `None` rather than `Some` the function is not called and the
* option stays the same.
*
* This function is the equivalent of calling `map` followed by `flatten`, and
* it is useful for chaining together multiple functions that return `Option`.
*
* ## Examples
*
* ```gleam
* assert then(Some(1), fn(x) { Some(x + 1) }) == Some(2)
* ```
*
* ```gleam
* assert then(Some(1), fn(x) { Some(#("a", x)) }) == Some(#("a", 1))
* ```
*
* ```gleam
* assert then(Some(1), fn(_) { None }) == None
* ```
*
* ```gleam
* assert then(None, fn(x) { Some(x + 1) }) == None
* ```
*/
export function then$(option, fun) {
if (option instanceof Some) {
let x = option[0];
return fun(x);
} else {
return option;
}
}
/**
* Returns the first value if it is `Some`, otherwise returns the second value.
*
* ## Examples
*
* ```gleam
* assert or(Some(1), Some(2)) == Some(1)
* ```
*
* ```gleam
* assert or(Some(1), None) == Some(1)
* ```
*
* ```gleam
* assert or(None, Some(2)) == Some(2)
* ```
*
* ```gleam
* assert or(None, None) == None
* ```
*/
export function or(first, second) {
if (first instanceof Some) {
return first;
} else {
return second;
}
}
/**
* Returns the first value if it is `Some`, otherwise evaluates the given function for a fallback value.
*
* ## Examples
*
* ```gleam
* assert lazy_or(Some(1), fn() { Some(2) }) == Some(1)
* ```
*
* ```gleam
* assert lazy_or(Some(1), fn() { None }) == Some(1)
* ```
*
* ```gleam
* assert lazy_or(None, fn() { Some(2) }) == Some(2)
* ```
*
* ```gleam
* assert lazy_or(None, fn() { None }) == None
* ```
*/
export function lazy_or(first, second) {
if (first instanceof Some) {
return first;
} else {
return second();
}
}
function values_loop(loop$list, loop$acc) {
while (true) {
let list = loop$list;
let acc = loop$acc;
if (list instanceof $Empty) {
return reverse(acc);
} else {
let $ = list.head;
if ($ instanceof Some) {
let rest = list.tail;
let first = $[0];
loop$list = rest;
loop$acc = listPrepend(first, acc);
} else {
let rest = list.tail;
loop$list = rest;
loop$acc = acc;
}
}
}
}
/**
* Given a list of `Option`s,
* returns only the values inside `Some`.
*
* ## Examples
*
* ```gleam
* assert values([Some(1), None, Some(3)]) == [1, 3]
* ```
*/
export function values(options) {
return values_loop(options, toList([]));
}
-175
View File
@@ -1,175 +0,0 @@
import { CustomType as $CustomType, isEqual } from "../gleam.mjs";
/**
* Less-than
*/
export class Lt extends $CustomType {}
export const Order$Lt = () => new Lt();
export const Order$isLt = (value) => value instanceof Lt;
/**
* Equal
*/
export class Eq extends $CustomType {}
export const Order$Eq = () => new Eq();
export const Order$isEq = (value) => value instanceof Eq;
/**
* Greater than
*/
export class Gt extends $CustomType {}
export const Order$Gt = () => new Gt();
export const Order$isGt = (value) => value instanceof Gt;
/**
* Inverts an order, so less-than becomes greater-than and greater-than
* becomes less-than.
*
* ## Examples
*
* ```gleam
* assert negate(Lt) == Gt
* ```
*
* ```gleam
* assert negate(Eq) == Eq
* ```
*
* ```gleam
* assert negate(Gt) == Lt
* ```
*/
export function negate(order) {
if (order instanceof Lt) {
return new Gt();
} else if (order instanceof Eq) {
return order;
} else {
return new Lt();
}
}
/**
* Produces a numeric representation of the order.
*
* ## Examples
*
* ```gleam
* assert to_int(Lt) == -1
* ```
*
* ```gleam
* assert to_int(Eq) == 0
* ```
*
* ```gleam
* assert to_int(Gt) == 1
* ```
*/
export function to_int(order) {
if (order instanceof Lt) {
return -1;
} else if (order instanceof Eq) {
return 0;
} else {
return 1;
}
}
/**
* Compares two `Order` values to one another, producing a new `Order`.
*
* ## Examples
*
* ```gleam
* assert compare(Eq, with: Lt) == Gt
* ```
*/
export function compare(a, b) {
let x = a;
let y = b;
if (isEqual(x, y)) {
return new Eq();
} else if (a instanceof Lt) {
return new Lt();
} else if (a instanceof Eq && b instanceof Gt) {
return new Lt();
} else {
return new Gt();
}
}
/**
* Inverts an ordering function, so less-than becomes greater-than and greater-than
* becomes less-than.
*
* ## Examples
*
* ```gleam
* import gleam/int
* import gleam/list
*
* assert list.sort([1, 5, 4], by: reverse(int.compare)) == [5, 4, 1]
* ```
*/
export function reverse(orderer) {
return (a, b) => { return orderer(b, a); };
}
/**
* Return a fallback `Order` in case the first argument is `Eq`.
*
* ## Examples
*
* ```gleam
* import gleam/int
*
* assert break_tie(in: int.compare(1, 1), with: Lt) == Lt
* ```
*
* ```gleam
* import gleam/int
*
* assert break_tie(in: int.compare(1, 0), with: Eq) == Gt
* ```
*/
export function break_tie(order, other) {
if (order instanceof Lt) {
return order;
} else if (order instanceof Eq) {
return other;
} else {
return order;
}
}
/**
* Invokes a fallback function returning an `Order` in case the first argument
* is `Eq`.
*
* This can be useful when the fallback comparison might be expensive and it
* needs to be delayed until strictly necessary.
*
* ## Examples
*
* ```gleam
* import gleam/int
*
* assert lazy_break_tie(in: int.compare(1, 1), with: fn() { Lt }) == Lt
* ```
*
* ```gleam
* import gleam/int
*
* assert lazy_break_tie(in: int.compare(1, 0), with: fn() { Eq }) == Gt
* ```
*/
export function lazy_break_tie(order, comparison) {
if (order instanceof Lt) {
return order;
} else if (order instanceof Eq) {
return comparison();
} else {
return order;
}
}
-88
View File
@@ -1,88 +0,0 @@
/**
* Returns the first element in a pair.
*
* ## Examples
*
* ```gleam
* assert first(#(1, 2)) == 1
* ```
*/
export function first(pair) {
let a = pair[0];
return a;
}
/**
* Returns the second element in a pair.
*
* ## Examples
*
* ```gleam
* assert second(#(1, 2)) == 2
* ```
*/
export function second(pair) {
let a = pair[1];
return a;
}
/**
* Returns a new pair with the elements swapped.
*
* ## Examples
*
* ```gleam
* assert swap(#(1, 2)) == #(2, 1)
* ```
*/
export function swap(pair) {
let a = pair[0];
let b = pair[1];
return [b, a];
}
/**
* Returns a new pair with the first element having had `with` applied to
* it.
*
* ## Examples
*
* ```gleam
* assert #(1, 2) |> map_first(fn(n) { n * 2 }) == #(2, 2)
* ```
*/
export function map_first(pair, fun) {
let a = pair[0];
let b = pair[1];
return [fun(a), b];
}
/**
* Returns a new pair with the second element having had `with` applied to
* it.
*
* ## Examples
*
* ```gleam
* assert #(1, 2) |> map_second(fn(n) { n * 2 }) == #(1, 4)
* ```
*/
export function map_second(pair, fun) {
let a = pair[0];
let b = pair[1];
return [a, fun(b)];
}
/**
* Returns a new pair with the given elements. This can also be done using the dedicated
* syntax instead: `new(1, 2) == #(1, 2)`.
*
* ## Examples
*
* ```gleam
* assert new(1, 2) == #(1, 2)
* ```
*/
export function new$(first, second) {
return [first, second];
}
-448
View File
@@ -1,448 +0,0 @@
import { Ok, Error, toList, Empty as $Empty, prepend as listPrepend } from "../gleam.mjs";
import * as $list from "../gleam/list.mjs";
/**
* Checks whether the result is an `Ok` value.
*
* ## Examples
*
* ```gleam
* assert is_ok(Ok(1))
* ```
*
* ```gleam
* assert !is_ok(Error(Nil))
* ```
*/
export function is_ok(result) {
if (result instanceof Ok) {
return true;
} else {
return false;
}
}
/**
* Checks whether the result is an `Error` value.
*
* ## Examples
*
* ```gleam
* assert !is_error(Ok(1))
* ```
*
* ```gleam
* assert is_error(Error(Nil))
* ```
*/
export function is_error(result) {
if (result instanceof Ok) {
return false;
} else {
return true;
}
}
/**
* Updates a value held within the `Ok` of a result by calling a given function
* on it.
*
* If the result is an `Error` rather than `Ok` the function is not called and the
* result stays the same.
*
* ## Examples
*
* ```gleam
* assert map(over: Ok(1), with: fn(x) { x + 1 }) == Ok(2)
* ```
*
* ```gleam
* assert map(over: Error(1), with: fn(x) { x + 1 }) == Error(1)
* ```
*/
export function map(result, fun) {
if (result instanceof Ok) {
let x = result[0];
return new Ok(fun(x));
} else {
return result;
}
}
/**
* Updates a value held within the `Error` of a result by calling a given function
* on it.
*
* If the result is `Ok` rather than `Error` the function is not called and the
* result stays the same.
*
* ## Examples
*
* ```gleam
* assert map_error(over: Error(1), with: fn(x) { x + 1 }) == Error(2)
* ```
*
* ```gleam
* assert map_error(over: Ok(1), with: fn(x) { x + 1 }) == Ok(1)
* ```
*/
export function map_error(result, fun) {
if (result instanceof Ok) {
return result;
} else {
let error = result[0];
return new Error(fun(error));
}
}
/**
* Merges a nested `Result` into a single layer.
*
* ## Examples
*
* ```gleam
* assert flatten(Ok(Ok(1))) == Ok(1)
* ```
*
* ```gleam
* assert flatten(Ok(Error(""))) == Error("")
* ```
*
* ```gleam
* assert flatten(Error(Nil)) == Error(Nil)
* ```
*/
export function flatten(result) {
if (result instanceof Ok) {
let x = result[0];
return x;
} else {
return result;
}
}
/**
* "Updates" an `Ok` result by passing its value to a function that yields a result,
* and returning the yielded result. (This may "replace" the `Ok` with an `Error`.)
*
* If the input is an `Error` rather than an `Ok`, the function is not called and
* the original `Error` is returned.
*
* This function is the equivalent of calling `map` followed by `flatten`, and
* it is useful for chaining together multiple functions that may fail.
*
* ## Examples
*
* ```gleam
* assert try(Ok(1), fn(x) { Ok(x + 1) }) == Ok(2)
* ```
*
* ```gleam
* assert try(Ok(1), fn(x) { Ok(#("a", x)) }) == Ok(#("a", 1))
* ```
*
* ```gleam
* assert try(Ok(1), fn(_) { Error("Oh no") }) == Error("Oh no")
* ```
*
* ```gleam
* assert try(Error(Nil), fn(x) { Ok(x + 1) }) == Error(Nil)
* ```
*/
export function try$(result, fun) {
if (result instanceof Ok) {
let x = result[0];
return fun(x);
} else {
return result;
}
}
/**
* Extracts the `Ok` value from a result, returning a default value if the result
* is an `Error`.
*
* ## Examples
*
* ```gleam
* assert unwrap(Ok(1), 0) == 1
* ```
*
* ```gleam
* assert unwrap(Error(""), 0) == 0
* ```
*/
export function unwrap(result, default$) {
if (result instanceof Ok) {
let v = result[0];
return v;
} else {
return default$;
}
}
/**
* Extracts the `Ok` value from a result, evaluating the default function if the result
* is an `Error`.
*
* ## Examples
*
* ```gleam
* assert lazy_unwrap(Ok(1), fn() { 0 }) == 1
* ```
*
* ```gleam
* assert lazy_unwrap(Error(""), fn() { 0 }) == 0
* ```
*/
export function lazy_unwrap(result, default$) {
if (result instanceof Ok) {
let v = result[0];
return v;
} else {
return default$();
}
}
/**
* Extracts the `Error` value from a result, returning a default value if the result
* is an `Ok`.
*
* ## Examples
*
* ```gleam
* assert unwrap_error(Error(1), 0) == 1
* ```
*
* ```gleam
* assert unwrap_error(Ok(""), 0) == 0
* ```
*/
export function unwrap_error(result, default$) {
if (result instanceof Ok) {
return default$;
} else {
let e = result[0];
return e;
}
}
/**
* Returns the first value if it is `Ok`, otherwise returns the second value.
*
* ## Examples
*
* ```gleam
* assert or(Ok(1), Ok(2)) == Ok(1)
* ```
*
* ```gleam
* assert or(Ok(1), Error("Error 2")) == Ok(1)
* ```
*
* ```gleam
* assert or(Error("Error 1"), Ok(2)) == Ok(2)
* ```
*
* ```gleam
* assert or(Error("Error 1"), Error("Error 2")) == Error("Error 2")
* ```
*/
export function or(first, second) {
if (first instanceof Ok) {
return first;
} else {
return second;
}
}
/**
* Returns the first value if it is `Ok`, otherwise evaluates the given function for a fallback value.
*
* If you need access to the initial error value, use `result.try_recover`.
*
* ## Examples
*
* ```gleam
* assert lazy_or(Ok(1), fn() { Ok(2) }) == Ok(1)
* ```
*
* ```gleam
* assert lazy_or(Ok(1), fn() { Error("Error 2") }) == Ok(1)
* ```
*
* ```gleam
* assert lazy_or(Error("Error 1"), fn() { Ok(2) }) == Ok(2)
* ```
*
* ```gleam
* assert lazy_or(Error("Error 1"), fn() { Error("Error 2") })
* == Error("Error 2")
* ```
*/
export function lazy_or(first, second) {
if (first instanceof Ok) {
return first;
} else {
return second();
}
}
/**
* Combines a list of results into a single result.
* If all elements in the list are `Ok` then returns an `Ok` holding the list of values.
* If any element is `Error` then returns the first error.
*
* ## Examples
*
* ```gleam
* assert all([Ok(1), Ok(2)]) == Ok([1, 2])
* ```
*
* ```gleam
* assert all([Ok(1), Error("e")]) == Error("e")
* ```
*/
export function all(results) {
return $list.try_map(results, (result) => { return result; });
}
function partition_loop(loop$results, loop$oks, loop$errors) {
while (true) {
let results = loop$results;
let oks = loop$oks;
let errors = loop$errors;
if (results instanceof $Empty) {
return [oks, errors];
} else {
let $ = results.head;
if ($ instanceof Ok) {
let rest = results.tail;
let a = $[0];
loop$results = rest;
loop$oks = listPrepend(a, oks);
loop$errors = errors;
} else {
let rest = results.tail;
let e = $[0];
loop$results = rest;
loop$oks = oks;
loop$errors = listPrepend(e, errors);
}
}
}
}
/**
* Given a list of results, returns a pair where the first element is a list
* of all the values inside `Ok` and the second element is a list with all the
* values inside `Error`. The values in both lists appear in reverse order with
* respect to their position in the original list of results.
*
* ## Examples
*
* ```gleam
* assert partition([Ok(1), Error("a"), Error("b"), Ok(2)])
* == #([2, 1], ["b", "a"])
* ```
*/
export function partition(results) {
return partition_loop(results, toList([]), toList([]));
}
/**
* Replace the value within a result
*
* ## Examples
*
* ```gleam
* assert replace(Ok(1), Nil) == Ok(Nil)
* ```
*
* ```gleam
* assert replace(Error(1), Nil) == Error(1)
* ```
*/
export function replace(result, value) {
if (result instanceof Ok) {
return new Ok(value);
} else {
return result;
}
}
/**
* Replace the error within a result
*
* ## Examples
*
* ```gleam
* assert replace_error(Error(1), Nil) == Error(Nil)
* ```
*
* ```gleam
* assert replace_error(Ok(1), Nil) == Ok(1)
* ```
*/
export function replace_error(result, error) {
if (result instanceof Ok) {
return result;
} else {
return new Error(error);
}
}
/**
* Given a list of results, returns only the values inside `Ok`.
*
* ## Examples
*
* ```gleam
* assert values([Ok(1), Error("a"), Ok(3)]) == [1, 3]
* ```
*/
export function values(results) {
return $list.filter_map(results, (result) => { return result; });
}
/**
* Updates a value held within the `Error` of a result by calling a given function
* on it, where the given function also returns a result. The two results are
* then merged together into one result.
*
* If the result is an `Ok` rather than `Error` the function is not called and the
* result stays the same.
*
* This function is useful for chaining together computations that may fail
* and trying to recover from possible errors.
*
* If you do not need access to the initial error value, use `result.lazy_or`.
*
* ## Examples
*
* ```gleam
* assert Ok(1)
* |> try_recover(with: fn(_) { Error("failed to recover") })
* == Ok(1)
* ```
*
* ```gleam
* assert Error(1)
* |> try_recover(with: fn(error) { Ok(error + 1) })
* == Ok(2)
* ```
*
* ```gleam
* assert Error(1)
* |> try_recover(with: fn(error) { Error("failed to recover") })
* == Error("failed to recover")
* ```
*/
export function try_recover(result, fun) {
if (result instanceof Ok) {
return result;
} else {
let error = result[0];
return fun(error);
}
}
-409
View File
@@ -1,409 +0,0 @@
import { CustomType as $CustomType, isEqual } from "../gleam.mjs";
import * as $dict from "../gleam/dict.mjs";
import * as $list from "../gleam/list.mjs";
import * as $result from "../gleam/result.mjs";
class Set extends $CustomType {
constructor(dict) {
super();
this.dict = dict;
}
}
const token = undefined;
/**
* Creates a new empty set.
*/
export function new$() {
return new Set($dict.new$());
}
/**
* Gets the number of members in a set.
*
* This function runs in constant time.
*
* ## Examples
*
* ```gleam
* assert new()
* |> insert(1)
* |> insert(2)
* |> size
* == 2
* ```
*/
export function size(set) {
return $dict.size(set.dict);
}
/**
* Determines whether or not the set is empty.
*
* ## Examples
*
* ```gleam
* assert new() |> is_empty
* ```
*
* ```gleam
* assert !{ new() |> insert(1) |> is_empty }
* ```
*/
export function is_empty(set) {
return isEqual(set, new$());
}
/**
* Inserts a member into the set.
*
* This function runs in logarithmic time.
*
* ## Examples
*
* ```gleam
* assert new()
* |> insert(1)
* |> insert(2)
* |> size
* == 2
* ```
*/
export function insert(set, member) {
return new Set($dict.insert(set.dict, member, token));
}
/**
* Checks whether a set contains a given member.
*
* This function runs in logarithmic time.
*
* ## Examples
*
* ```gleam
* assert new()
* |> insert(2)
* |> contains(2)
* ```
*
* ```gleam
* assert !{
* new()
* |> insert(2)
* |> contains(1)
* }
* ```
*/
export function contains(set, member) {
let _pipe = set.dict;
let _pipe$1 = $dict.get(_pipe, member);
return $result.is_ok(_pipe$1);
}
/**
* Removes a member from a set. If the set does not contain the member then
* the set is returned unchanged.
*
* This function runs in logarithmic time.
*
* ## Examples
*
* ```gleam
* assert !{
* new()
* |> insert(2)
* |> delete(2)
* |> contains(2)
* }
* ```
*/
export function delete$(set, member) {
return new Set($dict.delete$(set.dict, member));
}
/**
* Converts the set into a list of the contained members.
*
* The list has no specific ordering, any unintentional ordering may change in
* future versions of Gleam or Erlang.
*
* This function runs in linear time.
*
* ## Examples
*
* ```gleam
* assert new() |> insert(2) |> to_list == [2]
* ```
*/
export function to_list(set) {
return $dict.keys(set.dict);
}
/**
* Creates a new set of the members in a given list.
*
* This function runs in loglinear time.
*
* ## Examples
*
* ```gleam
* import gleam/int
* import gleam/list
*
* assert [1, 1, 2, 4, 3, 2]
* |> from_list
* |> to_list
* |> list.sort(by: int.compare)
* == [1, 2, 3, 4]
* ```
*/
export function from_list(members) {
let dict = $list.fold(
members,
$dict.new$(),
(m, k) => { return $dict.insert(m, k, token); },
);
return new Set(dict);
}
/**
* Combines all entries into a single value by calling a given function on each
* one.
*
* Sets are not ordered so the values are not returned in any specific order.
* Do not write code that relies on the order entries are used by this
* function as it may change in later versions of Gleam or Erlang.
*
* ## Examples
*
* ```gleam
* assert from_list([1, 3, 9])
* |> fold(0, fn(accumulator, member) { accumulator + member })
* == 13
* ```
*/
export function fold(set, initial, reducer) {
return $dict.fold(set.dict, initial, (a, k, _) => { return reducer(a, k); });
}
/**
* Creates a new set from an existing set, minus any members that a given
* function returns `False` for.
*
* This function runs in loglinear time.
*
* ## Examples
*
* ```gleam
* import gleam/int
*
* assert from_list([1, 4, 6, 3, 675, 44, 67])
* |> filter(keeping: int.is_even)
* |> to_list
* == [4, 6, 44]
* ```
*/
export function filter(set, predicate) {
return new Set($dict.filter(set.dict, (m, _) => { return predicate(m); }));
}
/**
* Creates a new set from a given set with the result of applying the given
* function to each member.
*
* ## Examples
*
* ```gleam
* assert from_list([1, 2, 3, 4])
* |> map(with: fn(x) { x * 2 })
* |> to_list
* == [2, 4, 6, 8]
* ```
*/
export function map(set, fun) {
return fold(
set,
new$(),
(acc, member) => { return insert(acc, fun(member)); },
);
}
/**
* Creates a new set from a given set with all the same entries except any
* entry found on the given list.
*
* ## Examples
*
* ```gleam
* assert from_list([1, 2, 3, 4])
* |> drop([1, 3])
* |> to_list
* == [2, 4]
* ```
*/
export function drop(set, disallowed) {
return $list.fold(disallowed, set, delete$);
}
/**
* Creates a new set from a given set, only including any members which are in
* a given list.
*
* This function runs in loglinear time.
*
* ## Examples
*
* ```gleam
* assert from_list([1, 2, 3])
* |> take([1, 3, 5])
* |> to_list
* == [1, 3]
* ```
*/
export function take(set, desired) {
return new Set($dict.take(set.dict, desired));
}
function order(first, second) {
let $ = $dict.size(first.dict) > $dict.size(second.dict);
if ($) {
return [first, second];
} else {
return [second, first];
}
}
/**
* Creates a new set that contains all members of both given sets.
*
* This function runs in loglinear time.
*
* ## Examples
*
* ```gleam
* assert union(from_list([1, 2]), from_list([2, 3])) |> to_list
* == [1, 2, 3]
* ```
*/
export function union(first, second) {
let $ = order(first, second);
let larger = $[0];
let smaller = $[1];
return fold(smaller, larger, insert);
}
/**
* Creates a new set that contains members that are present in both given sets.
*
* This function runs in loglinear time.
*
* ## Examples
*
* ```gleam
* assert intersection(from_list([1, 2]), from_list([2, 3])) |> to_list
* == [2]
* ```
*/
export function intersection(first, second) {
let $ = order(first, second);
let larger = $[0];
let smaller = $[1];
return take(larger, to_list(smaller));
}
/**
* Creates a new set that contains members that are present in the first set
* but not the second.
*
* ## Examples
*
* ```gleam
* assert difference(from_list([1, 2]), from_list([2, 3, 4])) |> to_list
* == [1]
* ```
*/
export function difference(first, second) {
return drop(first, to_list(second));
}
/**
* Determines if a set is fully contained by another.
*
* ## Examples
*
* ```gleam
* assert is_subset(from_list([1]), from_list([1, 2]))
* ```
*
* ```gleam
* assert !is_subset(from_list([1, 2, 3]), from_list([3, 4, 5]))
* ```
*/
export function is_subset(first, second) {
return isEqual(intersection(first, second), first);
}
/**
* Determines if two sets contain no common members
*
* ## Examples
*
* ```gleam
* assert is_disjoint(from_list([1, 2, 3]), from_list([4, 5, 6]))
* ```
*
* ```gleam
* assert !is_disjoint(from_list([1, 2, 3]), from_list([3, 4, 5]))
* ```
*/
export function is_disjoint(first, second) {
return isEqual(intersection(first, second), new$());
}
/**
* Creates a new set that contains members that are present in either set, but
* not both.
*
* ## Examples
*
* ```gleam
* assert symmetric_difference(from_list([1, 2, 3]), from_list([3, 4]))
* |> to_list
* == [1, 2, 4]
* ```
*/
export function symmetric_difference(first, second) {
return difference(union(first, second), intersection(first, second));
}
/**
* Calls a function for each member in a set, discarding the return
* value.
*
* Useful for producing a side effect for every item of a set.
*
* The order of elements in the iteration is an implementation detail that
* should not be relied upon.
*
* ## Examples
*
* ```gleam
* let set = from_list(["apple", "banana", "cherry"])
*
* assert each(set, io.println) == Nil
* // apple
* // banana
* // cherry
* ```
*/
export function each(set, fun) {
return fold(
set,
undefined,
(nil, member) => {
fun(member);
return nil;
},
);
}
-699
View File
@@ -1,699 +0,0 @@
import {
Ok,
Error,
Empty as $Empty,
prepend as listPrepend,
CustomType as $CustomType,
remainderInt,
divideInt,
} from "../gleam.mjs";
import * as $list from "../gleam/list.mjs";
import * as $option from "../gleam/option.mjs";
import { None, Some } from "../gleam/option.mjs";
import * as $order from "../gleam/order.mjs";
import * as $string_tree from "../gleam/string_tree.mjs";
import {
string_length as length,
lowercase,
uppercase,
less_than,
string_grapheme_slice as grapheme_slice,
string_byte_slice as unsafe_byte_slice,
crop_string as crop,
byte_size,
contains_string as contains,
starts_with,
ends_with,
pop_grapheme,
graphemes as to_graphemes,
split_once,
trim_end,
trim_start,
codepoint as unsafe_int_to_utf_codepoint,
string_to_codepoint_integer_list,
utf_codepoint_list_to_string as from_utf_codepoints,
utf_codepoint_to_int,
inspect as do_inspect,
string_remove_prefix as remove_prefix,
string_remove_suffix as remove_suffix,
} from "../gleam_stdlib.mjs";
export {
byte_size,
contains,
crop,
ends_with,
from_utf_codepoints,
length,
lowercase,
pop_grapheme,
remove_prefix,
remove_suffix,
split_once,
starts_with,
to_graphemes,
trim_end,
trim_start,
uppercase,
utf_codepoint_to_int,
};
class Leading extends $CustomType {}
class Trailing extends $CustomType {}
/**
* Determines if a `String` is empty.
*
* ## Examples
*
* ```gleam
* assert is_empty("")
* ```
*
* ```gleam
* assert !is_empty("the world")
* ```
*/
export function is_empty(str) {
return str === "";
}
/**
* Reverses a `String`.
*
* This function has to iterate across the whole `String` so it runs in linear
* time. Avoid using this in a loop.
*
* ## Examples
*
* ```gleam
* assert reverse("stressed") == "desserts"
* ```
*/
export function reverse(string) {
let _pipe = string;
let _pipe$1 = $string_tree.from_string(_pipe);
let _pipe$2 = $string_tree.reverse(_pipe$1);
return $string_tree.to_string(_pipe$2);
}
/**
* Creates a new `String` by replacing all occurrences of a given substring.
*
* ## Examples
*
* ```gleam
* assert replace("www.example.com", each: ".", with: "-") == "www-example-com"
* ```
*
* ```gleam
* assert replace("a,b,c,d,e", each: ",", with: "/") == "a/b/c/d/e"
* ```
*/
export function replace(string, pattern, substitute) {
let _pipe = string;
let _pipe$1 = $string_tree.from_string(_pipe);
let _pipe$2 = $string_tree.replace(_pipe$1, pattern, substitute);
return $string_tree.to_string(_pipe$2);
}
/**
* Compares two `String`s to see which is "larger" by comparing their graphemes.
*
* This does not compare the size or length of the given `String`s.
*
* ## Examples
*
* ```gleam
* import gleam/order
*
* assert compare("Anthony", "Anthony") == order.Eq
* ```
*
* ```gleam
* import gleam/order
*
* assert compare("A", "B") == order.Lt
* ```
*/
export function compare(a, b) {
let $ = a === b;
if ($) {
return new $order.Eq();
} else {
let $1 = less_than(a, b);
if ($1) {
return new $order.Lt();
} else {
return new $order.Gt();
}
}
}
/**
* Takes a substring given a start grapheme index and a length. Negative indexes
* are taken starting from the *end* of the string.
*
* This function runs in linear time with the size of the index and the
* length. Negative indexes are linear with the size of the input string in
* addition to the other costs.
*
* ## Examples
*
* ```gleam
* assert slice(from: "gleam", at_index: 1, length: 2) == "le"
* ```
*
* ```gleam
* assert slice(from: "gleam", at_index: 1, length: 10) == "leam"
* ```
*
* ```gleam
* assert slice(from: "gleam", at_index: 10, length: 3) == ""
* ```
*
* ```gleam
* assert slice(from: "gleam", at_index: -2, length: 2) == "am"
* ```
*
* ```gleam
* assert slice(from: "gleam", at_index: -12, length: 2) == ""
* ```
*/
export function slice(string, idx, len) {
let $ = len <= 0;
if ($) {
return "";
} else {
let $1 = idx < 0;
if ($1) {
let translated_idx = length(string) + idx;
let $2 = translated_idx < 0;
if ($2) {
return "";
} else {
return grapheme_slice(string, translated_idx, len);
}
} else {
return grapheme_slice(string, idx, len);
}
}
}
/**
* Drops *n* graphemes from the start of a `String`.
*
* This function runs in linear time with the number of graphemes to drop.
*
* ## Examples
*
* ```gleam
* assert drop_start(from: "The Lone Gunmen", up_to: 2) == "e Lone Gunmen"
* ```
*/
export function drop_start(string, num_graphemes) {
let $ = num_graphemes <= 0;
if ($) {
return string;
} else {
let prefix = grapheme_slice(string, 0, num_graphemes);
let prefix_size = byte_size(prefix);
return unsafe_byte_slice(
string,
prefix_size,
byte_size(string) - prefix_size,
);
}
}
/**
* Drops *n* graphemes from the end of a `String`.
*
* This function traverses the full string, so it runs in linear time with the
* size of the string. Avoid using this in a loop.
*
* ## Examples
*
* ```gleam
* assert drop_end(from: "Cigarette Smoking Man", up_to: 2)
* == "Cigarette Smoking M"
* ```
*/
export function drop_end(string, num_graphemes) {
let $ = num_graphemes <= 0;
if ($) {
return string;
} else {
return slice(string, 0, length(string) - num_graphemes);
}
}
function to_graphemes_loop(loop$string, loop$acc) {
while (true) {
let string = loop$string;
let acc = loop$acc;
let $ = pop_grapheme(string);
if ($ instanceof Ok) {
let grapheme = $[0][0];
let rest = $[0][1];
loop$string = rest;
loop$acc = listPrepend(grapheme, acc);
} else {
return acc;
}
}
}
/**
* Creates a list of `String`s by splitting a given string on a given substring.
*
* ## Examples
*
* ```gleam
* assert split("home/gleam/desktop/", on: "/")
* == ["home", "gleam", "desktop", ""]
* ```
*/
export function split(x, substring) {
if (substring === "") {
return to_graphemes(x);
} else {
let _pipe = x;
let _pipe$1 = $string_tree.from_string(_pipe);
let _pipe$2 = $string_tree.split(_pipe$1, substring);
return $list.map(_pipe$2, $string_tree.to_string);
}
}
/**
* Creates a new `String` by joining two `String`s together.
*
* This function typically copies both `String`s and runs in linear time, but
* the exact behaviour will depend on how the runtime you are using optimises
* your code. Benchmark and profile your code if you need to understand its
* performance better.
*
* If you are joining together large string and want to avoid copying any data
* you may want to investigate using the [`string_tree`](../gleam/string_tree.html)
* module.
*
* ## Examples
*
* ```gleam
* assert append(to: "butter", suffix: "fly") == "butterfly"
* ```
*/
export function append(first, second) {
return first + second;
}
function concat_loop(loop$strings, loop$accumulator) {
while (true) {
let strings = loop$strings;
let accumulator = loop$accumulator;
if (strings instanceof $Empty) {
return accumulator;
} else {
let string = strings.head;
let strings$1 = strings.tail;
loop$strings = strings$1;
loop$accumulator = accumulator + string;
}
}
}
/**
* Creates a new `String` by joining many `String`s together.
*
* This function copies all the `String`s and runs in linear time.
*
* ## Examples
*
* ```gleam
* assert concat(["never", "the", "less"]) == "nevertheless"
* ```
*/
export function concat(strings) {
return concat_loop(strings, "");
}
function repeat_loop(loop$times, loop$doubling_acc, loop$acc) {
while (true) {
let times = loop$times;
let doubling_acc = loop$doubling_acc;
let acc = loop$acc;
let _block;
let $ = times % 2;
if ($ === 0) {
_block = acc;
} else {
_block = acc + doubling_acc;
}
let acc$1 = _block;
let times$1 = globalThis.Math.trunc(times / 2);
let $1 = times$1 <= 0;
if ($1) {
return acc$1;
} else {
loop$times = times$1;
loop$doubling_acc = doubling_acc + doubling_acc;
loop$acc = acc$1;
}
}
}
/**
* Creates a new `String` by repeating a `String` a given number of times.
*
* This function runs in loglinear time.
*
* ## Examples
*
* ```gleam
* assert repeat("ha", times: 3) == "hahaha"
* ```
*/
export function repeat(string, times) {
let $ = times <= 0;
if ($) {
return "";
} else {
return repeat_loop(times, string, "");
}
}
function join_loop(loop$strings, loop$separator, loop$accumulator) {
while (true) {
let strings = loop$strings;
let separator = loop$separator;
let accumulator = loop$accumulator;
if (strings instanceof $Empty) {
return accumulator;
} else {
let string = strings.head;
let strings$1 = strings.tail;
loop$strings = strings$1;
loop$separator = separator;
loop$accumulator = (accumulator + separator) + string;
}
}
}
/**
* Joins many `String`s together with a given separator.
*
* This function runs in linear time.
*
* ## Examples
*
* ```gleam
* assert join(["home","evan","Desktop"], with: "/") == "home/evan/Desktop"
* ```
*/
export function join(strings, separator) {
if (strings instanceof $Empty) {
return "";
} else {
let first$1 = strings.head;
let rest = strings.tail;
return join_loop(rest, separator, first$1);
}
}
function padding(size, pad_string) {
let pad_string_length = length(pad_string);
let num_pads = divideInt(size, pad_string_length);
let extra = remainderInt(size, pad_string_length);
return repeat(pad_string, num_pads) + slice(pad_string, 0, extra);
}
/**
* Pads the start of a `String` until it has a given length.
*
* ## Examples
*
* ```gleam
* assert pad_start("121", to: 5, with: ".") == "..121"
* ```
*
* ```gleam
* assert pad_start("121", to: 3, with: ".") == "121"
* ```
*
* ```gleam
* assert pad_start("121", to: 2, with: ".") == "121"
* ```
*/
export function pad_start(string, desired_length, pad_string) {
let current_length = length(string);
let to_pad_length = desired_length - current_length;
let $ = to_pad_length <= 0;
if ($) {
return string;
} else {
return padding(to_pad_length, pad_string) + string;
}
}
/**
* Pads the end of a `String` until it has a given length.
*
* ## Examples
*
* ```gleam
* assert pad_end("123", to: 5, with: ".") == "123.."
* ```
*
* ```gleam
* assert pad_end("123", to: 3, with: ".") == "123"
* ```
*
* ```gleam
* assert pad_end("123", to: 2, with: ".") == "123"
* ```
*/
export function pad_end(string, desired_length, pad_string) {
let current_length = length(string);
let to_pad_length = desired_length - current_length;
let $ = to_pad_length <= 0;
if ($) {
return string;
} else {
return string + padding(to_pad_length, pad_string);
}
}
/**
* Removes whitespace on both sides of a `String`.
*
* Whitespace in this function is the set of nonbreakable whitespace
* codepoints, defined as Pattern_White_Space in [Unicode Standard Annex #31][1].
*
* [1]: https://unicode.org/reports/tr31/
*
* ## Examples
*
* ```gleam
* assert trim(" hats \n") == "hats"
* ```
*/
export function trim(string) {
let _pipe = string;
let _pipe$1 = trim_start(_pipe);
return trim_end(_pipe$1);
}
function do_to_utf_codepoints(string) {
let _pipe = string;
let _pipe$1 = string_to_codepoint_integer_list(_pipe);
return $list.map(_pipe$1, unsafe_int_to_utf_codepoint);
}
/**
* Converts a `String` to a `List` of `UtfCodepoint`.
*
* See <https://en.wikipedia.org/wiki/Code_point> and
* <https://en.wikipedia.org/wiki/Unicode#Codespace_and_Code_Points> for an
* explanation on code points.
*
* ## Examples
*
* ```gleam
* assert "a" |> to_utf_codepoints == [UtfCodepoint(97)]
* ```
*
* ```gleam
* // Semantically the same as:
* // ["🏳", "", "", "🌈"] or:
* // [waving_white_flag, variant_selector_16, zero_width_joiner, rainbow]
* assert "🏳️‍🌈" |> to_utf_codepoints
* == [
* UtfCodepoint(127987),
* UtfCodepoint(65039),
* UtfCodepoint(8205),
* UtfCodepoint(127752),
* ]
* ```
*/
export function to_utf_codepoints(string) {
return do_to_utf_codepoints(string);
}
/**
* Converts an integer to a `UtfCodepoint`.
*
* Returns an `Error` if the integer does not represent a valid UTF codepoint.
*/
export function utf_codepoint(value) {
let i = value;
if (i > 1_114_111) {
return new Error(undefined);
} else {
let i = value;
if ((i >= 55_296) && (i <= 57_343)) {
return new Error(undefined);
} else {
let i = value;
if (i < 0) {
return new Error(undefined);
} else {
let i = value;
return new Ok(unsafe_int_to_utf_codepoint(i));
}
}
}
}
/**
* Converts a `String` into `Option(String)` where an empty `String` becomes
* `None`.
*
* ## Examples
*
* ```gleam
* assert to_option("") == None
* ```
*
* ```gleam
* assert to_option("hats") == Some("hats")
* ```
*/
export function to_option(string) {
if (string === "") {
return new None();
} else {
return new Some(string);
}
}
/**
* Returns the first grapheme cluster in a given `String` and wraps it in a
* `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`.
* Otherwise, it returns `Ok(String)`.
*
* ## Examples
*
* ```gleam
* assert first("") == Error(Nil)
* ```
*
* ```gleam
* assert first("icecream") == Ok("i")
* ```
*/
export function first(string) {
let $ = pop_grapheme(string);
if ($ instanceof Ok) {
let first$1 = $[0][0];
return new Ok(first$1);
} else {
return $;
}
}
/**
* Returns the last grapheme cluster in a given `String` and wraps it in a
* `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`.
* Otherwise, it returns `Ok(String)`.
*
* This function traverses the full string, so it runs in linear time with the
* length of the string. Avoid using this in a loop.
*
* ## Examples
*
* ```gleam
* assert last("") == Error(Nil)
* ```
*
* ```gleam
* assert last("icecream") == Ok("m")
* ```
*/
export function last(string) {
let $ = pop_grapheme(string);
if ($ instanceof Ok) {
let $1 = $[0][1];
if ($1 === "") {
let first$1 = $[0][0];
return new Ok(first$1);
} else {
let rest = $1;
return new Ok(slice(rest, -1, 1));
}
} else {
return $;
}
}
/**
* Creates a new `String` with the first grapheme in the input `String`
* converted to uppercase and the remaining graphemes to lowercase.
*
* ## Examples
*
* ```gleam
* assert capitalise("mamouna") == "Mamouna"
* ```
*/
export function capitalise(string) {
let $ = pop_grapheme(string);
if ($ instanceof Ok) {
let first$1 = $[0][0];
let rest = $[0][1];
return append(uppercase(first$1), lowercase(rest));
} else {
return "";
}
}
/**
* Returns a `String` representation of a term in Gleam syntax.
*
* This may be occasionally useful for quick-and-dirty printing of values in
* scripts. For error reporting and other uses prefer constructing strings by
* pattern matching on the values.
*
* ## Limitations
*
* The output format of this function is not stable and could change at any
* time. The output is not suitable for parsing.
*
* This function works using runtime reflection, so the output may not be
* perfectly accurate for data structures where the runtime structure doesn't
* hold enough information to determine the original syntax. For example,
* tuples with an Erlang atom in the first position will be mistaken for Gleam
* records.
*
* ## Security and safety
*
* There is no limit to how large the strings that this function can produce.
* Be careful not to call this function with large data structures or you
* could use very large amounts of memory, potentially causing runtime
* problems.
*/
export function inspect(term) {
let _pipe = term;
let _pipe$1 = do_inspect(_pipe);
return $string_tree.to_string(_pipe$1);
}
@@ -1,128 +0,0 @@
import { toList, CustomType as $CustomType, isEqual } from "../gleam.mjs";
import * as $list from "../gleam/list.mjs";
import {
concat as from_strings,
identity as from_string,
add as append_tree,
concat,
identity as to_string,
length as byte_size,
lowercase,
uppercase,
graphemes as do_to_graphemes,
split,
string_replace as replace,
} from "../gleam_stdlib.mjs";
export {
append_tree,
byte_size,
concat,
from_string,
from_strings,
lowercase,
replace,
split,
to_string,
uppercase,
};
class All extends $CustomType {}
/**
* Create an empty `StringTree`. Useful as the start of a pipe chaining many
* trees together.
*/
export function new$() {
return from_strings(toList([]));
}
/**
* Prepends a `String` onto the start of some `StringTree`.
*
* Runs in constant time.
*/
export function prepend(tree, prefix) {
return append_tree(from_string(prefix), tree);
}
/**
* Appends a `String` onto the end of some `StringTree`.
*
* Runs in constant time.
*/
export function append(tree, second) {
return append_tree(tree, from_string(second));
}
/**
* Prepends some `StringTree` onto the start of another.
*
* Runs in constant time.
*/
export function prepend_tree(tree, prefix) {
return append_tree(prefix, tree);
}
/**
* Joins the given trees into a new tree separated with the given string.
*/
export function join(trees, sep) {
let _pipe = trees;
let _pipe$1 = $list.intersperse(_pipe, from_string(sep));
return concat(_pipe$1);
}
/**
* Converts a `StringTree` to a new one with the contents reversed.
*/
export function reverse(tree) {
let _pipe = tree;
let _pipe$1 = to_string(_pipe);
let _pipe$2 = do_to_graphemes(_pipe$1);
let _pipe$3 = $list.reverse(_pipe$2);
return from_strings(_pipe$3);
}
/**
* Compares two string trees to determine if they have the same textual
* content.
*
* Comparing two string trees using the `==` operator may return `False` even
* if they have the same content as they may have been built in different ways,
* so using this function is often preferred.
*
* ## Examples
*
* ```gleam
* assert from_strings(["a", "b"]) != from_string("ab")
* ```
*
* ```gleam
* assert is_equal(from_strings(["a", "b"]), from_string("ab"))
* ```
*/
export function is_equal(a, b) {
return isEqual(a, b);
}
/**
* Inspects a `StringTree` to determine if it is equivalent to an empty string.
*
* ## Examples
*
* ```gleam
* assert !{ from_string("ok") |> is_empty }
* ```
*
* ```gleam
* assert from_string("") |> is_empty
* ```
*
* ```gleam
* assert from_strings([]) |> is_empty
* ```
*/
export function is_empty(tree) {
return isEqual(from_string(""), tree);
}
File diff suppressed because it is too large Load Diff
@@ -1,347 +0,0 @@
-module(gleam@bit_array).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleam/bit_array.gleam").
-export([from_string/1, bit_size/1, byte_size/1, pad_to_bytes/1, concat/1, append/2, slice/3, is_utf8/1, to_string/1, base64_encode/2, base64_decode/1, base64_url_encode/2, base64_url_decode/1, base16_encode/1, base16_decode/1, inspect/1, compare/2, starts_with/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(" BitArrays are a sequence of binary data of any length.\n").
-file("src/gleam/bit_array.gleam", 11).
?DOC(" Converts a UTF-8 `String` type into a `BitArray`.\n").
-spec from_string(binary()) -> bitstring().
from_string(X) ->
gleam_stdlib:identity(X).
-file("src/gleam/bit_array.gleam", 17).
?DOC(" Returns an integer which is the number of bits in the bit array.\n").
-spec bit_size(bitstring()) -> integer().
bit_size(X) ->
erlang:bit_size(X).
-file("src/gleam/bit_array.gleam", 23).
?DOC(" Returns an integer which is the number of bytes in the bit array.\n").
-spec byte_size(bitstring()) -> integer().
byte_size(X) ->
erlang:byte_size(X).
-file("src/gleam/bit_array.gleam", 29).
?DOC(" Pads a bit array with zeros so that it is a whole number of bytes.\n").
-spec pad_to_bytes(bitstring()) -> bitstring().
pad_to_bytes(X) ->
gleam_stdlib:bit_array_pad_to_bytes(X).
-file("src/gleam/bit_array.gleam", 109).
?DOC(
" Creates a new bit array by joining multiple binaries.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert concat([from_string(\"butter\"), from_string(\"fly\")])\n"
" == from_string(\"butterfly\")\n"
" ```\n"
).
-spec concat(list(bitstring())) -> bitstring().
concat(Bit_arrays) ->
gleam_stdlib:bit_array_concat(Bit_arrays).
-file("src/gleam/bit_array.gleam", 40).
?DOC(
" Creates a new bit array by joining two bit arrays.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert append(to: from_string(\"butter\"), suffix: from_string(\"fly\"))\n"
" == from_string(\"butterfly\")\n"
" ```\n"
).
-spec append(bitstring(), bitstring()) -> bitstring().
append(First, Second) ->
gleam_stdlib:bit_array_concat([First, Second]).
-file("src/gleam/bit_array.gleam", 54).
?DOC(
" Extracts a sub-section of a bit array.\n"
"\n"
" The slice will start at given position and continue up to specified\n"
" length.\n"
" A negative length can be used to extract bytes at the end of a bit array.\n"
"\n"
" This function runs in constant time.\n"
).
-spec slice(bitstring(), integer(), integer()) -> {ok, bitstring()} |
{error, nil}.
slice(String, Position, Length) ->
gleam_stdlib:bit_array_slice(String, Position, Length).
-file("src/gleam/bit_array.gleam", 67).
-spec is_utf8_loop(bitstring()) -> boolean().
is_utf8_loop(Bits) ->
case Bits of
<<>> ->
true;
<<_/utf8, Rest/binary>> ->
is_utf8_loop(Rest);
_ ->
false
end.
-file("src/gleam/bit_array.gleam", 62).
?DOC(" Tests to see whether a bit array is valid UTF-8.\n").
-spec is_utf8(bitstring()) -> boolean().
is_utf8(Bits) ->
is_utf8_loop(Bits).
-file("src/gleam/bit_array.gleam", 88).
?DOC(
" Converts a bit array to a string.\n"
"\n"
" Returns an error if the bit array is invalid UTF-8 data.\n"
).
-spec to_string(bitstring()) -> {ok, binary()} | {error, nil}.
to_string(Bits) ->
case is_utf8(Bits) of
true ->
{ok, gleam_stdlib:identity(Bits)};
false ->
{error, nil}
end.
-file("src/gleam/bit_array.gleam", 118).
?DOC(
" Encodes a BitArray into a base 64 encoded string.\n"
"\n"
" If the bit array does not contain a whole number of bytes then it is padded\n"
" with zero bits prior to being encoded.\n"
).
-spec base64_encode(bitstring(), boolean()) -> binary().
base64_encode(Input, Padding) ->
gleam_stdlib:base64_encode(Input, Padding).
-file("src/gleam/bit_array.gleam", 122).
?DOC(" Decodes a base 64 encoded string into a `BitArray`.\n").
-spec base64_decode(binary()) -> {ok, bitstring()} | {error, nil}.
base64_decode(Encoded) ->
Padded = case erlang:byte_size(gleam_stdlib:identity(Encoded)) rem 4 of
0 ->
Encoded;
N ->
gleam@string:append(
Encoded,
gleam@string:repeat(<<"="/utf8>>, 4 - N)
)
end,
gleam_stdlib:base64_decode(Padded).
-file("src/gleam/bit_array.gleam", 140).
?DOC(
" Encodes a `BitArray` into a base 64 encoded string with URL and filename\n"
" safe alphabet.\n"
"\n"
" If the bit array does not contain a whole number of bytes then it is padded\n"
" with zero bits prior to being encoded.\n"
).
-spec base64_url_encode(bitstring(), boolean()) -> binary().
base64_url_encode(Input, Padding) ->
_pipe = Input,
_pipe@1 = gleam_stdlib:base64_encode(_pipe, Padding),
_pipe@2 = gleam@string:replace(_pipe@1, <<"+"/utf8>>, <<"-"/utf8>>),
gleam@string:replace(_pipe@2, <<"/"/utf8>>, <<"_"/utf8>>).
-file("src/gleam/bit_array.gleam", 150).
?DOC(
" Decodes a base 64 encoded string with URL and filename safe alphabet into a\n"
" `BitArray`.\n"
).
-spec base64_url_decode(binary()) -> {ok, bitstring()} | {error, nil}.
base64_url_decode(Encoded) ->
_pipe = Encoded,
_pipe@1 = gleam@string:replace(_pipe, <<"-"/utf8>>, <<"+"/utf8>>),
_pipe@2 = gleam@string:replace(_pipe@1, <<"_"/utf8>>, <<"/"/utf8>>),
base64_decode(_pipe@2).
-file("src/gleam/bit_array.gleam", 164).
?DOC(
" Encodes a `BitArray` into a base 16 encoded string.\n"
"\n"
" If the bit array does not contain a whole number of bytes then it is padded\n"
" with zero bits prior to being encoded.\n"
).
-spec base16_encode(bitstring()) -> binary().
base16_encode(Input) ->
gleam_stdlib:base16_encode(Input).
-file("src/gleam/bit_array.gleam", 170).
?DOC(" Decodes a base 16 encoded string into a `BitArray`.\n").
-spec base16_decode(binary()) -> {ok, bitstring()} | {error, nil}.
base16_decode(Input) ->
gleam_stdlib:base16_decode(Input).
-file("src/gleam/bit_array.gleam", 191).
-spec inspect_loop(bitstring(), binary()) -> binary().
inspect_loop(Input, Accumulator) ->
case Input of
<<>> ->
Accumulator;
<<X:1>> ->
<<<<Accumulator/binary, (erlang:integer_to_binary(X))/binary>>/binary,
":size(1)"/utf8>>;
<<X@1:2>> ->
<<<<Accumulator/binary, (erlang:integer_to_binary(X@1))/binary>>/binary,
":size(2)"/utf8>>;
<<X@2:3>> ->
<<<<Accumulator/binary, (erlang:integer_to_binary(X@2))/binary>>/binary,
":size(3)"/utf8>>;
<<X@3:4>> ->
<<<<Accumulator/binary, (erlang:integer_to_binary(X@3))/binary>>/binary,
":size(4)"/utf8>>;
<<X@4:5>> ->
<<<<Accumulator/binary, (erlang:integer_to_binary(X@4))/binary>>/binary,
":size(5)"/utf8>>;
<<X@5:6>> ->
<<<<Accumulator/binary, (erlang:integer_to_binary(X@5))/binary>>/binary,
":size(6)"/utf8>>;
<<X@6:7>> ->
<<<<Accumulator/binary, (erlang:integer_to_binary(X@6))/binary>>/binary,
":size(7)"/utf8>>;
<<X@7, Rest/bitstring>> ->
Suffix = case Rest of
<<>> ->
<<""/utf8>>;
_ ->
<<", "/utf8>>
end,
Accumulator@1 = <<<<Accumulator/binary,
(erlang:integer_to_binary(X@7))/binary>>/binary,
Suffix/binary>>,
inspect_loop(Rest, Accumulator@1);
_ ->
Accumulator
end.
-file("src/gleam/bit_array.gleam", 187).
?DOC(
" Converts a bit array to a string containing the decimal value of each byte.\n"
"\n"
" Use this over `string.inspect` when you have a bit array you want printed\n"
" in the array syntax even if it is valid UTF-8.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert inspect(<<0, 20, 0x20, 255>>) == \"<<0, 20, 32, 255>>\"\n"
" ```\n"
"\n"
" ```gleam\n"
" assert inspect(<<100, 5:3>>) == \"<<100, 5:size(3)>>\"\n"
" ```\n"
).
-spec inspect(bitstring()) -> binary().
inspect(Input) ->
<<(inspect_loop(Input, <<"<<"/utf8>>))/binary, ">>"/utf8>>.
-file("src/gleam/bit_array.gleam", 233).
?DOC(
" Compare two bit arrays as sequences of bytes.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert compare(<<1>>, <<2>>) == Lt\n"
" ```\n"
"\n"
" ```gleam\n"
" assert compare(<<\"AB\":utf8>>, <<\"AA\":utf8>>) == Gt\n"
" ```\n"
"\n"
" ```gleam\n"
" assert compare(<<1, 2:size(2)>>, with: <<1, 2:size(2)>>) == Eq\n"
" ```\n"
).
-spec compare(bitstring(), bitstring()) -> gleam@order:order().
compare(A, B) ->
case {A, B} of
{<<First_byte, First_rest/bitstring>>,
<<Second_byte, Second_rest/bitstring>>} ->
case {First_byte, Second_byte} of
{F, S} when F > S ->
gt;
{F@1, S@1} when F@1 < S@1 ->
lt;
{_, _} ->
compare(First_rest, Second_rest)
end;
{<<>>, <<>>} ->
eq;
{_, <<>>} ->
gt;
{<<>>, _} ->
lt;
{First, Second} ->
case {gleam_stdlib:bit_array_to_int_and_size(First),
gleam_stdlib:bit_array_to_int_and_size(Second)} of
{{A@1, _}, {B@1, _}} when A@1 > B@1 ->
gt;
{{A@2, _}, {B@2, _}} when A@2 < B@2 ->
lt;
{{_, Size_a}, {_, Size_b}} when Size_a > Size_b ->
gt;
{{_, Size_a@1}, {_, Size_b@1}} when Size_a@1 < Size_b@1 ->
lt;
{_, _} ->
eq
end
end.
-file("src/gleam/bit_array.gleam", 273).
?DOC(
" Checks whether the first `BitArray` starts with the second one.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert starts_with(<<1, 2, 3, 4>>, <<1, 2>>)\n"
" ```\n"
).
-spec starts_with(bitstring(), bitstring()) -> boolean().
starts_with(Bits, Prefix) ->
Prefix_size = erlang:bit_size(Prefix),
case Bits of
<<Pref:Prefix_size/bitstring, _/bitstring>> when Pref =:= Prefix ->
true;
_ ->
false
end.
-334
View File
@@ -1,334 +0,0 @@
-module(gleam@bool).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleam/bool.gleam").
-export(['and'/2, 'or'/2, negate/1, nor/2, nand/2, exclusive_or/2, exclusive_nor/2, to_string/1, guard/3, lazy_guard/3]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" A type with two possible values, `True` and `False`. Used to indicate whether\n"
" things are... true or false!\n"
"\n"
" It is often clearer and offers more type safety to define a custom type\n"
" than to use `Bool`. For example, rather than having a `is_teacher: Bool`\n"
" field consider having a `role: SchoolRole` field where `SchoolRole` is a custom\n"
" type that can be either `Student` or `Teacher`.\n"
).
-file("src/gleam/bool.gleam", 32).
?DOC(
" Returns the and of two bools, but it evaluates both arguments.\n"
"\n"
" It's the function equivalent of the `&&` operator.\n"
" This function is useful in higher order functions or pipes.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert and(True, True)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !and(False, True)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !and(False, True)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !and(False, False)\n"
" ```\n"
).
-spec 'and'(boolean(), boolean()) -> boolean().
'and'(A, B) ->
A andalso B.
-file("src/gleam/bool.gleam", 59).
?DOC(
" Returns the or of two bools, but it evaluates both arguments.\n"
"\n"
" It's the function equivalent of the `||` operator.\n"
" This function is useful in higher order functions or pipes.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert or(True, True)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert or(False, True)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert or(True, False)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !or(False, False)\n"
" ```\n"
).
-spec 'or'(boolean(), boolean()) -> boolean().
'or'(A, B) ->
A orelse B.
-file("src/gleam/bool.gleam", 77).
?DOC(
" Returns the opposite bool value.\n"
"\n"
" This is the same as the `!` or `not` operators in some other languages.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert !negate(True)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert negate(False)\n"
" ```\n"
).
-spec negate(boolean()) -> boolean().
negate(Bool) ->
not Bool.
-file("src/gleam/bool.gleam", 101).
?DOC(
" Returns the nor of two bools.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert nor(False, False)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !nor(False, True)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !nor(True, False)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !nor(True, True)\n"
" ```\n"
).
-spec nor(boolean(), boolean()) -> boolean().
nor(A, B) ->
not (A orelse B).
-file("src/gleam/bool.gleam", 125).
?DOC(
" Returns the nand of two bools.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert nand(False, False)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert nand(False, True)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert nand(True, False)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !nand(True, True)\n"
" ```\n"
).
-spec nand(boolean(), boolean()) -> boolean().
nand(A, B) ->
not (A andalso B).
-file("src/gleam/bool.gleam", 149).
?DOC(
" Returns the exclusive or of two bools.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert !exclusive_or(False, False)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert exclusive_or(False, True)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert exclusive_or(True, False)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !exclusive_or(True, True)\n"
" ```\n"
).
-spec exclusive_or(boolean(), boolean()) -> boolean().
exclusive_or(A, B) ->
A /= B.
-file("src/gleam/bool.gleam", 173).
?DOC(
" Returns the exclusive nor of two bools.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert exclusive_nor(False, False)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !exclusive_nor(False, True)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !exclusive_nor(True, False)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert exclusive_nor(True, True)\n"
" ```\n"
).
-spec exclusive_nor(boolean(), boolean()) -> boolean().
exclusive_nor(A, B) ->
A =:= B.
-file("src/gleam/bool.gleam", 189).
?DOC(
" Returns a string representation of the given bool.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert to_string(True) == \"True\"\n"
" ```\n"
"\n"
" ```gleam\n"
" assert to_string(False) == \"False\"\n"
" ```\n"
).
-spec to_string(boolean()) -> binary().
to_string(Bool) ->
case Bool of
false ->
<<"False"/utf8>>;
true ->
<<"True"/utf8>>
end.
-file("src/gleam/bool.gleam", 248).
?DOC(
" Run a callback function if the given bool is `False`, otherwise return a\n"
" default value.\n"
"\n"
" With a `use` expression this function can simulate the early-return pattern\n"
" found in some other programming languages.\n"
"\n"
" In a procedural language:\n"
"\n"
" ```js\n"
" if (predicate) return value;\n"
" // ...\n"
" ```\n"
"\n"
" In Gleam with a `use` expression:\n"
"\n"
" ```gleam\n"
" use <- guard(when: predicate, return: value)\n"
" // ...\n"
" ```\n"
"\n"
" Like everything in Gleam `use` is an expression, so it short circuits the\n"
" current block, not the entire function. As a result you can assign the value\n"
" to a variable:\n"
"\n"
" ```gleam\n"
" let x = {\n"
" use <- guard(when: predicate, return: value)\n"
" // ...\n"
" }\n"
" ```\n"
"\n"
" Note that unlike in procedural languages the `return` value is evaluated\n"
" even when the predicate is `False`, so it is advisable not to perform\n"
" expensive computation nor side-effects there.\n"
"\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" let name = \"\"\n"
" use <- guard(when: name == \"\", return: \"Welcome!\")\n"
" \"Hello, \" <> name\n"
" // -> \"Welcome!\"\n"
" ```\n"
"\n"
" ```gleam\n"
" let name = \"Kamaka\"\n"
" use <- guard(when: name == \"\", return: \"Welcome!\")\n"
" \"Hello, \" <> name\n"
" // -> \"Hello, Kamaka\"\n"
" ```\n"
).
-spec guard(boolean(), BTP, fun(() -> BTP)) -> BTP.
guard(Requirement, Consequence, Alternative) ->
case Requirement of
true ->
Consequence;
false ->
Alternative()
end.
-file("src/gleam/bool.gleam", 289).
?DOC(
" Runs a callback function if the given bool is `True`, otherwise runs an\n"
" alternative callback function.\n"
"\n"
" Useful when further computation should be delayed regardless of the given\n"
" bool's value.\n"
"\n"
" See [`guard`](#guard) for more info.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" let name = \"Kamaka\"\n"
" let inquiry = fn() { \"How may we address you?\" }\n"
" use <- lazy_guard(when: name == \"\", return: inquiry)\n"
" \"Hello, \" <> name\n"
" // -> \"Hello, Kamaka\"\n"
" ```\n"
"\n"
" ```gleam\n"
" import gleam/int\n"
"\n"
" let name = \"\"\n"
" let greeting = fn() { \"Hello, \" <> name }\n"
" use <- lazy_guard(when: name == \"\", otherwise: greeting)\n"
" let number = int.random(99)\n"
" let name = \"User \" <> int.to_string(number)\n"
" \"Welcome, \" <> name\n"
" // -> \"Welcome, User 54\"\n"
" ```\n"
).
-spec lazy_guard(boolean(), fun(() -> BTQ), fun(() -> BTQ)) -> BTQ.
lazy_guard(Requirement, Consequence, Alternative) ->
case Requirement of
true ->
Consequence();
false ->
Alternative()
end.
@@ -1,211 +0,0 @@
-module(gleam@bytes_tree).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleam/bytes_tree.gleam").
-export([concat/1, new/0, from_bit_array/1, append_tree/2, prepend/2, append/2, prepend_tree/2, from_string/1, prepend_string/2, append_string/2, concat_bit_arrays/1, from_string_tree/1, to_bit_array/1, byte_size/1]).
-export_type([bytes_tree/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" `BytesTree` is a type used for efficiently building binary content to be\n"
" written to a file or a socket. Internally it is represented as a tree so to\n"
" append or prepend to a bytes tree is a constant time operation that\n"
" allocates a new node in the tree without copying any of the content. When\n"
" writing to an output stream the tree is traversed and the content is sent\n"
" directly rather than copying it into a single buffer beforehand.\n"
"\n"
" If we append one bit array to another the bit arrays must be copied to a\n"
" new location in memory so that they can sit together. This behaviour\n"
" enables efficient reading of the data but copying can be expensive,\n"
" especially if we want to join many bit arrays together.\n"
"\n"
" BytesTree is different in that it can be joined together in constant\n"
" time using minimal memory, and then can be efficiently converted to a\n"
" bit array using the `to_bit_array` function.\n"
"\n"
" Byte trees are always byte aligned, so that a number of bits that is not\n"
" divisible by 8 will be padded with 0s.\n"
"\n"
" On Erlang this type is compatible with Erlang's iolists.\n"
).
-opaque bytes_tree() :: {bytes, bitstring()} |
{text, gleam@string_tree:string_tree()} |
{many, list(bytes_tree())}.
-file("src/gleam/bytes_tree.gleam", 98).
?DOC(
" Joins a list of bytes trees into a single one.\n"
"\n"
" Runs in constant time.\n"
).
-spec concat(list(bytes_tree())) -> bytes_tree().
concat(Trees) ->
gleam_stdlib:identity(Trees).
-file("src/gleam/bytes_tree.gleam", 35).
?DOC(
" Create an empty `BytesTree`. Useful as the start of a pipe chaining many\n"
" trees together.\n"
).
-spec new() -> bytes_tree().
new() ->
gleam_stdlib:identity([]).
-file("src/gleam/bytes_tree.gleam", 136).
?DOC(
" Creates a new bytes tree from a bit array.\n"
"\n"
" Runs in constant time.\n"
).
-spec from_bit_array(bitstring()) -> bytes_tree().
from_bit_array(Bits) ->
_pipe = Bits,
_pipe@1 = gleam_stdlib:bit_array_pad_to_bytes(_pipe),
gleam_stdlib:wrap_list(_pipe@1).
-file("src/gleam/bytes_tree.gleam", 68).
?DOC(
" Appends a bytes tree onto the end of another.\n"
"\n"
" Runs in constant time.\n"
).
-spec append_tree(bytes_tree(), bytes_tree()) -> bytes_tree().
append_tree(First, Second) ->
gleam_stdlib:iodata_append(First, Second).
-file("src/gleam/bytes_tree.gleam", 43).
?DOC(
" Prepends a bit array to the start of a bytes tree.\n"
"\n"
" Runs in constant time.\n"
).
-spec prepend(bytes_tree(), bitstring()) -> bytes_tree().
prepend(Second, First) ->
gleam_stdlib:iodata_append(from_bit_array(First), Second).
-file("src/gleam/bytes_tree.gleam", 51).
?DOC(
" Appends a bit array to the end of a bytes tree.\n"
"\n"
" Runs in constant time.\n"
).
-spec append(bytes_tree(), bitstring()) -> bytes_tree().
append(First, Second) ->
gleam_stdlib:iodata_append(First, from_bit_array(Second)).
-file("src/gleam/bytes_tree.gleam", 59).
?DOC(
" Prepends a bytes tree onto the start of another.\n"
"\n"
" Runs in constant time.\n"
).
-spec prepend_tree(bytes_tree(), bytes_tree()) -> bytes_tree().
prepend_tree(Second, First) ->
gleam_stdlib:iodata_append(First, Second).
-file("src/gleam/bytes_tree.gleam", 118).
?DOC(
" Creates a new bytes tree from a string.\n"
"\n"
" Runs in constant time when running on Erlang.\n"
" Runs in linear time otherwise.\n"
).
-spec from_string(binary()) -> bytes_tree().
from_string(String) ->
gleam_stdlib:wrap_list(String).
-file("src/gleam/bytes_tree.gleam", 80).
?DOC(
" Prepends a string onto the start of a bytes tree.\n"
"\n"
" Runs in constant time when running on Erlang.\n"
" Runs in linear time with the length of the string otherwise.\n"
).
-spec prepend_string(bytes_tree(), binary()) -> bytes_tree().
prepend_string(Second, First) ->
gleam_stdlib:iodata_append(gleam_stdlib:wrap_list(First), Second).
-file("src/gleam/bytes_tree.gleam", 89).
?DOC(
" Appends a string onto the end of a bytes tree.\n"
"\n"
" Runs in constant time when running on Erlang.\n"
" Runs in linear time with the length of the string otherwise.\n"
).
-spec append_string(bytes_tree(), binary()) -> bytes_tree().
append_string(First, Second) ->
gleam_stdlib:iodata_append(First, gleam_stdlib:wrap_list(Second)).
-file("src/gleam/bytes_tree.gleam", 106).
?DOC(
" Joins a list of bit arrays into a single bytes tree.\n"
"\n"
" Runs in constant time.\n"
).
-spec concat_bit_arrays(list(bitstring())) -> bytes_tree().
concat_bit_arrays(Bits) ->
_pipe = Bits,
_pipe@1 = gleam@list:map(_pipe, fun from_bit_array/1),
gleam_stdlib:identity(_pipe@1).
-file("src/gleam/bytes_tree.gleam", 128).
?DOC(
" Creates a new bytes tree from a string tree.\n"
"\n"
" Runs in constant time when running on Erlang.\n"
" Runs in linear time otherwise.\n"
).
-spec from_string_tree(gleam@string_tree:string_tree()) -> bytes_tree().
from_string_tree(Tree) ->
gleam_stdlib:wrap_list(Tree).
-file("src/gleam/bytes_tree.gleam", 162).
-spec to_list(list(list(bytes_tree())), list(bitstring())) -> list(bitstring()).
to_list(Stack, Acc) ->
case Stack of
[] ->
Acc;
[[] | Remaining_stack] ->
to_list(Remaining_stack, Acc);
[[{bytes, Bits} | Rest] | Remaining_stack@1] ->
to_list([Rest | Remaining_stack@1], [Bits | Acc]);
[[{text, Tree} | Rest@1] | Remaining_stack@2] ->
Bits@1 = gleam_stdlib:identity(unicode:characters_to_binary(Tree)),
to_list([Rest@1 | Remaining_stack@2], [Bits@1 | Acc]);
[[{many, Trees} | Rest@2] | Remaining_stack@3] ->
to_list([Trees, Rest@2 | Remaining_stack@3], Acc)
end.
-file("src/gleam/bytes_tree.gleam", 155).
?DOC(
" Turns a bytes tree into a bit array.\n"
"\n"
" Runs in linear time.\n"
"\n"
" When running on Erlang this function is implemented natively by the\n"
" virtual machine and is highly optimised.\n"
).
-spec to_bit_array(bytes_tree()) -> bitstring().
to_bit_array(Tree) ->
erlang:list_to_bitstring(Tree).
-file("src/gleam/bytes_tree.gleam", 186).
?DOC(
" Returns the size of the bytes tree's content in bytes.\n"
"\n"
" Runs in linear time.\n"
).
-spec byte_size(bytes_tree()) -> integer().
byte_size(Tree) ->
erlang:iolist_size(Tree).
-513
View File
@@ -1,513 +0,0 @@
-module(gleam@dict).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleam/dict.gleam").
-export([size/1, is_empty/1, fold/3, to_list/1, new/0, from_list/1, has_key/2, get/2, insert/3, map_values/2, keys/1, values/1, filter/2, take/2, combine/3, merge/2, delete/2, drop/2, upsert/3, each/2, group/2]).
-export_type([dict/2, transient_dict/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type dict(JL, JM) :: any() | {gleam_phantom, JL, JM}.
-type transient_dict(JN, JO) :: any() | {gleam_phantom, JN, JO}.
-file("src/gleam/dict.gleam", 53).
?DOC(
" Determines the number of key-value pairs in the dict.\n"
" This function runs in constant time and does not need to iterate the dict.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert new() |> size == 0\n"
" ```\n"
"\n"
" ```gleam\n"
" assert new() |> insert(\"key\", \"value\") |> size == 1\n"
" ```\n"
).
-spec size(dict(any(), any())) -> integer().
size(Dict) ->
maps:size(Dict).
-file("src/gleam/dict.gleam", 67).
?DOC(
" Determines whether or not the dict is empty.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert new() |> is_empty\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !{ new() |> insert(\"b\", 1) |> is_empty }\n"
" ```\n"
).
-spec is_empty(dict(any(), any())) -> boolean().
is_empty(Dict) ->
maps:size(Dict) =:= 0.
-file("src/gleam/dict.gleam", 469).
?DOC(
" Combines all entries into a single value by calling a given function on each\n"
" one.\n"
"\n"
" Dicts are not ordered so the values are not returned in any specific order. Do\n"
" not write code that relies on the order entries are used by this function\n"
" as it may change in later versions of Gleam or Erlang.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" let dict = from_list([#(\"a\", 1), #(\"b\", 3), #(\"c\", 9)])\n"
" assert fold(dict, 0, fn(accumulator, key, value) { accumulator + value })\n"
" == 13\n"
" ```\n"
"\n"
" ```gleam\n"
" import gleam/string\n"
"\n"
" let dict = from_list([#(\"a\", 1), #(\"b\", 3), #(\"c\", 9)])\n"
" assert\n"
" fold(dict, \"\", fn(accumulator, key, value) {\n"
" string.append(accumulator, key)\n"
" })\n"
" == \"abc\"\n"
" ```\n"
).
-spec fold(dict(QN, QO), QR, fun((QR, QN, QO) -> QR)) -> QR.
fold(Dict, Initial, Fun) ->
Fun@1 = fun(Key, Value, Acc) -> Fun(Acc, Key, Value) end,
maps:fold(Fun@1, Initial, Dict).
-file("src/gleam/dict.gleam", 97).
?DOC(
" Converts the dict to a list of 2-element tuples `#(key, value)`, one for\n"
" each key-value pair in the dict.\n"
"\n"
" The tuples in the list have no specific order.\n"
"\n"
" ## Examples\n"
"\n"
" Calling `to_list` on an empty `dict` returns an empty list.\n"
"\n"
" ```gleam\n"
" assert new() |> to_list == []\n"
" ```\n"
"\n"
" The ordering of elements in the resulting list is an implementation detail\n"
" that should not be relied upon.\n"
"\n"
" ```gleam\n"
" assert new()\n"
" |> insert(\"b\", 1)\n"
" |> insert(\"a\", 0)\n"
" |> insert(\"c\", 2)\n"
" |> to_list\n"
" == [#(\"a\", 0), #(\"b\", 1), #(\"c\", 2)]\n"
" ```\n"
).
-spec to_list(dict(KJ, KK)) -> list({KJ, KK}).
to_list(Dict) ->
maps:to_list(Dict).
-file("src/gleam/dict.gleam", 146).
?DOC(" Creates a fresh dict that contains no values.\n").
-spec new() -> dict(any(), any()).
new() ->
maps:new().
-file("src/gleam/dict.gleam", 111).
-spec from_list_loop(transient_dict(KT, KU), list({KT, KU})) -> dict(KT, KU).
from_list_loop(Transient, List) ->
case List of
[] ->
gleam_stdlib:identity(Transient);
[{Key, Value} | Rest] ->
from_list_loop(maps:put(Key, Value, Transient), Rest)
end.
-file("src/gleam/dict.gleam", 107).
?DOC(
" Converts a list of 2-element tuples `#(key, value)` to a dict.\n"
"\n"
" If two tuples have the same key the last one in the list will be the one\n"
" that is present in the dict.\n"
).
-spec from_list(list({KO, KP})) -> dict(KO, KP).
from_list(List) ->
maps:from_list(List).
-file("src/gleam/dict.gleam", 135).
?DOC(
" Determines whether or not a value is present in the dict for a given key.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert new() |> insert(\"a\", 0) |> has_key(\"a\")\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !{ new() |> insert(\"a\", 0) |> has_key(\"b\") }\n"
" ```\n"
).
-spec has_key(dict(LA, any()), LA) -> boolean().
has_key(Dict, Key) ->
maps:is_key(Key, Dict).
-file("src/gleam/dict.gleam", 165).
?DOC(
" Fetches a value from a dict for a given key.\n"
"\n"
" The dict may not have a value for the key, so the value is wrapped in a\n"
" `Result`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert new() |> insert(\"a\", 0) |> get(\"a\") == Ok(0)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert new() |> insert(\"a\", 0) |> get(\"b\") == Error(Nil)\n"
" ```\n"
).
-spec get(dict(LM, LN), LM) -> {ok, LN} | {error, nil}.
get(From, Get) ->
gleam_stdlib:map_get(From, Get).
-file("src/gleam/dict.gleam", 183).
?DOC(
" Inserts a value into the dict with the given key.\n"
"\n"
" If the dict already has a value for the given key then the value is\n"
" replaced with the new value.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert new() |> insert(\"a\", 0) == from_list([#(\"a\", 0)])\n"
" ```\n"
"\n"
" ```gleam\n"
" assert new() |> insert(\"a\", 0) |> insert(\"a\", 5) == from_list([#(\"a\", 5)])\n"
" ```\n"
).
-spec insert(dict(LS, LT), LS, LT) -> dict(LS, LT).
insert(Dict, Key, Value) ->
maps:put(Key, Value, Dict).
-file("src/gleam/dict.gleam", 210).
?DOC(
" Updates all values in a given dict by calling a given function on each key\n"
" and value.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert from_list([#(3, 3), #(2, 4)])\n"
" |> map_values(fn(key, value) { key * value })\n"
" == from_list([#(3, 9), #(2, 8)])\n"
" ```\n"
).
-spec map_values(dict(MK, ML), fun((MK, ML) -> MO)) -> dict(MK, MO).
map_values(Dict, Fun) ->
maps:map(Fun, Dict).
-file("src/gleam/dict.gleam", 230).
?DOC(
" Gets a list of all keys in a given dict.\n"
"\n"
" Dicts are not ordered so the keys are not returned in any specific order. Do\n"
" not write code that relies on the order keys are returned by this function\n"
" as it may change in later versions of Gleam or Erlang.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert from_list([#(\"a\", 0), #(\"b\", 1)]) |> keys == [\"a\", \"b\"]\n"
" ```\n"
).
-spec keys(dict(MY, any())) -> list(MY).
keys(Dict) ->
maps:keys(Dict).
-file("src/gleam/dict.gleam", 247).
?DOC(
" Gets a list of all values in a given dict.\n"
"\n"
" Dicts are not ordered so the values are not returned in any specific order. Do\n"
" not write code that relies on the order values are returned by this function\n"
" as it may change in later versions of Gleam or Erlang.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert from_list([#(\"a\", 0), #(\"b\", 1)]) |> values == [0, 1]\n"
" ```\n"
).
-spec values(dict(any(), NE)) -> list(NE).
values(Dict) ->
maps:values(Dict).
-file("src/gleam/dict.gleam", 268).
?DOC(
" Creates a new dict from a given dict, minus any entries that a given function\n"
" returns `False` for.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert from_list([#(\"a\", 0), #(\"b\", 1)])\n"
" |> filter(fn(key, value) { value != 0 })\n"
" == from_list([#(\"b\", 1)])\n"
" ```\n"
"\n"
" ```gleam\n"
" assert from_list([#(\"a\", 0), #(\"b\", 1)])\n"
" |> filter(fn(key, value) { True })\n"
" == from_list([#(\"a\", 0), #(\"b\", 1)])\n"
" ```\n"
).
-spec filter(dict(NI, NJ), fun((NI, NJ) -> boolean())) -> dict(NI, NJ).
filter(Dict, Predicate) ->
maps:filter(Predicate, Dict).
-file("src/gleam/dict.gleam", 313).
-spec do_take_loop(dict(OI, OJ), list(OI), transient_dict(OI, OJ)) -> dict(OI, OJ).
do_take_loop(Dict, Desired_keys, Acc) ->
case Desired_keys of
[] ->
gleam_stdlib:identity(Acc);
[Key | Rest] ->
case gleam_stdlib:map_get(Dict, Key) of
{ok, Value} ->
do_take_loop(Dict, Rest, maps:put(Key, Value, Acc));
{error, _} ->
do_take_loop(Dict, Rest, Acc)
end
end.
-file("src/gleam/dict.gleam", 304).
?DOC(
" Creates a new dict from a given dict, only including any entries for which the\n"
" keys are in a given list.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert from_list([#(\"a\", 0), #(\"b\", 1)])\n"
" |> take([\"b\"])\n"
" == from_list([#(\"b\", 1)])\n"
" ```\n"
"\n"
" ```gleam\n"
" assert from_list([#(\"a\", 0), #(\"b\", 1)])\n"
" |> take([\"a\", \"b\", \"c\"])\n"
" == from_list([#(\"a\", 0), #(\"b\", 1)])\n"
" ```\n"
).
-spec take(dict(NU, NV), list(NU)) -> dict(NU, NV).
take(Dict, Desired_keys) ->
maps:with(Desired_keys, Dict).
-file("src/gleam/dict.gleam", 525).
?DOC(
" Creates a new dict from a pair of given dicts by combining their entries.\n"
"\n"
" If there are entries with the same keys in both dicts the given function is\n"
" used to determine the new value to use in the resulting dict.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" let a = from_list([#(\"a\", 0), #(\"b\", 1)])\n"
" let b = from_list([#(\"a\", 2), #(\"c\", 3)])\n"
" assert combine(a, b, fn(one, other) { one + other })\n"
" == from_list([#(\"a\", 2), #(\"b\", 1), #(\"c\", 3)])\n"
" ```\n"
).
-spec combine(dict(RC, RD), dict(RC, RD), fun((RD, RD) -> RD)) -> dict(RC, RD).
combine(Dict, Other, Fun) ->
maps:merge_with(fun(_, L, R) -> Fun(L, R) end, Dict, Other).
-file("src/gleam/dict.gleam", 342).
?DOC(
" Creates a new dict from a pair of given dicts by combining their entries.\n"
"\n"
" If there are entries with the same keys in both dicts the entry from the\n"
" second dict takes precedence.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" let a = from_list([#(\"a\", 0), #(\"b\", 1)])\n"
" let b = from_list([#(\"b\", 2), #(\"c\", 3)])\n"
" assert merge(a, b) == from_list([#(\"a\", 0), #(\"b\", 2), #(\"c\", 3)])\n"
" ```\n"
).
-spec merge(dict(OR, OS), dict(OR, OS)) -> dict(OR, OS).
merge(Dict, New_entries) ->
maps:merge(Dict, New_entries).
-file("src/gleam/dict.gleam", 361).
?DOC(
" Creates a new dict from a given dict with all the same entries except for the\n"
" one with a given key, if it exists.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert from_list([#(\"a\", 0), #(\"b\", 1)]) |> delete(\"a\")\n"
" == from_list([#(\"b\", 1)])\n"
" ```\n"
"\n"
" ```gleam\n"
" assert from_list([#(\"a\", 0), #(\"b\", 1)]) |> delete(\"c\")\n"
" == from_list([#(\"a\", 0), #(\"b\", 1)])\n"
" ```\n"
).
-spec delete(dict(OZ, PA), OZ) -> dict(OZ, PA).
delete(Dict, Key) ->
_pipe = gleam_stdlib:identity(Dict),
_pipe@1 = maps:remove(Key, _pipe),
gleam_stdlib:identity(_pipe@1).
-file("src/gleam/dict.gleam", 398).
-spec drop_loop(transient_dict(PZ, QA), list(PZ)) -> dict(PZ, QA).
drop_loop(Transient, Disallowed_keys) ->
case Disallowed_keys of
[] ->
gleam_stdlib:identity(Transient);
[Key | Rest] ->
drop_loop(maps:remove(Key, Transient), Rest)
end.
-file("src/gleam/dict.gleam", 389).
?DOC(
" Creates a new dict from a given dict with all the same entries except any with\n"
" keys found in a given list.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"a\"])\n"
" == from_list([#(\"b\", 1)])\n"
" ```\n"
"\n"
" ```gleam\n"
" assert from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"c\"])\n"
" == from_list([#(\"a\", 0), #(\"b\", 1)])\n"
" ```\n"
"\n"
" ```gleam\n"
" assert from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"a\", \"b\", \"c\"])\n"
" == from_list([])\n"
" ```\n"
).
-spec drop(dict(PL, PM), list(PL)) -> dict(PL, PM).
drop(Dict, Disallowed_keys) ->
maps:without(Disallowed_keys, Dict).
-file("src/gleam/dict.gleam", 431).
?DOC(
" Creates a new dict with one entry inserted or updated using a given function.\n"
"\n"
" If there was not an entry in the dict for the given key then the function\n"
" gets `None` as its argument, otherwise it gets `Some(value)`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" let dict = from_list([#(\"a\", 0)])\n"
" let increment = fn(x) {\n"
" case x {\n"
" Some(i) -> i + 1\n"
" None -> 0\n"
" }\n"
" }\n"
"\n"
" assert upsert(dict, \"a\", increment) == from_list([#(\"a\", 1)])\n"
" ```\n"
"\n"
" ```gleam\n"
" assert upsert(dict, \"b\", increment) == from_list([#(\"a\", 0), #(\"b\", 0)])\n"
" ```\n"
).
-spec upsert(dict(QG, QH), QG, fun((gleam@option:option(QH)) -> QH)) -> dict(QG, QH).
upsert(Dict, Key, Fun) ->
case gleam_stdlib:map_get(Dict, Key) of
{ok, Value} ->
insert(Dict, Key, Fun({some, Value}));
{error, _} ->
insert(Dict, Key, Fun(none))
end.
-file("src/gleam/dict.gleam", 504).
?DOC(
" Calls a function for each key and value in a dict, discarding the return\n"
" value.\n"
"\n"
" Useful for producing a side effect for every item of a dict.\n"
"\n"
" ```gleam\n"
" import gleam/io\n"
"\n"
" let dict = from_list([#(\"a\", \"apple\"), #(\"b\", \"banana\"), #(\"c\", \"cherry\")])\n"
"\n"
" assert\n"
" each(dict, fn(k, v) {\n"
" io.println(k <> \" => \" <> v)\n"
" })\n"
" == Nil\n"
" // a => apple\n"
" // b => banana\n"
" // c => cherry\n"
" ```\n"
"\n"
" The order of elements in the iteration is an implementation detail that\n"
" should not be relied upon.\n"
).
-spec each(dict(QX, QY), fun((QX, QY) -> any())) -> nil.
each(Dict, Fun) ->
fold(
Dict,
nil,
fun(Nil, K, V) ->
Fun(K, V),
Nil
end
).
-file("src/gleam/dict.gleam", 566).
-spec group_loop(transient_dict(SE, list(SF)), fun((SF) -> SE), list(SF)) -> dict(SE, list(SF)).
group_loop(Transient, To_key, List) ->
case List of
[] ->
gleam_stdlib:identity(Transient);
[Value | Rest] ->
Key = To_key(Value),
Update = fun(Existing) -> [Value | Existing] end,
_pipe = Transient,
_pipe@1 = maps:update_with(Key, Update, [Value], _pipe),
group_loop(_pipe@1, To_key, Rest)
end.
-file("src/gleam/dict.gleam", 562).
?DOC(false).
-spec group(fun((RY) -> RZ), list(RY)) -> dict(RZ, list(RY)).
group(Key, List) ->
group_loop(gleam_stdlib:identity(maps:new()), Key, List).
@@ -1,105 +0,0 @@
-module(gleam@dynamic).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleam/dynamic.gleam").
-export([classify/1, bool/1, string/1, float/1, int/1, bit_array/1, list/1, array/1, properties/1, nil/0]).
-export_type([dynamic_/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type dynamic_() :: any().
-file("src/gleam/dynamic.gleam", 29).
?DOC(
" Return a string indicating the type of the dynamic value.\n"
"\n"
" This function may be useful for constructing error messages or logs. If you\n"
" want to turn dynamic data into well typed data then you want the\n"
" `gleam/dynamic/decode` module.\n"
"\n"
" ```gleam\n"
" assert classify(string(\"Hello\")) == \"String\"\n"
" ```\n"
).
-spec classify(dynamic_()) -> binary().
classify(Data) ->
gleam_stdlib:classify_dynamic(Data).
-file("src/gleam/dynamic.gleam", 35).
?DOC(" Create a dynamic value from a bool.\n").
-spec bool(boolean()) -> dynamic_().
bool(A) ->
gleam_stdlib:identity(A).
-file("src/gleam/dynamic.gleam", 43).
?DOC(
" Create a dynamic value from a string.\n"
"\n"
" On Erlang this will be a binary string rather than a character list.\n"
).
-spec string(binary()) -> dynamic_().
string(A) ->
gleam_stdlib:identity(A).
-file("src/gleam/dynamic.gleam", 49).
?DOC(" Create a dynamic value from a float.\n").
-spec float(float()) -> dynamic_().
float(A) ->
gleam_stdlib:identity(A).
-file("src/gleam/dynamic.gleam", 55).
?DOC(" Create a dynamic value from an int.\n").
-spec int(integer()) -> dynamic_().
int(A) ->
gleam_stdlib:identity(A).
-file("src/gleam/dynamic.gleam", 61).
?DOC(" Create a dynamic value from a bit array.\n").
-spec bit_array(bitstring()) -> dynamic_().
bit_array(A) ->
gleam_stdlib:identity(A).
-file("src/gleam/dynamic.gleam", 67).
?DOC(" Create a dynamic value from a list.\n").
-spec list(list(dynamic_())) -> dynamic_().
list(A) ->
gleam_stdlib:identity(A).
-file("src/gleam/dynamic.gleam", 76).
?DOC(
" Create a dynamic value from a list, converting it to a sequential runtime\n"
" format rather than the regular list format.\n"
"\n"
" On Erlang this will be a tuple, on JavaScript this will be an array.\n"
).
-spec array(list(dynamic_())) -> dynamic_().
array(A) ->
erlang:list_to_tuple(A).
-file("src/gleam/dynamic.gleam", 84).
?DOC(
" Create a dynamic value made of an unordered series of keys and values, where\n"
" the keys are unique.\n"
"\n"
" On Erlang this will be a map, on JavaScript this will be a Gleam dict\n"
" object.\n"
).
-spec properties(list({dynamic_(), dynamic_()})) -> dynamic_().
properties(Entries) ->
gleam_stdlib:identity(maps:from_list(Entries)).
-file("src/gleam/dynamic.gleam", 93).
?DOC(
" A dynamic value representing nothing.\n"
"\n"
" On Erlang this will be the atom `nil`, on JavaScript this will be\n"
" `undefined`.\n"
).
-spec nil() -> dynamic_().
nil() ->
gleam_stdlib:identity(nil).
File diff suppressed because it is too large Load Diff
-711
View File
@@ -1,711 +0,0 @@
-module(gleam@float).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleam/float.gleam").
-export([parse/1, to_string/1, max/2, min/2, clamp/3, compare/2, absolute_value/1, loosely_compare/3, loosely_equals/3, ceiling/1, floor/1, negate/1, round/1, truncate/1, to_precision/2, power/2, square_root/1, sum/1, product/1, random/0, modulo/2, divide/2, add/2, multiply/2, subtract/2, logarithm/1, exponential/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Functions for working with floats.\n"
"\n"
" ## Float representation\n"
"\n"
" Floats are represented as 64 bit floating point numbers on both the Erlang\n"
" and JavaScript runtimes. The floating point behaviour is native to their\n"
" respective runtimes, so their exact behaviour will be slightly different on\n"
" the two runtimes.\n"
"\n"
" ### Infinity and NaN\n"
"\n"
" Under the JavaScript runtime, exceeding the maximum (or minimum)\n"
" representable value for a floating point value will result in Infinity (or\n"
" -Infinity). Should you try to divide two infinities you will get NaN as a\n"
" result.\n"
"\n"
" When running on BEAM, exceeding the maximum (or minimum) representable\n"
" value for a floating point value will raise an error.\n"
"\n"
" ## Division by zero\n"
"\n"
" Gleam runs on the Erlang virtual machine, which does not follow the IEEE\n"
" 754 standard for floating point arithmetic and does not have an `Infinity`\n"
" value. In Erlang division by zero results in a crash, however Gleam does\n"
" not have partial functions and operators in core so instead division by zero\n"
" returns zero, a behaviour taken from Pony, Coq, and Lean.\n"
"\n"
" This may seem unexpected at first, but it is no less mathematically valid\n"
" than crashing or returning a special value. Division by zero is undefined\n"
" in mathematics.\n"
).
-file("src/gleam/float.gleam", 49).
?DOC(
" Attempts to parse a string as a `Float`, returning `Error(Nil)` if it was\n"
" not possible.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert parse(\"2.3\") == Ok(2.3)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert parse(\"ABC\") == Error(Nil)\n"
" ```\n"
).
-spec parse(binary()) -> {ok, float()} | {error, nil}.
parse(String) ->
gleam_stdlib:parse_float(String).
-file("src/gleam/float.gleam", 61).
?DOC(
" Returns the string representation of the provided `Float`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert to_string(2.3) == \"2.3\"\n"
" ```\n"
).
-spec to_string(float()) -> binary().
to_string(X) ->
gleam_stdlib:float_to_string(X).
-file("src/gleam/float.gleam", 192).
?DOC(
" Compares two `Float`s, returning the larger of the two.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert max(2.0, 2.3) == 2.3\n"
" ```\n"
).
-spec max(float(), float()) -> float().
max(A, B) ->
case A > B of
true ->
A;
false ->
B
end.
-file("src/gleam/float.gleam", 177).
?DOC(
" Compares two `Float`s, returning the smaller of the two.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert min(2.0, 2.3) == 2.0\n"
" ```\n"
).
-spec min(float(), float()) -> float().
min(A, B) ->
case A < B of
true ->
A;
false ->
B
end.
-file("src/gleam/float.gleam", 80).
?DOC(
" Restricts a float between two bounds.\n"
"\n"
" Note: If the `min` argument is larger than the `max` argument then they\n"
" will be swapped, so the minimum bound is always lower than the maximum\n"
" bound.\n"
"\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert clamp(1.2, min: 1.4, max: 1.6) == 1.4\n"
" ```\n"
"\n"
" ```gleam\n"
" assert clamp(1.2, min: 1.4, max: 0.6) == 1.2\n"
" ```\n"
).
-spec clamp(float(), float(), float()) -> float().
clamp(X, Min_bound, Max_bound) ->
case Min_bound >= Max_bound of
true ->
_pipe = X,
_pipe@1 = min(_pipe, Min_bound),
max(_pipe@1, Max_bound);
false ->
_pipe@2 = X,
_pipe@3 = min(_pipe@2, Max_bound),
max(_pipe@3, Min_bound)
end.
-file("src/gleam/float.gleam", 100).
?DOC(
" Compares two `Float`s, returning an `Order`:\n"
" `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert compare(2.0, 2.3) == Lt\n"
" ```\n"
"\n"
" To handle\n"
" [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems)\n"
" you may use [`loosely_compare`](#loosely_compare) instead.\n"
).
-spec compare(float(), float()) -> gleam@order:order().
compare(A, B) ->
case A =:= B of
true ->
eq;
false ->
case A < B of
true ->
lt;
false ->
gt
end
end.
-file("src/gleam/float.gleam", 302).
?DOC(
" Returns the absolute value of the input as a `Float`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert absolute_value(-12.5) == 12.5\n"
" ```\n"
"\n"
" ```gleam\n"
" assert absolute_value(10.2) == 10.2\n"
" ```\n"
).
-spec absolute_value(float()) -> float().
absolute_value(X) ->
case X >= +0.0 of
true ->
X;
false ->
+0.0 - X
end.
-file("src/gleam/float.gleam", 129).
?DOC(
" Compares two `Float`s within a tolerance, returning an `Order`:\n"
" `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.\n"
"\n"
" This function allows Float comparison while handling\n"
" [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).\n"
"\n"
" Notice: For `Float`s the tolerance won't be exact:\n"
" `5.3 - 5.0` is not exactly `0.3`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert loosely_compare(5.0, with: 5.3, tolerating: 0.5) == Eq\n"
" ```\n"
"\n"
" If you want to check only for equality you may use\n"
" [`loosely_equals`](#loosely_equals) instead.\n"
).
-spec loosely_compare(float(), float(), float()) -> gleam@order:order().
loosely_compare(A, B, Tolerance) ->
Difference = absolute_value(A - B),
case Difference =< Tolerance of
true ->
eq;
false ->
compare(A, B)
end.
-file("src/gleam/float.gleam", 160).
?DOC(
" Checks for equality of two `Float`s within a tolerance,\n"
" returning a `Bool`.\n"
"\n"
" This function allows Float comparison while handling\n"
" [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).\n"
"\n"
" Notice: For `Float`s the tolerance won't be exact:\n"
" `5.3 - 5.0` is not exactly `0.3`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert loosely_equals(5.0, with: 5.3, tolerating: 0.5)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert !loosely_equals(5.0, with: 5.1, tolerating: 0.1)\n"
" ```\n"
).
-spec loosely_equals(float(), float(), float()) -> boolean().
loosely_equals(A, B, Tolerance) ->
Difference = absolute_value(A - B),
Difference =< Tolerance.
-file("src/gleam/float.gleam", 209).
?DOC(
" Rounds the value to the next highest whole number as a `Float`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert ceiling(2.3) == 3.0\n"
" ```\n"
).
-spec ceiling(float()) -> float().
ceiling(X) ->
math:ceil(X).
-file("src/gleam/float.gleam", 221).
?DOC(
" Rounds the value to the next lowest whole number as a `Float`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert floor(2.3) == 2.0\n"
" ```\n"
).
-spec floor(float()) -> float().
floor(X) ->
math:floor(X).
-file("src/gleam/float.gleam", 376).
?DOC(
" Returns the negative of the value provided.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert negate(1.0) == -1.0\n"
" ```\n"
).
-spec negate(float()) -> float().
negate(X) ->
-1.0 * X.
-file("src/gleam/float.gleam", 236).
?DOC(
" Rounds the value to the nearest whole number as an `Int`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert round(2.3) == 2\n"
" ```\n"
"\n"
" ```gleam\n"
" assert round(2.5) == 3\n"
" ```\n"
).
-spec round(float()) -> integer().
round(X) ->
erlang:round(X).
-file("src/gleam/float.gleam", 256).
?DOC(
" Returns the value as an `Int`, truncating all decimal digits.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert truncate(2.4343434847383438) == 2\n"
" ```\n"
).
-spec truncate(float()) -> integer().
truncate(X) ->
erlang:trunc(X).
-file("src/gleam/float.gleam", 273).
?DOC(
" Converts the value to a given precision as a `Float`.\n"
" The precision is the number of allowed decimal places.\n"
" Negative precisions are allowed and force rounding\n"
" to the nearest tenth, hundredth, thousandth etc.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert to_precision(2.43434348473, 2) == 2.43\n"
" ```\n"
"\n"
" ```gleam\n"
" assert to_precision(547890.453444, -3) == 548000.0\n"
" ```\n"
).
-spec to_precision(float(), integer()) -> float().
to_precision(X, Precision) ->
case Precision =< 0 of
true ->
Factor = math:pow(10.0, erlang:float(- Precision)),
erlang:float(erlang:round(case Factor of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> X / Gleam@denominator
end)) * Factor;
false ->
Factor@1 = math:pow(10.0, erlang:float(Precision)),
case Factor@1 of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator@1 -> erlang:float(erlang:round(X * Factor@1))
/ Gleam@denominator@1
end
end.
-file("src/gleam/float.gleam", 334).
?DOC(
" Returns the result of the base being raised to the power of the\n"
" exponent, as a `Float`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert power(2.0, -1.0) == Ok(0.5)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert power(2.0, 2.0) == Ok(4.0)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert power(8.0, 1.5) == Ok(22.627416997969522)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert 4.0 |> power(of: 2.0) == Ok(16.0)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert power(-1.0, 0.5) == Error(Nil)\n"
" ```\n"
).
-spec power(float(), float()) -> {ok, float()} | {error, nil}.
power(Base, Exponent) ->
Fractional = (math:ceil(Exponent) - Exponent) > +0.0,
case ((Base < +0.0) andalso Fractional) orelse ((Base =:= +0.0) andalso (Exponent
< +0.0)) of
true ->
{error, nil};
false ->
{ok, math:pow(Base, Exponent)}
end.
-file("src/gleam/float.gleam", 364).
?DOC(
" Returns the square root of the input as a `Float`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert square_root(4.0) == Ok(2.0)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert square_root(-16.0) == Error(Nil)\n"
" ```\n"
).
-spec square_root(float()) -> {ok, float()} | {error, nil}.
square_root(X) ->
power(X, 0.5).
-file("src/gleam/float.gleam", 392).
-spec sum_loop(list(float()), float()) -> float().
sum_loop(Numbers, Initial) ->
case Numbers of
[First | Rest] ->
sum_loop(Rest, First + Initial);
[] ->
Initial
end.
-file("src/gleam/float.gleam", 388).
?DOC(
" Sums a list of `Float`s.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" assert sum([1.0, 2.2, 3.3]) == 6.5\n"
" ```\n"
).
-spec sum(list(float())) -> float().
sum(Numbers) ->
sum_loop(Numbers, +0.0).
-file("src/gleam/float.gleam", 411).
-spec product_loop(list(float()), float()) -> float().
product_loop(Numbers, Initial) ->
case Numbers of
[First | Rest] ->
product_loop(Rest, First * Initial);
[] ->
Initial
end.
-file("src/gleam/float.gleam", 407).
?DOC(
" Multiplies a list of `Float`s and returns the product.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" assert product([2.5, 3.2, 4.2]) == 33.6\n"
" ```\n"
).
-spec product(list(float())) -> float().
product(Numbers) ->
product_loop(Numbers, 1.0).
-file("src/gleam/float.gleam", 433).
?DOC(
" Generates a random float between the given zero (inclusive) and one\n"
" (exclusive).\n"
"\n"
" On Erlang this updates the random state in the process dictionary.\n"
" See: <https://www.erlang.org/doc/man/rand.html#uniform-0>\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" random()\n"
" // -> 0.646355926896028\n"
" ```\n"
).
-spec random() -> float().
random() ->
rand:uniform().
-file("src/gleam/float.gleam", 460).
?DOC(
" Computes the modulo of a float division of inputs as a `Result`.\n"
"\n"
" Returns division of the inputs as a `Result`: If the given divisor equals\n"
" `0`, this function returns an `Error`.\n"
"\n"
" The computed value will always have the same sign as the `divisor`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert modulo(13.3, by: 3.3) == Ok(0.1)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert modulo(-13.3, by: 3.3) == Ok(3.2)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert modulo(13.3, by: -3.3) == Ok(-3.2)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert modulo(-13.3, by: -3.3) == Ok(-0.1)\n"
" ```\n"
).
-spec modulo(float(), float()) -> {ok, float()} | {error, nil}.
modulo(Dividend, Divisor) ->
case Divisor of
+0.0 ->
{error, nil};
_ ->
{ok, Dividend - (math:floor(case Divisor of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> Dividend / Gleam@denominator
end) * Divisor)}
end.
-file("src/gleam/float.gleam", 479).
?DOC(
" Returns division of the inputs as a `Result`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert divide(0.0, 1.0) == Ok(0.0)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert divide(1.0, 0.0) == Error(Nil)\n"
" ```\n"
).
-spec divide(float(), float()) -> {ok, float()} | {error, nil}.
divide(A, B) ->
case B of
+0.0 ->
{error, nil};
B@1 ->
{ok, case B@1 of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> A / Gleam@denominator
end}
end.
-file("src/gleam/float.gleam", 507).
?DOC(
" Adds two floats together.\n"
"\n"
" It's the function equivalent of the `+.` operator.\n"
" This function is useful in higher order functions or pipes.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert add(1.0, 2.0) == 3.0\n"
" ```\n"
"\n"
" ```gleam\n"
" import gleam/list\n"
"\n"
" assert list.fold([1.0, 2.0, 3.0], 0.0, add) == 6.0\n"
" ```\n"
"\n"
" ```gleam\n"
" assert 3.0 |> add(2.0) == 5.0\n"
" ```\n"
).
-spec add(float(), float()) -> float().
add(A, B) ->
A + B.
-file("src/gleam/float.gleam", 532).
?DOC(
" Multiplies two floats together.\n"
"\n"
" It's the function equivalent of the `*.` operator.\n"
" This function is useful in higher order functions or pipes.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert multiply(2.0, 4.0) == 8.0\n"
" ```\n"
"\n"
" ```gleam\n"
" import gleam/list\n"
"\n"
" assert list.fold([2.0, 3.0, 4.0], 1.0, multiply) == 24.0\n"
" ```\n"
"\n"
" ```gleam\n"
" assert 3.0 |> multiply(2.0) == 6.0\n"
" ```\n"
).
-spec multiply(float(), float()) -> float().
multiply(A, B) ->
A * B.
-file("src/gleam/float.gleam", 561).
?DOC(
" Subtracts one float from another.\n"
"\n"
" It's the function equivalent of the `-.` operator.\n"
" This function is useful in higher order functions or pipes.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert subtract(3.0, 1.0) == 2.0\n"
" ```\n"
"\n"
" ```gleam\n"
" import gleam/list\n"
"\n"
" assert list.fold([1.0, 2.0, 3.0], 10.0, subtract) == 4.0\n"
" ```\n"
"\n"
" ```gleam\n"
" assert 3.0 |> subtract(_, 2.0) == 1.0\n"
" ```\n"
"\n"
" ```gleam\n"
" assert 3.0 |> subtract(2.0, _) == -1.0\n"
" ```\n"
).
-spec subtract(float(), float()) -> float().
subtract(A, B) ->
A - B.
-file("src/gleam/float.gleam", 586).
?DOC(
" Returns the natural logarithm (base e) of the given `Float` as a `Result`. If the\n"
" input is less than or equal to 0, returns `Error(Nil)`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert logarithm(1.0) == Ok(0.0)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert logarithm(2.718281828459045) == Ok(1.0)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert logarithm(0.0) == Error(Nil)\n"
" ```\n"
"\n"
" ```gleam\n"
" assert logarithm(-1.0) == Error(Nil)\n"
" ```\n"
).
-spec logarithm(float()) -> {ok, float()} | {error, nil}.
logarithm(X) ->
case X =< +0.0 of
true ->
{error, nil};
false ->
{ok, math:log(X)}
end.
-file("src/gleam/float.gleam", 621).
?DOC(
" Returns e (Euler's number) raised to the power of the given exponent, as\n"
" a `Float`.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" assert exponential(0.0) == 1.0\n"
" ```\n"
"\n"
" ```gleam\n"
" assert exponential(1.0) == 2.718281828459045\n"
" ```\n"
"\n"
" ```gleam\n"
" assert exponential(-1.0) == 0.36787944117144233\n"
" ```\n"
).
-spec exponential(float()) -> float().
exponential(X) ->
math:exp(X).

Some files were not shown because too many files have changed in this diff Show More