1
1
mirror of https://github.com/tweag/nickel.git synced 2024-10-04 23:27:15 +03:00

Remove website

The website now lives in a separate repo:
https://github.com/tweag/nickel-lang.org.
This commit is contained in:
Mathieu Boespflug 2021-12-31 16:36:19 +02:00
parent cfb2821ff6
commit b7c4b34ef6
49 changed files with 0 additions and 50196 deletions

View File

@ -1,40 +0,0 @@
repository:
has_wiki: false
labels:
- name: "duplicate"
color: cfd3d7
- name: "good first issue"
color: 7057ff
- name: "invalid"
color: cfd3d7
- name: "more data needed"
color: bfdadc
- name: "P0"
color: b60205
description: "blocker: fix immediately!"
- name: "P1"
color: d93f0b
description: "critical: next release"
- name: "P2"
color: e99695
description: "major: an upcoming release"
- name: "P3"
color: fbca04
description: "minor: not priorized"
- name: "P4"
color: fef2c0
description: "unimportant: consider wontfix or other priority"
- name: "question"
color: d876e3
- name: "type: bug"
color: 0052cc
- name: "type: documentation"
color: 0052cc
- name: "type: feature request"
color: 0052cc
- name: "wontfix"
color: ffffff
- name: "merge-queue"
color: 0e8a16
description: "merge on green CI"

4
website/.gitignore vendored
View File

@ -1,4 +0,0 @@
node_modules/
.cache/
public
.idea

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) Tweag Holding and its affiliates.
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.

View File

@ -1,4 +0,0 @@
# Nickel-lang.org website
This repository contains the content of the Nickel language website. This is
WIP.

View File

@ -1,5 +0,0 @@
import "./src/styles/custom.scss";
import "jquery/dist/jquery.min.js";
import "popper.js/dist/popper.min";
import "bootstrap/dist/js/bootstrap.min.js";
import "./src/styles/global.css";

View File

@ -1,35 +0,0 @@
module.exports = {
siteMetadata: {
title: "Nickel",
menuLinks: [
{
name: 'Getting started',
link: '/getting-started'
},
// Disabling the documentation page for now.
// There is just not enough interesting content to show.
/*{
name: 'Documentation',
link: '/documentation'
},*/
{
name: 'Playground',
link: '/playground'
},
]
},
plugins: [
'gatsby-plugin-react-helmet',
'gatsby-plugin-sharp',
'gatsby-transformer-sharp',
'gatsby-plugin-image',
{
resolve: `gatsby-source-filesystem`,
options: {
name: `markdown-pages`,
path: `${__dirname}/src/markdown-pages`,
},
},
`gatsby-plugin-sass`,
],
};

View File

@ -1,8 +0,0 @@
exports.onCreateWebpackConfig = ({ _stage, actions, _loaders }) => {
actions.setWebpackConfig({
experiments: {
// This was necessary to have the Nickel WASM REPL work with Webpack
asyncWebAssembly: true,
},
})
};

View File

@ -1,29 +0,0 @@
[[redirects]]
from = "https://nickel-lang.netlify.com/*"
to = "https://nickel-lang.org/:splat"
status = 301
force = true
[[redirects]]
from = "http://nickel-lang.netlify.com/*"
to = "https://nickel-lang.org/:splat"
status = 301
force = true
[[redirects]]
from = "http://www.nickel-lang.org/*"
to = "https://nickel-lang.org/:splat"
status = 301
force = true
[[redirects]]
from = "https://www.nickel-lang.org/*"
to = "https://nickel-lang.org/:splat"
status = 301
force = true
[[redirects]]
from = "http://nickel-lang.org/*"
to = "https://nickel-lang.org/:splat"
status = 301
force = true

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) Tweag Holding and its affiliates.
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.

View File

@ -1,217 +0,0 @@
# Nickel
[![Continuous integration](https://github.com/tweag/nickel/workflows/Continuous%20integration/badge.svg)](https://github.com/tweag/nickel/actions?query=branch%3Amaster)
Nickel is the cheap configuration language.
Its purpose is to automate the generation of static configuration files - think
JSON, YAML, XML, or your favorite data representation language - that are then
fed to another system. It is designed to have a simple, well-understood core: it
is in essence JSON with functions.
Nickel's salient traits are:
- **Lightweight**: Nickel is easy to embed. An interpreter should be simple to
implement. The reference interpreter can be called from many programming
languages.
- **Composable code**: the basic building blocks for computing are functions.
They are first-class citizens, which can be passed around, called and
composed.
- **Composable data**: the basic building blocks for data are records
(called *objects* in JSON). In Nickel, records can be merged at will,
including associated metadata (documentation, default values, type
contracts, etc).
- **Typed, but only when it helps**: static types improve code quality, serve as
documentation and eliminate bugs early. But application-specific
self-contained code will always evaluate to the same value, so type errors
will show up at runtime anyway. Some JSON is hard to type. There, types are
only a burden. Whereas reusable code - that is, *functions* - is evaluated
on potentially infinitely many different inputs, and is impossible to test
exhaustively. There, types are precious. Nickel has types, but you get to
choose when you want it or not, and it handles safely the interaction between
the typed and the untyped world.
- **Design by contract**: complementary to the type system, contracts are
a principled approach to checking assertions. The interpreter automatically
inserts assertions at the boundary between typed and untyped code. Nickel
lets users add arbitrary assertions of their own and easily understand why
when assertions fail.
The motto guiding Nickel's design is:
> Great defaults, design for extensibility
There should be a standard, clear path for common things. There should be no
arbitrary restrictions that limit what you can do you the one day you need to go
beyond.
## Use cases
Nickel is a good fit in any situation where you need to generate a complex
configuration, be it for a single app, a machine, whole infrastructure, or a
build system.
The motivating use cases are in particular:
- The [Nix package manager](https://nixos.org/): Nix is a declarative package
manager using its own language for specifying packages. Nickel is an
evolution of the Nix language, while trying to overcome some of its
limitations.
- Infrastructure as code: infrastructure is becoming increasingly complex,
requiring a rigorous approach to deployment, modification and configuration.
This is where a declarative approach also shines, as adopted by
[Terraform](https://www.terraform.io/),
[NixOps](https://github.com/NixOS/nixops) or
[Kubernetes](https://kubernetes.io/), all requiring potentially complex
generation of configuration.
- Build systems: build systems (like [Bazel](https://bazel.build/)) need
a specification of the dependency graph.
Most aforementioned projects have their own bespoke configuration language. See
[Related projects and inspirations](#Related-projects-and-inspirations). In
general, application-specific languages might suffer from feature creep, lack of
abstractions or just feel ad hoc. Nickel buys you more for less.
## Getting started
### Run
1. Start Nickel
* with [flake-enabled](https://nixos.wiki/wiki/Flakes) Nix directly
with `nix run nickel` (which pulls it from the global flakes
registry), or with `nix run github:tweag/nickel` (which pulls it
from the repo). You can use [our binary cache](https://nickel.cachix.org) to
prevent rebuilding a lot of packages. You pass in arguments with
an extra `--` as in `nix run nickel -- repl`,
* with `./nickel`, after [building](#Build) this repo, depending on the
location of the executable and passing in arguments directly,
* or with `cargo run` after [building](#Build), passing in arguments with
an extra `--` as in `cargo run -- -f program.ncl`.
2. Run your first program:
```console
$ ./nickel <<< 'let x = 2 in x + x'
Typechecked: Ok(Types(Dyn))
Done: Num(4.0)
```
Or load it from a file:
```console
$ echo 'let s = "world" in "Hello, " ++ s' > program.ncl
$ ./nickel -f program.ncl
Typechecked: Ok(Types(Dyn))
Done: Str("Hello, world")
```
3. Start a REPL:
```console
$ ./nickel repl
nickel> let x = 2 in x + x
4
nickel>
```
Use `:help` for a list of available commands.
4. Export your configuration to JSON, YAML or TOML:
```console
$ ./nickel export --format json <<< '{foo = "Hello, world!"}'
{
"foo": "Hello, world!"
}
```
Use `nickel help` for a list of subcommands, and `nickel help <subcommand>`
for help about a specific subcommand.
### Build
[rust-guide]: https://doc.rust-lang.org/cargo/getting-started/installation.html
1. Download build dependencies:
- **With Nix**: If you have [Nix](https://nixos.org/nix) installed:
```console
$ nix-shell shell.nix
```
to be dropped in a shell, ready to build. You can use [our binary
cache](https://nickel.cachix.org) to prevent rebuilding a lot of
packages.
- **Without Nix**: otherwise, follow [this guide][rust-guide] to install Rust
and Cargo first.
2. Build Nickel:
```console
$ cargo build
```
And voilà! Generated files are placed in `target/debug`.
1. *(optional)* make a symbolic link to the executable:
```console
$ ln -S nickel target/debug/nickel
```
### Tests
```console
$ cargo test
```
### Documentation
1. Build the doc:
```console
$ cargo doc --no-deps
```
2. Open the file `target/doc/nickel/index.html` in your browser.
### Examples
You can find examples in
the [`./examples`](./examples) directory. Note
that as the syntax is not yet fixed, and some basic helpers are missing, they
may seem a bit alien currently.
## Roadmap
The design is settled and implemented for the most part, but the final syntax
and other important practical aspects are still being debated. We aim to
transition from an experimental stage to a minimum viable product stage. The
next points to deal with are:
- [Stdlib stabilization](https://github.com/tweag/nickel/issues/321)
- [Overriding](https://github.com/tweag/nickel/pull/330)
- Memory management (use reference counting) & basic performance improvements
- [List comprehensions](https://github.com/tweag/nickel/issues/80)
- [Destructuring](https://github.com/tweag/nickel/issues/81)
## Related projects and inspirations
- [Cue](https://cuelang.org/) is a configuration language with a focus on data
validation. It introduces a new constraint system backed by a solid theory
which ensures strong guarantees about your code. It allows for very elegant
schema specifications. In return, the cost to pay is to abandon functions
and
[Turing-completeness](https://en.wikipedia.org/wiki/Turing_completeness).
Nickel's merge system is inspired by the one of CUE, even if since Nickel
does have general functions and is Turing-complete, they are necessarily
different.
- [Nix](https://nixos.org/): The Nix language, or *Nix expressions*, is one of
the main inspirations for Nickel. It is a very simple yet powerful lazy
functional language. We strive to retain this simplicity, while adding
typing capabilities, modularity, and detaching the language from the Nix
package manager.
- [Dhall](https://dhall-lang.org/) is a statically typed configuration language.
It is also inspired by Nix, to which it adds a powerful static type system.
However, this forces the programmer to annotate all of their code with types.
- [Jsonnet](https://jsonnet.org/) is another language which could be dubbed as
"JSON with functions" (and others things as well). It is a lazy functional
language with object oriented features, among which inheritance is similar
to Nickel's merge system. One big difference with Nickel is the absence of
typing.
- [Pulumi](https://www.pulumi.com/) is not a language in itself, but a cloud
tool (like Terraform) where you can use your preferred language for
describing your infrastructure. This is a different approach to the problem,
with different trade-offs.
- [Starlark](https://docs.bazel.build/versions/master/skylark/language.html) is
the language of [Bazel](https://bazel.build/), which is a dialect of
[Python](https://www.python.org/). It does not have types and recursion is
forbidden, making it not Turing-complete.
See [RATIONALE.md](./RATIONALE.md) for the design rationale and a more detailed
comparison with a selection of these languages.

View File

@ -1,77 +0,0 @@
/* tslint:disable */
/* eslint-disable */
/**
* Return a new instance of the WASM REPL, with the standard library loaded.
* @returns {WasmInitResult}
*/
export function repl_init(): WasmInitResult;
/**
* Evaluate an input in the WASM REPL.
* @param {ReplState} state
* @param {string} line
* @returns {WasmInputResult}
*/
export function repl_input(state: ReplState, line: string): WasmInputResult;
/**
* Evaluate an input in the WASM REPL and serialize it.
* @param {ReplState} state
* @param {any} format
* @param {string} line
* @returns {WasmInputResult}
*/
export function repl_serialize(state: ReplState, format: any, line: string): WasmInputResult;
/**
* Return codes of the WASM REPL.
*
* wasm-bindgen doesn't support exporting arbitrary enumeration. Thus we have to encode these
* enums as structures with a tag and values. The values that are actually set depend on the
* tag.
*/
export enum WasmResultTag {
Success,
Blank,
Partial,
Error,
}
/**
* WASM-compatible wrapper around `ReplImpl`.
*/
export class ReplState {
free(): void;
}
/**
* WASM wrapper for the result type of the initialization of the REPL.
*/
export class WasmInitResult {
free(): void;
/**
* @returns {ReplState}
*/
repl(): ReplState;
/**
* @returns {string}
*/
readonly msg: string;
/**
* @returns {number}
*/
tag: number;
}
/**
* WASM wrapper for the result type of an execution of the REPL.
*/
export class WasmInputResult {
free(): void;
/**
* @returns {any}
*/
readonly errors: any;
/**
* @returns {string}
*/
readonly msg: string;
/**
* @returns {number}
*/
tag: number;
}

View File

@ -1,2 +0,0 @@
import * as wasm from "./nickel_bg.wasm";
export * from "./nickel_bg.js";

View File

@ -1,340 +0,0 @@
import * as wasm from './nickel_bg.wasm';
const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;
let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
let cachegetUint8Memory0 = null;
function getUint8Memory0() {
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachegetUint8Memory0;
}
function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
const heap = new Array(32).fill(undefined);
heap.push(undefined, null, true, false);
let heap_next = heap.length;
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
function getObject(idx) { return heap[idx]; }
function dropObject(idx) {
if (idx < 36) return;
heap[idx] = heap_next;
heap_next = idx;
}
function takeObject(idx) {
const ret = getObject(idx);
dropObject(idx);
return ret;
}
let WASM_VECTOR_LEN = 0;
const lTextEncoder = typeof TextEncoder === 'undefined' ? (0, module.require)('util').TextEncoder : TextEncoder;
let cachedTextEncoder = new lTextEncoder('utf-8');
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
? function (arg, view) {
return cachedTextEncoder.encodeInto(arg, view);
}
: function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
});
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length);
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len);
const mem = getUint8Memory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3);
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
const ret = encodeString(arg, view);
offset += ret.written;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
function isLikeNone(x) {
return x === undefined || x === null;
}
let cachegetInt32Memory0 = null;
function getInt32Memory0() {
if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) {
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
}
return cachegetInt32Memory0;
}
/**
* Return a new instance of the WASM REPL, with the standard library loaded.
* @returns {WasmInitResult}
*/
export function repl_init() {
var ret = wasm.repl_init();
return WasmInitResult.__wrap(ret);
}
function _assertClass(instance, klass) {
if (!(instance instanceof klass)) {
throw new Error(`expected instance of ${klass.name}`);
}
return instance.ptr;
}
/**
* Evaluate an input in the WASM REPL.
* @param {ReplState} state
* @param {string} line
* @returns {WasmInputResult}
*/
export function repl_input(state, line) {
_assertClass(state, ReplState);
var ptr0 = passStringToWasm0(line, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
var ret = wasm.repl_input(state.ptr, ptr0, len0);
return WasmInputResult.__wrap(ret);
}
/**
* Evaluate an input in the WASM REPL and serialize it.
* @param {ReplState} state
* @param {any} format
* @param {string} line
* @returns {WasmInputResult}
*/
export function repl_serialize(state, format, line) {
_assertClass(state, ReplState);
var ptr0 = passStringToWasm0(line, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
var ret = wasm.repl_serialize(state.ptr, addHeapObject(format), ptr0, len0);
return WasmInputResult.__wrap(ret);
}
/**
* Return codes of the WASM REPL.
*
* wasm-bindgen doesn't support exporting arbitrary enumeration. Thus we have to encode these
* enums as structures with a tag and values. The values that are actually set depend on the
* tag.
*/
export const WasmResultTag = Object.freeze({ Success:0,"0":"Success",Blank:1,"1":"Blank",Partial:2,"2":"Partial",Error:3,"3":"Error", });
/**
* WASM-compatible wrapper around `ReplImpl`.
*/
export class ReplState {
static __wrap(ptr) {
const obj = Object.create(ReplState.prototype);
obj.ptr = ptr;
return obj;
}
__destroy_into_raw() {
const ptr = this.ptr;
this.ptr = 0;
return ptr;
}
free() {
const ptr = this.__destroy_into_raw();
wasm.__wbg_replstate_free(ptr);
}
}
/**
* WASM wrapper for the result type of the initialization of the REPL.
*/
export class WasmInitResult {
static __wrap(ptr) {
const obj = Object.create(WasmInitResult.prototype);
obj.ptr = ptr;
return obj;
}
__destroy_into_raw() {
const ptr = this.ptr;
this.ptr = 0;
return ptr;
}
free() {
const ptr = this.__destroy_into_raw();
wasm.__wbg_wasminitresult_free(ptr);
}
/**
* @returns {number}
*/
get tag() {
var ret = wasm.__wbg_get_wasminitresult_tag(this.ptr);
return ret >>> 0;
}
/**
* @param {number} arg0
*/
set tag(arg0) {
wasm.__wbg_set_wasminitresult_tag(this.ptr, arg0);
}
/**
* @returns {string}
*/
get msg() {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.wasminitresult_msg(retptr, this.ptr);
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
return getStringFromWasm0(r0, r1);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
wasm.__wbindgen_free(r0, r1);
}
}
/**
* @returns {ReplState}
*/
repl() {
const ptr = this.__destroy_into_raw();
var ret = wasm.wasminitresult_repl(ptr);
return ReplState.__wrap(ret);
}
}
/**
* WASM wrapper for the result type of an execution of the REPL.
*/
export class WasmInputResult {
static __wrap(ptr) {
const obj = Object.create(WasmInputResult.prototype);
obj.ptr = ptr;
return obj;
}
__destroy_into_raw() {
const ptr = this.ptr;
this.ptr = 0;
return ptr;
}
free() {
const ptr = this.__destroy_into_raw();
wasm.__wbg_wasminputresult_free(ptr);
}
/**
* @returns {number}
*/
get tag() {
var ret = wasm.__wbg_get_wasminputresult_tag(this.ptr);
return ret >>> 0;
}
/**
* @param {number} arg0
*/
set tag(arg0) {
wasm.__wbg_set_wasminputresult_tag(this.ptr, arg0);
}
/**
* @returns {string}
*/
get msg() {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.wasminputresult_msg(retptr, this.ptr);
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
return getStringFromWasm0(r0, r1);
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
wasm.__wbindgen_free(r0, r1);
}
}
/**
* @returns {any}
*/
get errors() {
var ret = wasm.wasminputresult_errors(this.ptr);
return takeObject(ret);
}
}
export function __wbindgen_json_parse(arg0, arg1) {
var ret = JSON.parse(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
export function __wbindgen_object_drop_ref(arg0) {
takeObject(arg0);
};
export function __wbindgen_object_clone_ref(arg0) {
var ret = getObject(arg0);
return addHeapObject(ret);
};
export function __wbindgen_string_get(arg0, arg1) {
const obj = getObject(arg1);
var ret = typeof(obj) === 'string' ? obj : undefined;
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
export function __wbindgen_throw(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};

Binary file not shown.

View File

@ -1,21 +0,0 @@
/* tslint:disable */
/* eslint-disable */
export const memory: WebAssembly.Memory;
export function __wbg_wasminitresult_free(a: number): void;
export function __wbg_get_wasminitresult_tag(a: number): number;
export function __wbg_set_wasminitresult_tag(a: number, b: number): void;
export function wasminitresult_msg(a: number, b: number): void;
export function wasminitresult_repl(a: number): number;
export function __wbg_wasminputresult_free(a: number): void;
export function __wbg_get_wasminputresult_tag(a: number): number;
export function __wbg_set_wasminputresult_tag(a: number, b: number): void;
export function wasminputresult_msg(a: number, b: number): void;
export function wasminputresult_errors(a: number): number;
export function __wbg_replstate_free(a: number): void;
export function repl_init(): number;
export function repl_input(a: number, b: number, c: number): number;
export function repl_serialize(a: number, b: number, c: number, d: number): number;
export function __wbindgen_malloc(a: number): number;
export function __wbindgen_realloc(a: number, b: number, c: number): number;
export function __wbindgen_add_to_stack_pointer(a: number): number;
export function __wbindgen_free(a: number, b: number): void;

View File

@ -1,17 +0,0 @@
{
"name": "nickel-repl",
"collaborators": [
"Nicl team"
],
"description": "Programmable configuration files.",
"version": "0.1.0",
"license": "MIT OR Apache-2.0",
"files": [
"nickel_bg.wasm",
"nickel.js",
"nickel.d.ts"
],
"module": "nickel.js",
"types": "nickel.d.ts",
"sideEffects": false
}

47479
website/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +0,0 @@
{
"name": "nickel-lang.org",
"version": "1.0.0",
"private": true,
"description": "nickel-lang.org",
"author": "Yann Hamdaoui",
"keywords": [
"gatsby"
],
"scripts": {
"develop": "gatsby develop",
"start": "gatsby develop",
"build": "gatsby build",
"serve": "gatsby serve",
"clean": "gatsby clean"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.35",
"@fortawesome/free-brands-svg-icons": "^5.15.3",
"@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/react-fontawesome": "^0.1.14",
"@loadable/component": "^5.15.0",
"ace-builds": "^1.4.12",
"ansi-to-react": "^6.1.5",
"bootstrap": "^4.6.0",
"create-react-class": "^15.7.0",
"gatsby": "^3.2.1",
"gatsby-plugin-fontawesome-css": "^1.1.0",
"gatsby-plugin-image": "^1.3.0",
"gatsby-plugin-react-helmet": "^4.3.0",
"gatsby-plugin-sass": "^4.8.0",
"gatsby-plugin-sharp": "^3.3.0",
"gatsby-remark-prismjs": "^5.0.0",
"gatsby-source-filesystem": "^3.3.0",
"gatsby-transformer-sharp": "^3.3.0",
"jquery": "^3.6.0",
"nickel-repl": "file:nickel-repl",
"popper.js": "^1.16.1",
"prismjs": "^1.23.0",
"react": "^17.0.1",
"react-ace": "^9.4.0",
"react-bootstrap": "^1.5.2",
"react-bootstrap-icons": "^1.5.0",
"react-dom": "^17.0.1",
"react-helmet": "^6.1.0",
"sass": "^1.35.1"
}
}

View File

@ -1,158 +0,0 @@
/**
* Define a Nickel mode in the ace editor. This enables syntax highlighting for the Nickel language.
*/
import ace from "ace-builds/src-noconflict/ace";
ace.define('ace/mode/nickel_highlight_rules', ['require', 'exports', 'ace/lib/oop', 'ace/mode/text_highlight_rules'], function (_require, exports, _module) {
const oop = ace.require("ace/lib/oop");
const TextHighlightRules = ace.require("ace/mode/text_highlight_rules").TextHighlightRules;
const NickelHighlightRules = function () {
const constantLanguage = "true|false|null";
const keywordControl = "switch|import|if|else|then";
const keywordDeclaration = "let|in";
const keywordMetavalue = "doc|default";
const keywordMapper = this.createKeywordMapper({
"constant.language.nickel": constantLanguage,
"keyword.control.nickel": keywordControl,
"keyword.declaration.nickel": keywordDeclaration,
'keyword.metavalue.nickel': keywordMetavalue,
}, "identifier");
// Although Ace supports modal lexing (the next, push and pop rules allow to
// maintain a state and a stack), we can't encode nickel
// variable-length delimiter directly with one nice generic rule.
//
// We thus generate a rule for lengths 1, 2 and 3 (m#", m##", and m###")
// plus write a generic rule for size n. The generic rule is wrong for
// length 5 and above, but this is highly unlikely to be used in
// practice.
// Generate the starting rule of a string with variable-length
// delimiters
let genQqdoc = length => ({
token: "string",
regex: `m${'#'.repeat(length)}"`,
next: `qqdoc${length}`,
});
// Generate the escape and end rules of a string with variable-length delimiters
let genQqdocState = length => ({
[`qqdoc${length}`]: [
{
token: "constant.language.escape",
regex: `${'#'.repeat(length)}{`,
push: "start",
}, {
token: "string",
regex: `"${'#'.repeat(length)}m`,
next: "pop",
}, {
defaultToken: "string"
}]
});
this.$rules = {
"start": [{
token: "comment",
regex: /\/\/.*$/
}, {
regex: "(==|!=|<=?|>=?)",
token: ["keyword.operator.comparison.nickel"]
}, {
regex: "(\\+\\+|@)",
token: ["keyword.operator.combinator.nickel"]
}, {
regex: "(#|->|:)",
token: ["keyword.operator.type.nickel"]
}, {
regex: "=",
token: "keyword.operator.assignment.nickel"
},
{
token: "string",
regex: "\"",
next: "qqstring",
},
{
token: "string",
regex: "m(#{4,})\"",
next: "qqdocn"
},
genQqdoc(1),
genQqdoc(2),
genQqdoc(3), {
token: "constant.numeric", // hex
regex: "0[xX][0-9a-fA-F]+\\b"
}, {
token: "constant.numeric", // float
regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token: keywordMapper,
regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
regex: "}",
token: function (_val, _start, stack) {
return stack[1] && stack[1].charAt(0) === "q" ? "constant.language.escape" : "text";
},
next: "pop"
}],
"qqdocn": [
{
token: "constant.language.escape",
regex: "#{4,}{",
push: "start"
}, {
token: "string",
regex: "\"(#{4,})m",
next: "pop"
}, {
defaultToken: "string"
}],
...genQqdocState(1),
...genQqdocState(2),
...genQqdocState(3),
"qqstring": [
{
token: "constant.language.escape",
regex: "#{",
push: "start"
}, {
token: "string",
regex: '"',
next: "pop"
}, {
defaultToken: "string"
}],
};
this.normalizeRules();
};
oop.inherits(NickelHighlightRules, TextHighlightRules);
exports.NickelHighlightRules = NickelHighlightRules;
});
ace.define("ace/mode/nickel",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/nickel_highlight_rules","ace/mode/folding/cstyle"], function (_require, exports, _module) {
const oop = ace.require("ace/lib/oop");
const TextMode = ace.require("ace/mode/text").Mode;
const NimHighlightRules = ace.require("ace/mode/nickel_highlight_rules").NickelHighlightRules;
const Mode = function () {
TextMode.call(this);
this.HighlightRules = NimHighlightRules;
this.$behaviour = this.$defaultBehaviour;
};
oop.inherits(Mode, TextMode);
(function () {
this.lineCommentStart = "//";
this.$id = "ace/mode/nickel";
}).call(Mode.prototype);
exports.Mode = Mode;
});

View File

@ -1,37 +0,0 @@
import React from "react";
import { Link } from "gatsby";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faGithub,
faTwitter
} from "@fortawesome/free-brands-svg-icons";
import {
faArrowUp,
faComments
} from '@fortawesome/free-solid-svg-icons';
const Footer = () => (
<footer className="bg-secondary text-center">
<div className="container pt-3">
<section>
<Link className="btn text-black btn-outline btn-floating m-1" to="https://twitter.com/nickel_lang" role="button"
><FontAwesomeIcon color="black" icon={faTwitter}/></Link>
<Link className="btn btn-outline btn-floating m-1" to="https://github.com/tweag/nickel" role="button"
><FontAwesomeIcon color="black" icon={faGithub}/></Link>
<Link className="btn btn-outline btn-floating m-1" to="https://github.com/tweag/nickel/discussions" role="button"
><FontAwesomeIcon color="black" icon={faComments}/></Link>
<Link className="btn btn-outline-dark btn-floating m-1 ml-4" to="#" role="button"
><FontAwesomeIcon color="black" icon={faArrowUp}/></Link>
</section>
</div>
<hr/>
<div className="text-center pb-3">
© 2021 Copyright: <Link to={'https://github.com/tweag/nickel/graphs/contributors'} className={'link-footer'}>Nickel contributors</Link>
</div>
</footer>
)
export default Footer

View File

@ -1,30 +0,0 @@
import React from "react"
import { Link } from "gatsby"
import {StaticImage} from "gatsby-plugin-image";
const Header = ({ menuLinks }) => (
<header>
<nav className="navbar navbar-expand-md navbar-light bg-primary">
<div className="container-fluid">
<Link className="navbar-brand flex-md-fill w-md-100" to="/">
<StaticImage className={"logo-navbar"} src="../images/nickel-logo-2.svg" alt="logo"/><span className="nickel">Nickel</span>
</Link>
<button className="navbar-toggler" type="button" data-toggle="collapse"
data-target="#navbarNavAltMarkup"
aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"/>
</button>
<div className="collapse navbar-collapse justify-content-center flex-fill w-100" id="navbarNavAltMarkup">
<div className="navbar-nav">
{menuLinks.map(link => (
<Link key={link.name} className="nav-link" activeClassName="active" to={link.link}>{link.name}</Link>
))}
</div>
</div>
<ul className={'d-none d-md-block w-100 justify-contend-end'}/>
</div>
</nav>
</header>
);
export default Header

View File

@ -1,42 +0,0 @@
import React from "react"
import {graphql, StaticQuery} from "gatsby"
import {Helmet} from "react-helmet"
import Header from "./header"
import Footer from "./footer"
export default function Layout({children}) {
return (
<StaticQuery
query={graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
menuLinks {
name
link
}
}
}
}
`}
render={data => (
<React.Fragment>
<Helmet
title={'Nickel'}
meta={[
{name: 'description', content: 'Sample'},
{name: 'keywords', content: 'sample, something'},
]}
>
</Helmet>
<Header menuLinks={data.site.siteMetadata.menuLinks}/>
<div>
{children}
</div>
<Footer/>
</React.Fragment>
)}
/>
)
}

View File

@ -1,31 +0,0 @@
import {lazy} from "@loadable/component";
import React from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faSpinner,
} from '@fortawesome/free-solid-svg-icons';
/**
* Wrapper around the Playground component to use it on the client side only (and not via server-side rendering).
* This is made necessary by the code editor, based on react-ace and ace-builds, which use `window` and don't seem to fully support SSR yet.
* @type {React.ForwardRefExoticComponent<React.PropsWithoutRef<{}> & React.RefAttributes<unknown>>}
*/
const LoadablePlayground = lazy(() => import("./playground/playground"));
export default function ClientSidePlayground(props) {
const isSSR = typeof window === "undefined";
return (
<>
{!isSSR && (
<React.Suspense fallback={
<div className={"text-center playground-loader mt-4"}>
Loading playground <span className={"ml-2"}><FontAwesomeIcon icon={faSpinner} size={"lg"} spin/></span>
</div>
}>
<LoadablePlayground {...props}/>
</React.Suspense>
)}
</>
);
}

View File

@ -1,184 +0,0 @@
import * as React from 'react';
import AceEditor from 'react-ace';
import nickelCodes from './nickel-codes'
import {PLAYGROUND_SEND_EVENT, EDITOR_SEND_EVENT, REPL_RUN_EVENT} from "./events";
import "ace-builds/src-noconflict/theme-solarized_dark";
import "../../ace-nickel-mode/ace-nickel-mode";
import ReactDOMServer from "react-dom/server";
import {wrapPageElement} from "gatsby/dist/utils/api-browser-docs";
import modes from "./modes";
/**
* Nickel code editor component, based on the Ace editor.
*/
export default class Editor extends React.Component {
constructor(props) {
super(props);
this.state = {
value: this.props.value,
name: this.props.name,
placeholder: 'Write your code. Press Ctrl+Enter (Cmd+Enter) to run it',
theme: "solarized_dark",
mode: "nickel",
height: "100%",
width: "100%",
enableBasicAutocompletion: false,
enableLiveAutocompletion: false,
fontSize: 14,
showGutter: true,
showPrintMargin: true,
highlightActiveLine: true,
enableSnippets: false,
showLineNumbers: true,
annotations: [],
wrapEnabled: true,
};
if(this.props.fit && this.props.fit === 'code') {
// Taking more lines to account for potential wrapping
const lines = this.props.value.split(/\r?\n/g).length+2;
this.state.maxLines = lines;
this.state.minLines = lines;
}
else if(this.props.fit && this.props.fit === 'lines' && this.props.lines) {
this.state.maxLines = this.props.lines;
this.state.minLines = this.props.lines;
}
this.onChange = this.onChange.bind(this);
this.onREPLRun = this.onREPLRun.bind(this);
this.send = this.send.bind(this);
this.aceEditorRef = React.createRef();
}
static defaultProps = {
value: `let data = {value = "Hello," ++ " world!"} in data.value`,
name: 'nickel-repl-input',
};
componentDidMount() {
// Listen to the REPL's execution events, in order to update potential error messages.
document.addEventListener(REPL_RUN_EVENT, this.onREPLRun);
document.addEventListener(PLAYGROUND_SEND_EVENT, this.send);
if(this.props.onResize) {
const ro = new ResizeObserver(entries => {
for(let entry of entries) {
this.props.onResize(entry.target.clientHeight);
}
});
ro.observe(document.getElementById(this.state.name));
}
}
onChange(newValue) {
this.setState({
value: newValue
});
}
getHeight() {
return document.getElementById(this.state.name).clientHeight;
}
/**
* Static component displaying a Nickel diagnostic error.
* @param diagnostic
* @param label
* @returns {*}
*/
annotationWidget(diagnostic, label) {
const labelClass = label.style === nickelCodes.error.label.PRIMARY ? 'ansi-red-fg' : 'ansi-blue-fg';
return (<div>
<span className={"ansi-bright-red-fg"}>{diagnostic.msg}</span><br/>
<span className={labelClass}>{label.msg}</span><br/>
<ul>
{diagnostic.notes.map(note => <li>{note}</li>)}
</ul>
</div>)
}
/**
* Once the REPL has run, update the error messages.
* @param result
*/
onREPLRun({detail: result}) {
if (result.tag === nickelCodes.result.ERROR) {
const annotations = result.errors.filter(diagnostic => diagnostic.severity >= nickelCodes.error.severity.WARNING)
.map(diagnostic => (
diagnostic.labels.map(label => ({
row: label.line_start,
column: label.col_start,
html: ReactDOMServer.renderToStaticMarkup(this.annotationWidget(diagnostic, label)),
type: label.style === nickelCodes.error.label.PRIMARY ? 'error' : 'warning',
}))
)).flat();
// In some obscure circumstances (annotation on the last line, and then insertion of a new line), annotations disappear, even if the user send the same input again.
// To avoid this and make annotations reappear at least when sending an input, we clear the old one first, to triggers reactive updates.
this.setState({annotations: []}, () => this.setState({annotations}));
} else {
this.setState({annotations: []});
}
}
/**
* Dispatch an EDITOR_SEND_EVENT with the current content as a payload.
*/
send() {
// Dispatch the result as an event, so that the editor or other components can react to the outcome of the last input
const event = new CustomEvent(EDITOR_SEND_EVENT, {detail: this.state.value});
document.dispatchEvent(event);
}
render() {
const setEditorMargin = (editor) => {
editor.renderer.setPadding(10);
editor.renderer.setScrollMargin(10, 10, 0, 0);
};
return <AceEditor
ref={this.aceEditorRef}
placeholder={this.state.placeholder}
mode={this.state.mode}
theme={this.state.theme}
name={this.state.name}
height={this.state.height}
width={this.state.width}
minLines={this.state.minLines}
maxLines={this.state.maxLines}
onChange={this.onChange}
onSelectionChange={this.onSelectionChange}
onCursorChange={this.onCursorChange}
onValidate={this.onValidate}
value={this.state.value}
annotations={this.state.annotations}
fontSize={this.state.fontSize}
showPrintMargin={this.state.showPrintMargin}
showGutter={this.state.showGutter}
highlightActiveLine={this.state.highlightActiveLine}
wrapEnabled={this.state.wrapEnabled}
onLoad={setEditorMargin}
commands={[
{
name: 'send-repl',
bindKey: {
win: 'Ctrl-enter',
mac: 'Cmd-enter',
},
exec: this.send,
},
]}
setOptions={{
useWorker: false,
enableBasicAutocompletion: this.state.enableBasicAutocompletion,
enableLiveAutocompletion: this.state.enableLiveAutocompletion,
enableSnippets: this.state.enableSnippets,
showLineNumbers: this.state.showLineNumbers,
tabSize: 2
}}
/>;
}
}

View File

@ -1,18 +0,0 @@
/**
* The user request the execution of the current snippet (by clicking the "Run" button, or using the corresponding shortcut).
* @type {string}
*/
const PLAYGROUND_SEND_EVENT = 'playground:send';
/**
* The editor is sending a snippet for execution (by clicking the "Run" button, or usign the corresponding shortcut). Editor listens to `PLAYGROUND_SEND_EVENT`,
* and dispatch `EDITOR_SEND_ENVENT`. The payload (field `detail` of the event) contains the input as a string.
* @type {string}
*/
const EDITOR_SEND_EVENT = 'nickel-repl:send';
/**
* The REPL has run a snippet and returned. The `details`
* @type {string}
*/
const REPL_RUN_EVENT = 'nickel-repl:run';
export {PLAYGROUND_SEND_EVENT, EDITOR_SEND_EVENT, REPL_RUN_EVENT};

View File

@ -1,12 +0,0 @@
/**
* The different execution modes of the REPL component.
* @type {{REPL: string, JSON: string, TOML: string, YAML: string}}
*/
const modes = {
REPL: 'repl',
JSON: 'json',
TOML: 'toml',
YAML: 'yaml',
};
export default modes;

View File

@ -1,27 +0,0 @@
/**
* Codes returned by the Nickel WASM evaluator.
* @type {{result: {BLANK: number, SUCCESS: number, PARTIAL: number, ERROR: number}, error: {severity: {HELP: number, BUG: number, NOTE: number, ERROR: number, WARNING: number}, label: {SECONDARY: number, PRIMARY: number}}}}
*/
const nickelCodes = {
result: {
SUCCESS: 0,
BLANK: 1,
PARTIAL: 2,
ERROR: 3,
},
error: {
severity: {
HELP: 1,
NOTE: 2,
WARNING: 3,
ERROR: 4,
BUG: 5,
},
label: {
PRIMARY: 0,
SECONDARY: 1,
}
}
};
export default nickelCodes;

View File

@ -1,98 +0,0 @@
import * as React from 'react';
import Editor from "./editor";
import Repl from "./repl";
import modes from "./modes";
import {PLAYGROUND_SEND_EVENT} from "./events.js";
import {Command} from 'react-bootstrap-icons';
/**
* Playground component, composed of both a code editor and a REPL component.
*/
export default class Playground extends React.Component {
constructor(props) {
super(props);
this.state = {mode: this.props.mode};
this.setMode = this.setMode.bind(this);
this.dispatchSendEvent = this.dispatchSendEvent.bind(this);
if(this.props.fit === 'code' || this.props.fit === 'lines') {
// In fit-to-code mode, fix the height of the output (terminal) element to the height of the current code
this.onEditorResize = (height) => {
if(this.terminalContainer) {
this.terminalContainer.style.height = height + "px";
}
else {
setTimeout(this.onEditorResize, 100)
}
}
}
}
componentDidMount() {
// If a program was provided initially, run it.
if(this.props.value) {
this.editor.send();
}
}
static defaultProps = {
mode: modes.REPL,
fit: 'page',
};
setTerminalContainer = element => this.terminalContainer = element;
setEditor = editor => this.editor = editor;
replTabStyle = (mode) => ('nav-link link-secondary playground-nav-item' + (this.state.mode === mode ? ' active' : ''));
setMode = (mode) => {
this.setState({mode});
};
dispatchSendEvent = () => {
const event = new CustomEvent(PLAYGROUND_SEND_EVENT);
document.dispatchEvent(event);
};
render() {
return <React.Fragment>
<div className={"row"}>
<div className={"col-6 playground-tab d-flex align-items-center"}>
<div>
<button className={"btn btn-primary"} onClick={() => this.dispatchSendEvent()}>Run</button>
<span className={'ml-4'}> or press</span> <kbd>Ctrl</kbd>+<kbd>Enter</kbd> or <kbd>Cmd <Command/>
</kbd>+<kbd>Enter</kbd>
</div>
</div>
<ul className={"col-6 nav nav-pills playground-tab"}>
<li className="nav-item">
<a className={this.replTabStyle(modes.REPL)} onClick={() => this.setMode(modes.REPL)}>REPL</a>
</li>
<li className="nav-item">
<a className={this.replTabStyle(modes.JSON)} onClick={() => this.setMode(modes.JSON)}>JSON</a>
</li>
<li className="nav-item">
<a className={this.replTabStyle(modes.YAML)} onClick={() => this.setMode(modes.YAML)}>YAML</a>
</li>
<li className="nav-item">
<a className={this.replTabStyle(modes.TOML)} onClick={() => this.setMode(modes.TOML)}>TOML</a>
</li>
</ul>
</div>
<section className={'row playground-container overflow-hidden flex-grow-1'}>
<div className={'col-6'}>
<Editor ref={this.setEditor} fit={this.props.fit} lines={this.props.lines} value={this.props.value} onResize={this.onEditorResize}/>
</div>
<div id={"playground-terminal-container"}
ref={this.setTerminalContainer}
className={'col-6 ansi-monokai playground-terminal-container'}>
<Repl containerId={"playground-terminal-container"} className={'playground-terminal'}
mode={this.state.mode}/>
</div>
</section>
</React.Fragment>
}
}

View File

@ -1,179 +0,0 @@
import * as React from 'react';
import {repl_init, repl_input, repl_serialize} from "nickel-repl";
import Ansi from "ansi-to-react";
import {EDITOR_SEND_EVENT, REPL_RUN_EVENT} from "./events";
import modes from './modes';
import nickelCodes from './nickel-codes';
/**
* An REPL. This component can run Nickel programs or REPL commands and display a stylized output.
*/
export default class Repl extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
lastInput: '',
// Output displayed in REPL mode. It is appended to at each run.
output_repl: "Nickel Online REPL | Welcome to the Nickel online REPL.\n"
+ "See the output of your snippets here.\n\n",
// Output displayed in serialize mode. Cleared at each new run.
output_serialize: '',
};
this.endRef = React.createRef();
}
static defaultProps = {
mode: modes.REPL
};
/**
* Return the current REPL output as an array of lines.
* @returns {string[]}
*/
lines() {
return this.state.output_repl.split(/\r?\n/g);
}
componentDidMount() {
const result = repl_init();
if (result.tag === nickelCodes.result.ERROR) {
this.write(`Initialization error: ${result.msg}\n`);
} else {
// /!\ WARNING: result is moved by the Rust code when calling to the repl() method. Do not use or copy result after this call to repl().
this.repl = result.repl();
this.prompt();
}
document.addEventListener(EDITOR_SEND_EVENT, this.onSend.bind(this))
}
/**
* Write text. Newlines and ANSI escape codes are converted to HTML before rendering.
* In serialize mode, the new output erase the old content. In REPL mode, the new output is appended to.
* Because state updates are asynchronous, this returns a Promise that resolves when everything is up to date.
* @param data String
* @returns {Promise<unknown>}
*/
write(data) {
return new Promise(resolve => {
if (this.props.mode === modes.REPL) {
this.setState({output_repl: this.state.output_repl + data}, resolve);
} else {
this.setState({output_serialize: data}, resolve);
}
}
);
}
/**
* Clear the output.
* @returns {Promise<unknown>}
*/
clear() {
return new Promise(resolve => {
if (this.props.mode === modes.REPL) {
this.setState({output_repl: ''}, resolve);
} else {
this.setState({output_serialize: ''}, resolve);
}
}
).then(() => this.prompt());
}
/**
* Write a new line followed by a prompt, if in REPL mode. Do nothing otherwise.
* @returns {Promise<unknown>}
*/
prompt = () => {
if (this.props.mode === modes.REPL) {
return this.write('\n\u001b[32mnickel>\u001b[0m ');
}
};
/**
* Run it. In REPL mode, the input is also appended to the output.
* @param input String
*/
onSend = ({detail: input}) => {
if (this.props.mode === modes.REPL) {
return this.write(input).then(() => this.run(input));
} else {
return this.run(input);
}
};
/**
* Run an input and write the result in the output.
* @param input String
* @returns {Promise<number>} A promise resolving to the return code of the execution of the Nickel REPL, or -1 if the REPL wasn't loaded.
*/
run = (input) => {
if (this.repl === null) {
console.error("Terminal: REPL is not loaded (this.repl === null)");
return new Promise(resolve => resolve(-1));
}
this.setState({lastInput: input});
let result;
if (this.props.mode !== modes.REPL) {
result = repl_serialize(this.repl, this.props.mode, input);
}
else {
result = repl_input(this.repl, input);
}
let task;
if (this.props.mode === modes.REPL) {
task = this.write("\n" + result.msg).then(() => this.prompt());
} else {
//If there's an error, we run the original snippet in order to have a better error message.
if (result.tag === nickelCodes.result.ERROR) {
const resultAlone = repl_input(this.repl, this.state.lastInput);
// If there's no error for the original snippet alone, this may be a NonSerializable error. In this case,
// we keep the first error message.
if (resultAlone.tag === nickelCodes.result.ERROR) {
result = resultAlone;
}
}
task = this.write(result.msg);
}
// Dispatch the result as an event, so that the editor or other components can react to the outcome of the last input
const event = new CustomEvent(REPL_RUN_EVENT, {detail: result});
document.dispatchEvent(event);
return task.then(() => result.tag);
};
componentDidUpdate = (prevProps) => {
// If we switched mode to a serialization mode and there is a last input, we re-run the last input
if (this.props.mode !== prevProps.mode && this.props.mode !== modes.REPL && this.state.lastInput !== '') {
this.run(this.state.lastInput);
}
// Scroll to the last message
const terminalContainer = document.getElementById(this.props.containerId);
terminalContainer.scrollTop = terminalContainer.scrollHeight;
};
render() {
let content;
if (this.props.mode === modes.REPL) {
content = this.lines().map((line, index) => <div key={index}><Ansi useClasses>{line.toString()}</Ansi><br/>
</div>);
} else {
content = <Ansi useClasses>{this.state.output_serialize}</Ansi>;
}
return <div style={{whiteSpace: 'pre-wrap'}}>
{content}
<div ref={this.endRef}/>
</div>
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1 +0,0 @@
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 299.83 339.82"><defs><style>.cls-1{fill:#e0c3fc;}.cls-2{fill:#fff;}</style></defs><path class="cls-1" d="M1110.37,614.62V465.38a20.67,20.67,0,0,0-10.34-17.9L970.79,372.86a20.68,20.68,0,0,0-20.67,0L820.88,447.48a20.67,20.67,0,0,0-10.34,17.9V614.62a20.67,20.67,0,0,0,10.34,17.9l129.24,74.62a20.68,20.68,0,0,0,20.67,0L1100,632.52A20.67,20.67,0,0,0,1110.37,614.62Z" transform="translate(-810.54 -370.09)"/><path class="cls-2" d="M1023.14,509.09V511q0,34.5,0,69a2.31,2.31,0,0,1-1.57,2.53q-25.8,11.37-51.54,22.85c-.44.2-.89.37-1.5.62,0-.49-.1-.88-.1-1.28q0-35,0-70a1.77,1.77,0,0,1,1.2-2q26.14-11.55,52.27-23.18C1022.24,509.45,1022.59,509.32,1023.14,509.09Z" transform="translate(-810.54 -370.09)"/><path class="cls-2" d="M898.14,509.06l8.94,3.94q22,9.79,44.11,19.56a2.38,2.38,0,0,1,1.67,2.64q-.08,34.41,0,68.83v2c-.62-.24-1.11-.41-1.59-.62q-25.83-11.48-51.68-22.92a2.09,2.09,0,0,1-1.45-2.28q.06-34.66,0-69.33Z" transform="translate(-810.54 -370.09)"/><path class="cls-2" d="M1011.61,497.07l-23.47,10.42c-8.76,3.89-17.52,7.8-26.3,11.65a3.1,3.1,0,0,1-2.24.06q-24.45-10.77-48.86-21.66c-.25-.1-.48-.25-.91-.47a11.69,11.69,0,0,1,1.11-.67q24.27-10.78,48.56-21.54a3,3,0,0,1,2.1-.07q24.52,10.83,49,21.74C1010.84,496.63,1011.06,496.77,1011.61,497.07Z" transform="translate(-810.54 -370.09)"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1 +0,0 @@
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 299.09 338.96"><defs><style>.cls-1{fill:#3a3a3c;}.cls-2{fill:#e0c3fc;}</style></defs><path class="cls-1" d="M1110,614.41V465.59a20.68,20.68,0,0,0-10.34-17.9l-128.87-74.4a20.63,20.63,0,0,0-20.67,0l-128.88,74.4a20.69,20.69,0,0,0-10.33,17.9V614.41a20.69,20.69,0,0,0,10.33,17.9l128.88,74.4a20.63,20.63,0,0,0,20.67,0l128.87-74.4A20.68,20.68,0,0,0,1110,614.41Z" transform="translate(-810.91 -370.52)"/><path class="cls-2" d="M1023,509.16v1.9q0,34.41,0,68.83a2.31,2.31,0,0,1-1.56,2.53Q995.71,593.76,970,605.21c-.44.2-.89.37-1.5.62,0-.49-.1-.88-.1-1.28q0-34.9,0-69.8a1.77,1.77,0,0,1,1.19-2q26.1-11.52,52.15-23.12Z" transform="translate(-810.91 -370.52)"/><path class="cls-2" d="M898.29,509.14c3.12,1.37,6,2.64,8.92,3.93,14.67,6.51,29.32,13,44,19.51a2.39,2.39,0,0,1,1.66,2.63q-.07,34.34,0,68.67v2c-.62-.24-1.11-.41-1.58-.62q-25.77-11.44-51.56-22.87a2.07,2.07,0,0,1-1.44-2.27q0-34.58,0-69.15Z" transform="translate(-810.91 -370.52)"/><path class="cls-2" d="M1011.49,497.17l-23.42,10.4c-8.74,3.88-17.47,7.79-26.23,11.62a3.15,3.15,0,0,1-2.24.07q-24.39-10.75-48.74-21.61c-.25-.11-.48-.25-.9-.48.44-.26.75-.5,1.1-.66q24.21-10.77,48.45-21.49a3,3,0,0,1,2.09-.07q24.46,10.8,48.89,21.69C1010.72,496.74,1010.94,496.88,1011.49,497.17Z" transform="translate(-810.91 -370.52)"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -1,174 +0,0 @@
---
page: "getting-started"
---
# Getting started
Nickel is quite new and not yet distributed using the standard channels
(binaries, nix package, Rust crate, and so on). We are sorry if the installation
process is not yet optimal, but this should change soon, so stay tuned.
## Build from source using Nix
Using [Nix]("https://nixos.org/") is the easiest way to get a Nickel executable
running:
1. Clone the [Nickel repository](https://github.io/tweag/nickel)
locally and set it as the current directory:
```shell-session
$ git clone git@github.com:tweag/nickel.git
Cloning in 'nickel'...
[..]
$ cd nickel
devops@nickel-lang:~/nickel$
```
1. Invoke nix build:
```shell-session
devops@nickel-lang:~/nickel$ nix build
[1 built, 0.0 MiB DL]
devops@nickel-lang:~/nickel$
```
1. If everything went right, a binary is now available in the
result directory:
```shell-session
devops@nickel-lang:~/nickel$ ./result/bin/nickel -V
nickel 0.1.0
devops@nickel-lang:~/nickel$
```
## Build from source without Nix
You will find alternative ways to build Nickel from source by cloning the
[repository](href="https://github.io/tweag/nickel) and following the
instructions of the
[README](href="https://github.com/tweag/nickel/#getting-started").
## Write your first configuration
Nickel has a ton of cool features, like gradual typing, contracts and a merge
system. However, you'll only have to deal with them once you need them. Writing
basic configuration is almost as writing JSON or YAML. Let us start with a
basic fictional app configuration:
```nickel
{
name = "example",
description = m#"
This is an awesome software I'm developing.
Please use it!
"#m,
version = "0.1.1",
main = "index.js",
keywords = ["example", "config"],
scripts = {
test = m#"test.sh --option --install example --version "0.1.1""#m,
do_stuff = "do_stuff.sh subcommand",
},
contributors = [{
name = "John Doe",
email = "johndoe@example.com"
}, {
name = "Ivy Lane",
url = "https=//example.com/ivylane"
}],
dependencies = {
dep1 = "^1.0.0",
dep3 = "6.7"
}
}
```
This program describe a record delimited by `{` and `}`, consisting in a list of
key-value pairs, akin to JSON's objects. Nickel basic datatypes include strings
delimited by `"` and lists, by `[` and `]`.
The m#" and "#m delimits multiline strings. In such strings, the common
indentation prefix is stripped, and special characters (excepted
interpolation #{}) loose their meaning. It is useful for two purpose
illustrated here:
- Writing strings spanning multiple lines while keeping the same
indentation as code.
- Writing strings with special characters in it, without having to
escape them (", \, and so on).
## Export
Now, save the content in "example.ncl" and run nickel export (or
./result/bin/nickel export if you haven't made a symbolic link):
```shell-session
devops@nickel-lang:~/nickel$ nickel -f example.ncl export --format yaml
---
contributors:
- email: johndoe@example.com
name: John Doe
- name: Ivy Lane
url: https=//example.com/ivylane
dependencies:
dep1: ^1.0.0
dep3: "6.7"
description: "This is an awesome software I'm developing.\nPlease use it!"
keywords:
- example
- config
main: index.js
name: example
scripts:
do_stuff: do_stuff.sh subcommand
test: "test.sh --option --install example --version \"0.1.1\""
version: 0.1.1
```
Currently supported formats are yaml, toml, json, and raw. json is the
default, while raw expect a string result that it output directly, useful to
generate e.g. shell scripts or other custom data.
## Reuse
Nickel is a programming language. This allows you not only to describe, but to
generate data. There's some repetition in our previous example (reproducing only
the interesting part):
```nickel
name = "example",
version = "0.1.1",
scripts = {
test = m#"test.sh --option --install example --version "0.1.1""#m,
```
Apart from aesthetics, a more serious issue is inconsistency. If you bump the
version number in version, you may forget to do so in the test scripts as well,
leading to an incorrect configuration. To remedy this problem, let us have a
single source of truth by reusing the value of name and version in test, using
the interpolation syntax `#{expr}`:
```nickel
name = "example",
version = "0.1.1",
scripts = {
test = m#"test.sh --option --install #{name} --version "#{version}""#m
```
Now, if we change version to "0.1.2" and export the result, the test script
invocation is updated as well:
```yaml
# [...]
scripts:
do_stuff: do_stuff.sh subcommand
test: "test.sh --option --install example --version \"0.1.2\""
version: 0.1.2
```
## Going further
This was a short introduction that should get you started. But Nickel is a
full-fledged programming language, featuring higher-order functions, gradual
typing, contracts, and much more. You'll find more resources on the
[Documentation](/documentation) page.

View File

@ -1,54 +0,0 @@
import * as React from "react"
import { Link } from "gatsby"
// styles
const pageStyles = {
color: "#232129",
padding: "96px",
fontFamily: "-apple-system, Roboto, sans-serif, serif",
}
const headingStyles = {
marginTop: 0,
marginBottom: 64,
maxWidth: 320,
}
const paragraphStyles = {
marginBottom: 48,
}
const codeStyles = {
color: "#8A6534",
padding: 4,
backgroundColor: "#FFF4DB",
fontSize: "1.25rem",
borderRadius: 4,
}
// markup
const NotFoundPage = () => {
return (
<main style={pageStyles}>
<title>Not found</title>
<h1 style={headingStyles}>Page not found</h1>
<p style={paragraphStyles}>
Sorry{" "}
<span role="img" aria-label="Pensive emoji">
😔
</span>{" "}
we couldnt find what you were looking for.
<br />
{process.env.NODE_ENV === "development" ? (
<>
<br />
Try creating a page in <code style={codeStyles}>src/pages/</code>.
<br />
</>
) : null}
<br />
<Link to="/">Go home</Link>.
</p>
</main>
)
}
export default NotFoundPage

View File

@ -1,30 +0,0 @@
import * as React from "react"
import Layout from "../components/layout"
import { Link } from "gatsby"
const IndexPage = () => {
return (
<Layout>
<main className="container main-container">
<div className="row">
<h1 className="main-title col-12">Documentation</h1>
<div className="mt-4 col-12">
<div className="list-group">
<Link to="https://github.com/tweag/nickel/#readme" className="list-group-item list-group-item-action">The
Nickel README</Link>
<Link to="https://github.com/tweag/nickel/blob/master/RATIONALE.md"
className="list-group-item list-group-item-action">Design rationale</Link>
<Link to="#" className="list-group-item list-group-item-action
disabled">Tutorials<span className={'text-primary'}> - coming soon</span></Link>
<Link to="#" className="list-group-item list-group-item-action disabled">The Nickel Manual <span className={'text-primary'}> - coming soon</span></Link>
<Link to="#" className="list-group-item list-group-item-action disabled">Language specification<span className={'text-primary'}> - coming soon</span></Link>
</div>
</div>
</div>
</main>
</Layout>
)
};
export default IndexPage

View File

@ -1,211 +0,0 @@
import * as React from "react"
import {useEffect} from "react"
import Layout from "../components/layout"
import Prism from "prismjs";
import "prismjs/components/prism-bash";
import "prismjs/components/prism-yaml";
import "prismjs/themes/prism-tomorrow.css";
import "prismjs/plugins/command-line/prism-command-line";
import "prismjs/plugins/command-line/prism-command-line.css";
import Playground from "../components/playground-clientside";
import modes from "../components/playground/modes";
import nickelLanguageDefinition from "../prism/nickel";
// Escaping curly braces and other stuff in JSX is tiring, so we define all code examples here
const codeExamples = {
withNix: {
clone: `git clone git@github.com:tweag/nickel.git
Cloning in 'nickel'...
[..]
cd nickel`,
build: `nix-build
[1 built, 0.0 MiB DL]`,
run: `./result/bin/nickel -V
nickel 0.1.0`,
},
firstConfig: `{
name = "example",
description = m#"
This is an awesome software I'm developing.
Please use it!
"#m,
version = "0.1.1",
main = "index.js",
keywords = ["example", "config"],
scripts = {
test = m#"test.sh --option --install example --version "0.1.1""#m,
do_stuff = "do_stuff.sh subcommand",
},
contributors = [{
name = "John Doe",
email = "johndoe@example.com"
}, {
name = "Ivy Lane",
url = "https://example.com/ivylane"
}],
dependencies = {
dep1 = "^1.0.0",
dep3 = "6.7"
}
}`,
export: `./result/bin/nickel -f example.ncl export --format yaml
---
contributors:
- email: johndoe@example.com
name: John Doe
- name: Ivy Lane
url: https://example.com/ivylane
dependencies:
dep1: ^1.0.0
dep3: "6.7"
description: "This is an awesome software I'm developing.\\nPlease use it!"
keywords:
- example
- config
main: index.js
name: example
scripts:
do_stuff: do_stuff.sh subcommand
test: "test.sh --option --install example --version \\"0.1.1\\""
version: 0.1.1`,
reuse: {
problem: `name = "example",
version = "0.1.1",
scripts = {
test = m#"test.sh --option --install example --version "0.1.1""#m,`,
diff: `name = "example",
version = "0.1.1",
scripts = {
test = m#"test.sh --option --install #{name} --version "#{version}""#m`,
result: `# [...]
scripts:
do_stuff: do_stuff.sh subcommand
test: "test.sh --option --install example --version \\"0.1.2\\""
version: 0.1.2`,
},
};
const IndexPage = () => {
useEffect(() => {
Prism.languages.nickel = nickelLanguageDefinition;
Prism.highlightAll();
}, []);
return (
<Layout>
<main className="container content-main-container content">
<h1 id="getting-started" className={'main-title'}>Getting started</h1>
<p>Nickel is still young and the installation process is not yet optimal. Sorry about that! We are focused on improving the
experience, so stay tuned. </p>
<h2 id="build-from-source-using-nix">Build from source using Nix</h2>
<p>Using <a className={"link-primary"} href="https://nixos.org/">Nix</a> is the easiest way
to get a Nickel executable
running.</p>
<ol>
<li><p>Clone the <a className={"link-primary"} href="https://github.com/tweag/nickel">Nickel
repository</a> and set it as the current directory:</p>
<pre className={'command-line language-bash'} data-user="devops" data-host="nickel"
data-output="2-3:"><code>{codeExamples.withNix.clone}</code></pre>
</li>
<li><p>Invoke <code>nix-build</code>:</p>
<pre className={'command-line language-bash'} data-user="devops" data-host="nickel:~/nickel"
data-output="2:"><code>{codeExamples.withNix.build}</code></pre>
</li>
<li><p>If everything went right, a binary is now available in the <code>result</code> directory:</p>
<pre className={'command-line language-bash'} data-user="devops" data-host="nickel:~/nickel"
data-output="2:"><code>{codeExamples.withNix.run}</code></pre>
</li>
</ol>
<h2 id="build-from-source-without-nix">Build from source without Nix</h2>
<p>Please refer to the <a
className={"link-primary"}
href="https://github.com/tweag/nickel/#getting-started">README</a> of the <a
className={"link-primary"}
href="https://github.com/tweag/nickel">Nickel repository</a> for alternative ways of building Nickel.</p>
<h2 id="write-your-first-configuration">Write your first configuration</h2>
<p> Nickel has advanced features to help you handle and organize complex configurations (gradual typing, contracts, a merge system, and so on).
But you'll only have to deal with any of this once you need to.
Writing a basic configuration is as simple as writing JSON or YAML. Let us write a manifest of a fictional app:</p>
<div className={'d-none d-md-block'}>
<Playground fit={'code'} mode={modes.YAML} value={codeExamples.firstConfig}/>
</div>
<div className={'d-block d-md-none'}>
<pre><code className={'language-nickel'}>{codeExamples.firstConfig}</code></pre>
</div>
<p/>This program is composed of <i>record</i>. A record is the same thing as an object in JSON. It is a list of
key-value pairs delimited
by <code>{'{'}</code> and <code>{'}'}</code>. In general, the values of Nickel map directly to
corresponding values in JSON (excluding functions). Thus, the basic datatypes of Nickel are the same as in JSON:
<ul>
<li>Records (objects), delimited by <code>{'{'}</code> and <code>{'}'}</code>.</li>
<li>Strings, delimited by <code>&quot;</code>. The sequence <code>m#&quot;</code> and <code>&quot;#m</code> delimits multiline strings.
</li>
<li>Numbers</li>
<li>Lists, delimited by <code>[</code> and <code>]</code> and separated by <code>,</code>.</li>
</ul>
<p/>Multiline strings are an alternative way of defining strings. Line 11 is an example of such a string. Without diving into the details, multiline strings are
useful for:
<ul>
<li>Write strings spanning several lines, as their name suggests. Multiline strings can be indented at the same
level as the surrounding code while still producing the expected result (the common indentation prefix is stripped).
</li>
<li>Write strings with special characters without having to escape them.</li>
</ul>
In our example, using a multiline string saves us from escaping the recurring double quotes <code>"</code>.
<h2 id="export">Export</h2>
<p>The ultimate goal of a Nickel program is to produce a static configuration. To do so, save the content of our example above in <code>example.ncl</code> and run <code>nickel export</code>:</p>
<pre className={'command-line language-bash'} data-user="devops" data-host="nickel:~/nickel"
data-output="2-21:"><code>{codeExamples.export}</code></pre>
<p>Nickel currently supports exporting to and importing from YAML, TOML and JSON.</p>
<h2 id="reuse">Reuse</h2>
<p>Nickel is a programming language. This allows you not only to describe, but to
generate data. There&#39;s repetition in our previous example:</p>
<pre><code className={'language-nickel'}>{codeExamples.reuse.problem}</code></pre>
<p>The version <code>0.1.1</code> appears both in <code>version</code> and <code>scripts.test</code>.
The name <code>example</code> appears both in <code>name</code> and <code>scripts.test</code> as well.
Pure aesthetics aside, a more serious issue is inconsistency. If you bump the
version number in <code>version</code>, you may forget to do so in the <code>scripts.test</code> as well,
ending up wih incoherent version numbers in the same configuration. To remedy the problem, let's have a
single source of truth by reusing the value of <code>name</code> and <code>version</code> in <code>scripts.test</code>, using
the string interpolation syntax <code>#{'{expr}'}</code>:</p>
<pre><code className={'language-nickel'}>{codeExamples.reuse.diff}</code></pre>
<p>Now, if we change version to <code>0.1.2</code> and export the result, the test script
invocation is updated as well:</p>
<pre><code className={'language-yaml'}>{codeExamples.reuse.result}</code></pre>
<h2 id="going-further">Going further</h2>
<p>This short introduction should get you started. Nickel is a
full-fledged programming language, featuring higher-order functions, gradual
typing, contracts, and more! Additional resources are to come on this website. In the meantime, you can find <a
className={"link-primary"}
href="https://github.com/tweag/nickel/tree/master/examples">examples in the repository</a>. You will also find more details on the language and its design in the <a
className={"link-primary"}
href="https://github.com/tweag/nickel/#nickel">README</a> and in the <a
className={"link-primary"}
href="https://github.com/tweag/nickel/blob/master/RATIONALE.md">design rationale</a>.</p>
</main>
</Layout>
);
};
export default IndexPage

View File

@ -1,128 +0,0 @@
import * as React from "react"
import Layout from "../components/layout"
import {StaticImage} from "gatsby-plugin-image";
import mergeImage from '../images/merge-2.png';
import validateImage from '../images/validate-2.png';
import reuseImage from '../images/reuse-2.png';
import PlaygroundComponent from "../components/playground-clientside";
import modes from "../components/playground/modes";
import {Command} from "react-bootstrap-icons";
import {
faChevronDown,
} from '@fortawesome/free-solid-svg-icons';
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
const codeExample = `let conf = {
name = "NiCl",
version = "0.0.1$",
description = "My cool app!"
} in
let SemanticVersion = fun label value =>
let pattern = "^\\\\d{1,2}\\\\.\\\\d{1,2}(\\\\.\\\\d{1,2})?$" in
if strings.isMatch pattern value then
value
else
let msg = "invalid version number" in
contracts.blame (contracts.tag msg label)
in
let AppSchema = {
name | Str,
version | #SemanticVersion,
description | Str,
} in
conf | #AppSchema`;
/**
* Scroll offset after which the scrolldown arrow is hidden, in pixels.
* @type {number}
*/
const HIDE_SCROLLDOWN_ARROW_AFTER = 100;
const IndexPage = () => {
const [isArrowVisible, setArrowVisible] = React.useState(true);
const onScroll = () => {
const currentScroll = document.body.scrollTop || document.documentElement.scrollTop;
if(isArrowVisible && currentScroll > HIDE_SCROLLDOWN_ARROW_AFTER) {
setArrowVisible(false);
}
};
React.useEffect(() => {
window.addEventListener('scroll', onScroll);
return () =>
window.removeEventListener('scroll', onScroll);
}, []);
return (
<Layout>
<main className="container main-container">
<section className="row first-section-block">
<div className="col-12 text-center">
<h1 className="main-title mb-4"><StaticImage className={"logo"} src="../images/nickel-logo-2.svg" alt="logo"/><span className="nickel">Nickel</span></h1>
<div className="main-subtitle mt-4 mb-4 title-font">Better configuration
for less
</div>
<div className="mt-4 mb-4 main-text">
Write complex configurations. Modular, correct and boilerplate-free.
</div>
</div>
</section>
<hr className={'horizontal-sep d-none d-md-block'}/>
<section className={'row section-block d-none d-md-block'}>
<div className="col-12 text-center">
<h2 className="mb-4">Try it out. Find the <span className={'landingpage-error'}>error</span>!</h2>
<div className="mt-4 mb-4 main-text">
This configuration contains an error. Fix it and press <kbd>Ctrl</kbd>+<kbd>Enter</kbd> (or <kbd>Cmd <Command/>
</kbd>+<kbd>Enter</kbd>) or click <span className={'btn btn-primary disabled'}>Run</span> to try your solution.
</div>
<div className={'text-left landingpage-playground-wrapper'}>
<PlaygroundComponent value={codeExample} fit={'code'} mode={modes.JSON}/>
</div>
</div>
</section>
<hr className={'horizontal-sep'}/>
<section className="row last-section-block">
<div className="col-12 col-lg-4 mb-5 mb-lg-0 main-text text-center landingpage-column">
<img src={mergeImage} className="abstract-illustration" alt={""}/>
<h3 className="mb-4 mt-4">Merge</h3>
<div className="text-left mt-4">
Write simple, modular blocks. Merge them into a complex configuration.
</div>
</div>
<div className="col-12 col-lg-4 mb-5 mb-lg-0 main-text text-center landingpage-column">
<img src={validateImage} className="abstract-illustration" alt={""}/>
<h3 className="mb-4 mt-4">Verify & Validate</h3>
<div className="text-left mt-4">
<p>Use (opt-in) static typing to verify functions, if you need to. Let
type inference do the boring work.</p>
<p>Use contracts
to validate your data and ensure they conform to a given schema.</p>
</div>
</div>
<div className="col-12 col-lg-4 main-text text-center landingpage-column">
<img src={reuseImage} className="abstract-illustration" alt={""}/>
<h3 className="mb-4 mt-4">Reuse</h3>
<div className="text-left lt-4">
Don't use hacks, don't reinvent the wheel: Nickel is a
programming language. Factorize. Reuse the generic parts. Import external libraries.
</div>
</div>
</section>
{isArrowVisible && <FontAwesomeIcon icon={faChevronDown} className={'scroll-down-arrow'}/>}
</main>
</Layout>
)
};
export default IndexPage

View File

@ -1,21 +0,0 @@
import * as React from "react"
import Layout from "../components/layout"
import PlaygroundComponent from "../components/playground-clientside";
const PlaygroundPage = () => {
return (
<Layout>
<div className={"container-fluid playground-main-container d-flex flex-column"}>
<section className={"row"}>
<div className={"col-12 text-center"}>
<h1 className="main-title">Playground</h1>
Experiment with the Nickel REPL online!
</div>
</section>
<PlaygroundComponent/>
</div>
</Layout>
)
};
export default PlaygroundPage

View File

@ -1,28 +0,0 @@
/**
* Simple language definition for Nickel to use with the Prism highlighting library.
* @type {{number: RegExp, string: RegExp[], builtin: RegExp, punctuation: RegExp[], comment: RegExp, keyword: RegExp[], operator: RegExp[]}}
*/
const nickel = {
comment: /\/\/.+/,
string: [
{ pattern: /m(#+)"(.|\n)*?"\1m/, greedy: true},
{ pattern: /".*?"/, greedy: true},
],
operator: [
/>/, />=/, /</, /<=/, /&/, /==/, /&&/, /\|\|/, /!/, /\+/, /@/, /-/, /\+\+/,
],
keyword: [
/let/,
/in/,
/fun/,
/switch/,
/forall/,
],
punctuation: [
/:/, /,/, /;/, /\{/, /}/, /\(/, /\)/, /=/, /\|/, /#/,
],
number: /[0-9]*\.?[0-9]+/,
builtin: /((?:Dyn)|(?:Num)|(?:Bool)|(?:Str)|(?:List:(?:[a-zA-Z0-9_]*)?))/,
};
export default nickel;

View File

@ -1,108 +0,0 @@
@use "sass:map";
@use "sass:color";
$theme-colors: (
"primary": #e0c3fc,
"secondary": #8ec5fc,
);
@import '~bootstrap/scss/bootstrap.scss';
a:hover { text-decoration: none};
/* Correctly style links with our custom primary and secondary colors */
@mixin link($color) {
color: $color;
&:hover, &:focus {
color: color.adjust($color, $lightness: -30%);
}
&.active {
background-color: color.adjust($color, $lightness: +10%) !important;
}
}
@mixin link-theme($color) {
$selected: map.get($theme-colors, $color);
@include link(color.adjust($selected, $lightness: -25%));
}
.link-primary {
@include link-theme("primary");
}
.link-secondary {
@include link-theme("secondary");
}
.link-footer {
color: #757575;
&:hover, &:focus {
color: black;
}
}
.horizontal-sep {
height: 5px;
background: map.get($theme-colors, "primary");
}
.content {
h1, h2, h3, h4, h5 {
margin-bottom: 0.5em;
margin-top: 2.5em;
}
h1:first-child {
margin-top: 0;
}
}
/* Augment bootstrap with breakpoint variants of w-100, w-50, and so on. */
@each $breakpoint in map-keys($grid-breakpoints) {
@each $size, $length in $sizes {
@include media-breakpoint-up($breakpoint) {
.w-#{$breakpoint}-#{$size} {width: $length !important;}
}
}
}
/* Animation of the landing page's scrolldown arrow */
.scroll-down-arrow {
height: 60px;
width: 80px;
margin: 0px 0 0 -40px;
line-height: 60px;
position: absolute;
left: 50%;
bottom: 0px;
color: black;
text-align: center;
font-size: 70px;
z-index: 100;
text-decoration: none;
text-shadow: 0px 0px 3px rgba(0, 0, 0, 0.4);
-webkit-animation: ca3_fade_move_down 1.5s ease-in-out infinite;
-moz-animation: ca3_fade_move_down 1.5s ease-in-out infinite;
animation: ca3_fade_move_down 1.5s ease-in-out infinite;
}
@-webkit-keyframes ca3_fade_move_down {
0% { -webkit-transform:translate(0,-20px); opacity: 0; }
50% { opacity: 1; }
100% { -webkit-transform:translate(0,20px); opacity: 0; }
}
@-moz-keyframes ca3_fade_move_down {
0% { -moz-transform:translate(0,-20px); opacity: 0; }
50% { opacity: 1; }
100% { -moz-transform:translate(0,20px); opacity: 0; }
}
@keyframes ca3_fade_move_down {
0% { transform:translate(0,-20px); opacity: 0; }
50% { opacity: 1; }
100% { transform:translate(0,20px); opacity: 0; }
}

View File

@ -1,256 +0,0 @@
.main-title {
font-size: 3em;
line-height: 1.5;
}
.main-subtitle {
font-size: 2em;
}
.main-text {
font-size: 1.5em;
line-height: 1.3;
}
.playground-loader {
font-size: 1.5em;
line-height: 1.3;
}
.secondary-text {
font-size: 1.3em;
line-height: 1.2;
}
.main-container {
padding-top: 5em;
padding-bottom: 5em;
}
.content-main-container {
margin-top: 5em;
padding-bottom: 5em;
}
.playground-main-container {
margin-top: 5em;
margin-bottom: 5em;
height: 80vh;
}
.playground-terminal {
height: 100%;
width: 100%;
}
.playground-tab {
margin-top: 2.5em;
margin-bottom: 0.5em;
width: 100%;
}
.playground-container {
width: 100%;
}
.playground-terminal-container {
max-height: 100%;
padding: 10px;
overflow-y: scroll;
overflow-x: hidden;
}
#playground-input {
width: 100%;
height: 100%;
}
.playground-nav-item {
color: black;
cursor: pointer;
}
.playground-nav-item.active {
color: black !important;
}
.navbar {
font-size: 1.2em;
}
.section-block {
padding-top: 12.5em;
padding-bottom: 12.5em;
}
.first-section-block {
padding-top: 7.5em;
padding-bottom: 12.5em;
}
.last-section-block {
padding-top: 12.5em;
}
.landingpage-column {
padding-left: 2em;
padding-right: 2em;
}
.landingpage-playground-wrapper {
margin-top: 5em;
}
.landingpage-error {
color: #D44045;
}
.logo {
height: auto;
width: 100px;
vertical-align: middle;
margin-right: 0.3em;
}
.logo-navbar {
height: auto;
width: 50px;
vertical-align: middle;
margin-right: 0.3em;
}
@font-face {
font-family: "Century Gothic";
src: url('../fonts/century-gothic.woff')
}
@font-face {
font-family: "Bureau Grotesque";
src: url('../fonts/bureau-grotesque-55-regular.woff')
}
.nickel {
font-family: "Century Gothic";
}
.title-font, h1, h2, h3 {
font-family: "Bureau Grotesque";
}
.list-elt {
padding-top: 0.2em;
padding-bottom: 0.2em;
}
.abstract-illustration {
height: 6em;
}
.code {
word-wrap: normal;
background-color: #f8f9fa;
padding: 1rem;
}
.code pre {
display: block;
}
.code pre > code {
padding: 0;
margin: 0;
word-break: normal;
white-space: pre;
border: 0;
}
.full-page {
min-height: 100vh;
}
.overflow-scroll {
overflow: scroll;
}
.asciinema-iframe {
width: 100%;
height: 100%;
}
.ansi-monokai {
background: #2F3129;
color: #8F908A;
}
.ansi-monokai code {
color: #8F908A;
}
.ansi-black-bg {
color: #002b36;
}
.ansi-black-fg .ansi-bright-black-fg {
color: #073642;
}
.ansi-green-bg {
color: #586e75;
}
.ansi-yellow-bg {
color: #657b83;
}
.ansi-blue-bg {
color: #839496;
}
.ansi-cyan-bg {
color: #93a1a1;
}
.ansi-white-fg .ansi-bright-white-fg {
color: #eee8d5;
}
.ansi-white-bg {
color: #fdf6e3;
}
.ansi-yellow-fg .ansi-bright-yellow-fg {
color: #b58900;
}
.ansi-red-bg {
color: #cb4b16;
}
.ansi-red-fg, .ansi-bright-red-fg {
color: #dc322f;
}
.ansi-magenta-fg, .ansi-bright-magenta-fg {
color: #d33682;
}
.ansi-magenta-fb {
color: #6c71c4;
}
.ansi-blue-fg, .ansi-bright-blue-fg {
color: #268bd2;
}
.ansi-cyan-fg, .ansi-bright-cyan-fg {
color: #2aa198;
}
.ansi-green-fg, .ansi-bright-green-fg {
color: #859900;
}
.ansi-bright-black-fg, .ansi-bright-red-fg, .ansi-bright-green-fg, .ansi-bright-yellow-fg,
.ansi-bright-blue-fg, .ansi-bright-magenta-fg, .ansi-bright-cyan-fg, .ansi-bright-white-fg {
font-weight: bold;
}