Skip to content

Commit

Permalink
playground: add basic examples
Browse files Browse the repository at this point in the history
This adds a small set of representative examples to the playground,
replacing the current invalid examples.

They are placed in an indicative structure, with the "Introduction"
category being intended to hold examples for the user who landed on the
playground before reading any other part of the site, and the "Tour"
category showing a couple of CUE examples taken directly from the
on-page CUE in docs/tour/.

The Tour category isn't expanded to include all the docs examples, yet,
as both cue-lang/cue#2995 and cue-lang/cue#2900 need resolving to let us
avoid spending a *lot* of time on manual content syncing.

Formatting notes for as&when the examples are expanded, and if their
generation is automated:

- Because cue-lang/cue#722 also strikes the playground ("top-level
  comments are indented") when the playground's default of "cue eval" is
  selected, care has been taken to make sure that comments are used that
  don't trigger this bug (as it looks pretty poor for predefined
  examples to have this problem). Some relevant information:
  - only the first comment presented at the top of the "eval" output is
    affected
  - it doesn't affect comments which aren't included in the output, such
    as introductory comments which are separated by a blank line from
    the first field emitted
  - it doesn't affect fields with a struct or list value
  - it only affects single-line comments
  - it can affect a comment that's not the first line of the source, if
    it's attached to any definition of the first field that's present in
    the emitted output

- Including  links from tour-derived examples back to the relevant tour
  page feels like a win, but they need to be split over two comment
  lines or the end of the URL disappears from view. This also has the
  nice effect of pushing the URL to the second line of the editor, which
  makes the "Follow link (ctrl+click)" mouseover popup *not* get
  visually truncated by the top edge of the editor pane.

Preview-Path: /play
Signed-off-by: Jonathan Matthews <[email protected]>
Change-Id: I374ee591f767bea3a0e07f29ce7825468661f42f
  • Loading branch information
jpluscplusm committed Mar 28, 2024
1 parent a10f685 commit 90572e5
Show file tree
Hide file tree
Showing 14 changed files with 200 additions and 31 deletions.
5 changes: 3 additions & 2 deletions playground/src/config/examples/categories.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const categoryWeight: {[key: string]: number } = {
'Category 1': 10,
'Category 2': 20,
'Introduction': 1,
'Tour': 10,
'Commented CUE': 20,
}
19 changes: 19 additions & 0 deletions playground/src/config/examples/exIntroBasicTypes.cue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// CUE has several basic types:

a: int
b: float
c: string
d: bool
e: null
f: bytes
g: number

// Each type has a literal form:

a: 42
b: 42.0
c: "42"
d: true
e: null
f: '42'
g: 42 | 42.0 // number is compatible with int or float
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,19 @@ import { OPTION_TYPE } from '@models/options';
// Clone config because we don't want to change the original workspace config
const config = cloneDeep<WorkspaceConfig>(functionWorkspace.config);

export const testExample: Example = {
slug: 'test-example',
title: 'Test example',
category: 'Category 1',
export const exIntroBasicTypes: Example = {
slug: 'intro-basic-types',
title: 'Basic Types',
category: 'Introduction',
workspace: WORKSPACE.FUNC,
workspaceConfig: {
...config,
inputTabs: config.inputTabs.map((tab) => {
if (tab.type === OPTION_TYPE.INPUT) {
tab.code = 'Examples are coming soon!';
// This text is a manually sync'd copy of <basename>.cue, produced by
// cue export text: <basename>.cue
// TODO: make this better (cue-lang/cue#2995)
tab.code = "// CUE has several basic types:\n\na: int\nb: float\nc: string\nd: bool\ne: null\nf: bytes\ng: number\n\n// Each type has a literal form:\n\na: 42\nb: 42.0\nc: \"42\"\nd: true\ne: null\nf: '42'\ng: 42 | 42.0 // number is compatible with int or float\n";
}
return tab;
}),
Expand Down
27 changes: 27 additions & 0 deletions playground/src/config/examples/exIntroStructsAndLists.cue
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Structs and lists are composite types, composed of
// "fields" (structs) and "elements" (lists).
// Structs are indicated by { and }, and lists by [ and ].

// aStruct is a struct.
aStruct: {
a: 1
b: 2.0
c: "3"
d: {
e: 4 + 4
f: 5 * 5.0
}
g: false
}

// aList is a list.
aList: [
1,
2.0,
"3",
{
e: 4 + 4
f: 5 * 5.0
},
false,
]
32 changes: 32 additions & 0 deletions playground/src/config/examples/exIntroStructsAndLists.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { cloneDeep } from 'lodash';
import { Example } from '@models/example';
import { WORKSPACE, WorkspaceConfig } from '@models/workspace';
import { functionWorkspace } from '@config/workspaces';
import { OPTION_TYPE } from '@models/options';

/* In the future we can also let the pre-processor create examples based on one of the workspace config's
instead of doing it with typescript. Make sure the example follows the Example model and the config
is correct for the chosen workspace. */

// Clone config because we don't want to change the original workspace config
const config = cloneDeep<WorkspaceConfig>(functionWorkspace.config);

export const exIntroStructsAndLists: Example = {
slug: 'intro-structs-and-lists',
title: 'Structs and Lists',
category: 'Introduction',
workspace: WORKSPACE.FUNC,
workspaceConfig: {
...config,
inputTabs: config.inputTabs.map((tab) => {
if (tab.type === OPTION_TYPE.INPUT) {
// This text is a manually sync'd copy of <basename>.cue, produced by
// cue export text: <basename>.cue
// TODO: make this better (cue-lang/cue#2995)
tab.code = "// Structs and lists are composite types, composed of\n// \"fields\" (structs) and \"elements\" (lists).\n// Structs are indicated by { and }, and lists by [ and ].\n\n// aStruct is a struct.\naStruct: {\n\ta: 1\n\tb: 2.0\n\tc: \"3\"\n\td: {\n\t\te: 4 + 4\n\t\tf: 5 * 5.0\n\t}\n\tg: false\n}\n\n// aList is a list.\naList: [\n\t1,\n\t2.0,\n\t\"3\",\n\t{\n\t\te: 4 + 4\n\t\tf: 5 * 5.0\n\t},\n\tfalse,\n]\n";
}
return tab;
}),
},
}

Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ import { OPTION_TYPE } from '@models/options';
// Clone config because we don't want to change the original workspace config
const config = cloneDeep<WorkspaceConfig>(functionWorkspace.config);

export const defaultExample: Example = {
slug: 'welcome-to-cue',
export const exIntroWelcomeToCue: Example = {
slug: 'intro-welcome-to-cue',
title: 'Welcome to CUE!',
category: 'Category 1',
category: 'Introduction',
workspace: WORKSPACE.FUNC,
workspaceConfig: {
...config,
inputTabs: config.inputTabs.map((tab) => {
if (tab.type === OPTION_TYPE.INPUT) {
// This text is a manually sync'd copy of defaultExample.cue, produced by
// cue export text: defaultExample.cue
// This text is a manually sync'd copy of <basename>.cue, produced by
// cue export text: <basename>.cue
// TODO: make this better (cue-lang/cue#2995)
tab.code = "// Welcome to CUE!\n//\n// Play around with CUE by typing directly into this window,\n// or use the Examples menu to load some CUE.\n//\n// There are many examples of how to use the language on the CUE\n// documentation site, https://cuelang.org/docs/, with the language\n// tour being a great place to start: https://cuelang.org/docs/tour/.\n// Just Ctrl-click links to open them in a new window.\n//\n// You can safely delete the text in this editor window - simply\n// reload the page to see this message again. Happy CUEing!\n\n// This is a comment\n_greeting: \"Welcome\" // Hidden fields start with \"_\"\n#project: \"CUE\" // Definitions start with \"#\"\n\nmessage: \"\\(_greeting) to \\(#project)!\" // Regular fields are exported\n";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import { OPTION_TYPE } from '@models/options';
// Clone config because we don't want to change the original workspace config
const config = cloneDeep<WorkspaceConfig>(policyWorkspace.config);

export const testExample3: Example = {
slug: 'test-example-3',
title: 'Some other example',
category: 'Category 2',
export const exPolicy: Example = {
slug: 'policy',
title: 'Policy example',
category: 'TODO',
workspace: WORKSPACE.POLICY,
workspaceConfig: {
...config,
Expand Down
24 changes: 24 additions & 0 deletions playground/src/config/examples/exTourBasicsJsonSuperset.cue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// This example is explained at
// https://cuelang.org/docs/tour/basics/json-superset/

import "math"

// Simple labels don't
// need to be quoted.
one: 1
two: 2
piPlusOne: math.Pi + 1

// Field names must be quoted if they contain
// special characters, such as hyphen and space.
"quoted field names": {
"two-and-a-half": 2.5
"three point three": 3.3
"four^four": math.Pow(4, 4)
}

aList: [
1,
2,
3,
]
32 changes: 32 additions & 0 deletions playground/src/config/examples/exTourBasicsJsonSuperset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { cloneDeep } from 'lodash';
import { Example } from '@models/example';
import { WORKSPACE, WorkspaceConfig } from '@models/workspace';
import { functionWorkspace } from '@config/workspaces';
import { OPTION_TYPE } from '@models/options';

/* In the future we can also let the pre-processor create examples based on one of the workspace config's
instead of doing it with typescript. Make sure the example follows the Example model and the config
is correct for the chosen workspace. */

// Clone config because we don't want to change the original workspace config
const config = cloneDeep<WorkspaceConfig>(functionWorkspace.config);

export const exTourBasicsJsonSuperset: Example = {
slug: 'tour-basics-json-superset',
title: 'Basics: JSON Superset',
category: 'Tour',
workspace: WORKSPACE.FUNC,
workspaceConfig: {
...config,
inputTabs: config.inputTabs.map((tab) => {
if (tab.type === OPTION_TYPE.INPUT) {
// This text is a manually sync'd copy of <basename>.cue, produced by
// cue export text: <basename>.cue
// TODO: make this better (cue-lang/cue#2995)
tab.code = "// This example is explained at\n// https://cuelang.org/docs/tour/basics/json-superset/\n\nimport \"math\"\n\n// Simple labels don't\n// need to be quoted.\none: 1\ntwo: 2\npiPlusOne: math.Pi + 1\n\n// Field names must be quoted if they contain\n// special characters, such as hyphen and space.\n\"quoted field names\": {\n\t\"two-and-a-half\": 2.5\n\t\"three point three\": 3.3\n\t\"four^four\": math.Pow(4, 4)\n}\n\naList: [\n\t1,\n\t2,\n\t3,\n]\n";
}
return tab;
}),
},
}

23 changes: 23 additions & 0 deletions playground/src/config/examples/exTourBasicsTypesAreValues.cue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// This example is explained at
// https://cuelang.org/docs/tour/basics/types-are-values/

municipality: {
name: string
pop: int
capital: bool
}

largeCapital: {
name: string
pop: >5M
capital: true
}

kinshasa: {
name: "Kinshasa"
pop: 16.32M
capital: true
}

largeCapital: municipality
kinshasa: largeCapital
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,19 @@ import { OPTION_TYPE } from '@models/options';
// Clone config because we don't want to change the original workspace config
const config = cloneDeep<WorkspaceConfig>(functionWorkspace.config);

export const testExample2: Example = {
slug: 'test-example-2',
title: 'Another example',
category: 'Category 2',
export const exTourBasicsTypesAreValues: Example = {
slug: 'tour-basics-types-are-values',
title: 'Basics: Types are Values',
category: 'Tour',
workspace: WORKSPACE.FUNC,
workspaceConfig: {
...config,
inputTabs: config.inputTabs.map((tab) => {
if (tab.type === OPTION_TYPE.INPUT) {
tab.code = 'Examples are coming soon!';
// This text is a manually sync'd copy of <basename>.cue, produced by
// cue export text: <basename>.cue
// TODO: make this better (cue-lang/cue#2995)
tab.code = "// This example is explained at\n// https://cuelang.org/docs/tour/basics/types-are-values/\n\nmunicipality: {\n\tname: string\n\tpop: int\n\tcapital: bool\n}\n\nlargeCapital: {\n\tname: string\n\tpop: >5M\n\tcapital: true\n}\n\nkinshasa: {\n\tname: \"Kinshasa\"\n\tpop: 16.32M\n\tcapital: true\n}\n\nlargeCapital: municipality\nkinshasa: largeCapital\n";
}
return tab;
}),
Expand Down
23 changes: 14 additions & 9 deletions playground/src/config/examples/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { Example } from '@models/example';
import { defaultExample } from '@config/examples/defaultExample';
import { testExample } from '@config/examples/example';
import { cloneDeep } from 'lodash';
import { testExample2 } from '@config/examples/example2';
import { testExample3 } from '@config/examples/example3';
import { Example } from '@models/example';
import { exIntroWelcomeToCue} from '@config/examples/exIntroWelcomeToCue';
import { exIntroBasicTypes} from '@config/examples/exIntroBasicTypes';
import { exIntroStructsAndLists} from '@config/examples/exIntroStructsAndLists';
import { exTourBasicsJsonSuperset } from '@config/examples/exTourBasicsJsonSuperset';
import { exTourBasicsTypesAreValues } from '@config/examples/exTourBasicsTypesAreValues';
// import { exPolicy } from '@config/examples/exPolicy';

export const examples: Example[] = [
cloneDeep(defaultExample),
cloneDeep(testExample),
cloneDeep(testExample2),
cloneDeep(testExample3),
cloneDeep(exIntroWelcomeToCue),
cloneDeep(exIntroBasicTypes),
cloneDeep(exIntroStructsAndLists),
cloneDeep(exTourBasicsJsonSuperset),
cloneDeep(exTourBasicsTypesAreValues),
// Policy workspace is currently disabled.
// cloneDeep(exPolicy),
];
2 changes: 1 addition & 1 deletion playground/src/containers/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export class App extends React.Component<AppProps, AppState>
let saved = false;
const urlSearchParams = getSearchParamsFromUrl();
const params: hashParams = getHashParamsFromUrl();
const defaultCUEInput = 'welcome-to-cue';
const defaultCUEInput = 'intro-welcome-to-cue';

// Check if we have saved code to get
const id = urlSearchParams.get('id');
Expand Down

0 comments on commit 90572e5

Please sign in to comment.