{"id":13530275,"url":"https://github.com/timoxley/adventure-map","last_synced_at":"2025-04-13T02:12:00.628Z","repository":{"id":21813986,"uuid":"25136729","full_name":"timoxley/adventure-map","owner":"timoxley","description":"Simple exercise loader \u0026 generators for substack/adventure.","archived":false,"fork":false,"pushed_at":"2016-01-30T20:42:04.000Z","size":296,"stargazers_count":19,"open_issues_count":4,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-10T20:17:38.007Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timoxley.png","metadata":{"files":{"readme":"Readme.md","changelog":"History.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-10-13T00:40:31.000Z","updated_at":"2022-02-16T19:54:32.000Z","dependencies_parsed_at":"2022-07-22T03:47:07.891Z","dependency_job_id":null,"html_url":"https://github.com/timoxley/adventure-map","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timoxley%2Fadventure-map","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timoxley%2Fadventure-map/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timoxley%2Fadventure-map/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timoxley%2Fadventure-map/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timoxley","download_url":"https://codeload.github.com/timoxley/adventure-map/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248654089,"owners_count":21140236,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T07:00:47.178Z","updated_at":"2025-04-13T02:12:00.611Z","avatar_url":"https://github.com/timoxley.png","language":"JavaScript","funding_links":[],"categories":["Workshoppers"],"sub_categories":["Additional Tools"],"readme":"# adventure-map\n\n\u003cimg align=\"right\" src=\"https://cloud.githubusercontent.com/assets/43438/4612060/79cb38f0-52c2-11e4-9bc8-87cb0b355666.png\"/\u003e\n\nTools with sensible defaults for guiding the creation of new [adventure](https://github.com/substack/adventure) workshops.\n\n* Coloured syntax highlighting in exercise descriptions.\n* Prints syntax highlighted solution on completion of an exercise.\n* Add optional exercise boilerplate.\n* Generates a user solution directory for each exercise.\n* User solution directory includes exercise boilerplate \u0026 problem description.\n\nCode generators for easily starting new workshops \u0026 exercises:\n\n* Generate a new workshop with `adventure-map init`. Creates minimal bootstrap (~20 LOC).\n* Generate a new exercise with `adventure-map new exercise-name`: Bootstraps a few [default files](https://github.com/timoxley/adventure-map/tree/dfecf9ec22152216e7e3ba61c6150bde2dee5596/boilerplate/exercises/example) for an exercise (`Readme.md`, `bootstrap.js`, `solution.js` \u0026 `verify.js`)\n\nI normally *hate* code generators so I've tried to make the code generation only spit out the most unopinionated code that you probably would have written anyway. All generated code is extremely simple and makes minimal assumptions. You can safely and easily modify the generated code to work however you wish.\n\nTODO: custom code generation templates.\n\n## CLI Usage\n\n```\n\u003e adventure-map --help\n  Usage:\n    adventure-map init         Bootstrap current directory.\n    adventure-map new [name]   Bootstrap new exercise with [name].\n```\n\n## Generating Adventures\n\nYou can use `adventure-map` to generate the minimal boilerplate for an\nentire adventure. It includes a bootstrap file to load all the exercises\nand an example exercise to use as a guide.\n\n```\n\u003e mkdir test-adventure\n\u003e cd test-adventure\n\u003e npm init -f\n\u003e npm install --save adventure-map\n\u003e adventure-map init\nexercises/example/Readme.md\nexercises/example/boilerplate.js\nexercises/example/index.js\nexercises/example/solution.js\nindex.js\n```\n\nBy default, exercises are loaded as `\"name\": \"relative/path/to/exercise\"` pairs\nfrom your package.json. You need to add exercises to the package.json manually.\n\n```json\n{\n  \"name\": \"test-adventure\",\n  \"version\": \"1.0.0\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"adventure-map\": \"1.0.0\"\n  },\n  \"exercises\": {\n    \"Getting Started\": \"exercises/example\"\n  }\n}\n```\nIf you don't like this convention of loading from the package.json,\njust change where the exercises load from, it's one line of code in\nthe bootstrap code (see below).\n\nAfter you've configured at least one exercise, can start your adventure:\n\n```\n\u003e node index.js\n```\n\n![image](https://cloud.githubusercontent.com/assets/43438/4608128/f6e40db2-5272-11e4-8ff4-7c2347badf27.png)\n\n## Adventure Bootstrap Code\n\nThe adventure bootstrap simply finds the exercises defined in your\npackage.json and loads them into adventure.\n\n```js\n#!/usr/bin/env node\n\nvar path = require('path')\nvar adventureMap = require('adventure-map')\nvar pkg = require('./package.json')\n\n// resolve all package.json exercises relative\n// to this directory.\nObject.keys(pkg.exercises).forEach(function(name) {\n  pkg.exercises[name] = path.resolve(__dirname, pkg.exercises[name])\n})\n\nvar adventure = adventureMap(pkg)\n\n// auto-execute if run from commandline\nif (!module.parent) adventure.execute(process.argv.slice(2))\n\n// export for manual execution\nmodule.exports = adventure\n```\n\n### Important\n\nThe boilerplate is just provided as a starting point, don't feel bad\nabout changing any of the generated code.\n\n## Generating Exercises\n\nYou can use `adventure-map` to generate the required boilerplate for an\nexercise:\n\n```\n\u003e adventure-map new getting-started\nexercises/getting-started/Readme.md\nexercises/getting-started/boilerplate.js\nexercises/getting-started/index.js\nexercises/getting-started/solution.js\n```\n\nThe exercise's script will load up the Readme, boilerplate and solution\ntext for you, and provide a verify stub.\n\n## Exercise Bootstrap Code\n\n```js\n\"use strict\"\n\nvar fs = require('fs')\nvar path = require('path')\n\nexports.problem = fs.readFileSync(__dirname + '/Readme.md', 'utf8')\nexports.solution = fs.readFileSync(__dirname + '/solution.js', 'utf8')\nexports.boilerplate = fs.readFileSync(__dirname + '/boilerplate.js', 'utf8')\n\nvar solution = require('./solution')\n\nexports.verify = function(args, cb) {\n  var submission = require(path.resolve(process.cwd(), args[0]))\n  // insert validation logic\n  cb(false) // true if submission good\n}\n\nexports.run = function() {\n  // TODO\n}\n```\n\n## API Usage\n\nYou don't need to use the generated boilerplate in order to\nuse adventure-map! Just pass it the adventure name and a mapping of\nexercise names and corresponding exercise paths.\n\nYou'll be passed back a [substack/adventure](https://github.com/substack/adventure)\ninstance.\n\n```js\nvar r = require('path').resolve\nvar adventureMap = require('adventure-map')\n\nvar adventure = adventureMap({\n  name: 'test-adventure',\n  exercises: {\n    'Getting Started': r(__dirname, 'exercises/getting-started'),\n    'Learning Things': r(__dirname, 'exercises/learning-things')\n  }\n})\n\nadventure.execute(process.argv.slice(2))\n```\n\n\n## Exercise Format\n\n`adventure-map` exercises follow the same format as `adventure`\nexercises, with an additional `boilerplate` property:\n\n```js\nmodule.exports = {\n  problem: 'problem text',\n  solution: 'solution code',\n  boilerplate: 'boilerplate code' // optional\n  verify: function(args, cb) {\n    // insert validation logic\n    cb(false) // true if submission good\n  },\n  run: function() {\n    // optional 'run' logic\n  }\n}\n```\n\n# Credit\n\n* Map logo designed by Ruben Verhasselt from the [thenounproject.com](http://thenounproject.com).\n* Big thanks to substack for the creation of [adventure](https://github.com/substack/adventure).\n\n# License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimoxley%2Fadventure-map","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimoxley%2Fadventure-map","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimoxley%2Fadventure-map/lists"}