{"id":15015905,"url":"https://github.com/ember-learn/super-rentals-tutorial","last_synced_at":"2025-10-07T03:11:07.215Z","repository":{"id":35519237,"uuid":"203297455","full_name":"ember-learn/super-rentals-tutorial","owner":"ember-learn","description":null,"archived":false,"fork":false,"pushed_at":"2025-09-29T22:01:54.000Z","size":1902,"stargazers_count":68,"open_issues_count":22,"forks_count":45,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-09-29T22:40:43.094Z","etag":null,"topics":["ember","emberjs","hacktoberfest"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/ember-learn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-08-20T04:06:37.000Z","updated_at":"2025-09-27T21:42:40.000Z","dependencies_parsed_at":"2023-02-10T09:00:36.012Z","dependency_job_id":"347d5c11-63e6-4e83-86ce-ccc9687c390e","html_url":"https://github.com/ember-learn/super-rentals-tutorial","commit_stats":{"total_commits":311,"total_committers":44,"mean_commits":7.068181818181818,"dds":0.4212218649517685,"last_synced_commit":"d5f121e1eaedc1f403a62c6195359ad833273868"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ember-learn/super-rentals-tutorial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ember-learn%2Fsuper-rentals-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ember-learn%2Fsuper-rentals-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ember-learn%2Fsuper-rentals-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ember-learn%2Fsuper-rentals-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ember-learn","download_url":"https://codeload.github.com/ember-learn/super-rentals-tutorial/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ember-learn%2Fsuper-rentals-tutorial/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278712952,"owners_count":26032793,"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","status":"online","status_checked_at":"2025-10-07T02:00:06.786Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["ember","emberjs","hacktoberfest"],"created_at":"2024-09-24T19:48:07.920Z","updated_at":"2025-10-07T03:11:07.208Z","avatar_url":"https://github.com/ember-learn.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Runnable super-rentals tutorial\n\n[![Build Status](https://github.com/ember-learn/super-rentals-tutorial/actions/workflows/build.yml/badge.svg)](https://github.com/ember-learn/super-rentals-tutorial/actions/workflows/build.yml)\n\n## What?\n\nThis allows you to create a runnable tutorial by embedding special runnable\ninstructions (directives) in the markdown source, using the triple-backtick\nmarkdown code block syntax. These code blocks will be executed at build time\nand replaced with their output in the final markdown files.\n\n## Why?\n\n* Make sure the tutorial steps are up-to-date and working correctly with the\n  latest Ember, Ember CLI EmberData, etc.\n* Save time by not having to manually sync the content with upstream blueprint\n  changes!\n* Easy to maintain – changing a step early on in the tutorial automatically\n  propagates to later steps (in code snippets, etc).\n* A fantastic integration test suite for the Ember ecosystem!\n\n## What?\n\n### `run:command`\n\nRun one or more commands.\n\nExample:\n\n    ```run:command\n    ember new super-rentals\n    ```\n\nResult:\n\n    ```\n    \u003e ember new super-rentals\n    installing\n      create .editorconfig\n      create .ember-cli.js\n      create .eslintignore\n      create .eslintrc.js\n      create .template-lintrc.js\n      create .travis.yml\n      create .watchmanconfig\n      create README.md\n      create app/app.js\n      create app/index.html\n      create app/resolver.js\n      create app/router.js\n      create app/styles/app.css\n      create app/templates/application.hbs\n      create config/environment.js\n      create config/optional-features.json\n      create config/targets.js\n      create ember-cli-build.js\n      create .gitignore\n      create jsconfig.json\n      create package.json\n      create public/robots.txt\n      create testem.js\n      create tests/index.html\n      create tests/test-helper.js\n    npm: Installed dependencies\n    Successfully initialized git.\n    ```\n\nThe content of the source code block is the command(s) to run.\n\nCommands can span multiple lines using `\\` at the end of each line to signal\nline-continuation, as in:\n\n    ```run:command\n    echo \"This is a \\\n      command that \\\n      spans multiple \\\n      lines.\"\n    ```\n\nMultiple commands can be supplied. If any of them fails, it will fail the\nbuild.\n\n    ```run:command\n    npm run lint:hbs\n    npm run lint:js\n    npm run test\n    ```\n\nLines starting with `#` and empty lines are ignored.\n\nOptions:\n\n* `lang`\n\n  The syntax highlight language to use in the resulting code block. Defaults\n  to `shell`.\n\n* `hidden=true`\n\n  Run the command(s), but omit the code block from the final markdown file\n  entirely.\n\n* `cwd`\n\n  Specify a CWD (relative to `dist/code`) for the command. This defaults to\n  `.` (i.e. `dist/code`), but most of the time you probably want to set it to\n  `super-rentals` (i.e. `dist/code/super-rentals`). Unfortunately, we cannot\n  just make that the default, because at the beginning of the tutorial, the\n  folder does not exists yet. (Generating the app is part of the tutorial.)\n\n* `captureCommand=false`\n\n  Run the command(s), but omit the command(s) themselves from the resulting\n  code block.\n\n* `captureOutput=false`\n\n  Run the command(s), but omit their output from the resulting code block.\n\n### `run:file:create`\n\nCreate a file.\n\nExample:\n\n    ```run:file:create lang=handlebars cwd=super-rentals filename=app/templates/index.hbs\n    \u003cdiv class=\"jumbo\"\u003e\n      \u003cdiv class=\"right tomster\"\u003e\u003c/div\u003e\n      \u003ch2\u003eWelcome to Super Rentals!\u003c/h2\u003e\n      \u003cp\u003eWe hope you find exactly what you're looking for in a place to stay.\u003c/p\u003e\n    \u003c/div\u003e\n    ```\n\nResult:\n\n    ```handlebars { data-filename=\"app/templates/index.hbs\" }\n    \u003cdiv class=\"jumbo\"\u003e\n      \u003cdiv class=\"right tomster\"\u003e\u003c/div\u003e\n      \u003ch2\u003eWelcome to Super Rentals!\u003c/h2\u003e\n      \u003cp\u003eWe hope you find exactly what you're looking for in a place to stay.\u003c/p\u003e\n    \u003c/div\u003e\n    ```\n\nThe content of the source code block is used to populate the newly created\nfile. It is also rendered into the resulting code block. A trailing newline\nwill be added automatically, if it's not already included in the source code\nblock.\n\nOptions:\n\n* `lang`\n\n  The syntax highlight language to use in the resulting code block.\n\n* `hidden=true`\n\n  Create the file, but omit the code block from the final markdown file\n  entirely.\n\n* `cwd`\n\n  Specify a CWD (relative to `dist/code`) for the filename. This defaults to\n  `.` (i.e. `dist/code`), but most of the time you probably want to set it to\n  `super-rentals` (i.e. `dist/code/super-rentals`). Otherwise, the resulting\n  code block will have its `data-filename` set to `super-rentals/app/...`,\n  which is probably not what you want. Unfortunately, we cannot just make that\n  the default, because at the beginning of the tutorial, the folder does not\n  exists yet. (Generating the app is part of the tutorial.)\n\n* `filename` (**required**)\n\n  The filename (the path relative to `cwd`) used for creating the file. Also\n  sets the `data-filename` metadata field in the resulting code block.\n\n### `run:file:copy`\n\nCopy a file or folder from the `assets` folder.\n\nExample:\n\n    ```run:file:copy lang=css src=downloads/style.css cwd=super-rentals filename=app/styles/app.css\n    @import url(https://fonts.googleapis.com/css?family=Lato:300,300italic,400,700,700italic);\n\n    /**\n     * Base Elements\n     */\n\n    * {\n      margin: 0;\n      padding: 0;\n    }\n\n    /** ...snip... */\n    ```\n\nResult:\n\n    ```css { data-filename=\"app/styles/app.css\" }\n    @import url(https://fonts.googleapis.com/css?family=Lato:300,300italic,400,700,700italic);\n\n    /**\n     * Base Elements\n     */\n\n    * {\n      margin: 0;\n      padding: 0;\n    }\n\n    /** ...snip... */\n    ```\n\nIf the source is a file, then the source file's content will be rendered into\nthe resulting code block. ~~If the source is a folder, its structure will be\nrendered into the resulting code block using a format similar to the Unix\n`tree` command.~~\n\nIf the source code block is non-empty, its content will be rendered into the\nresulting code block in place of the default output described above. This is\nuseful because the file you are copying is probably quite large, and you don't\nnecessarily want to render the whole file into the resulting markdown file.\n\nOptions:\n\n* `lang`\n\n  The syntax highlight language to use in the resulting code block.\n\n* `hidden=true`\n\n  Copy the file, but omit the code block from the final markdown file entirely.\n\n* `cwd`\n\n  Specify a CWD (relative to `dist/code`) for the filename. This defaults to\n  `.` (i.e. `dist/code`), but most of the time you probably want to set it to\n  `super-rentals` (i.e. `dist/code/super-rentals`). Otherwise, the resulting\n  code block will have its `data-filename` set to `super-rentals/app/...`,\n  which is probably not what you want. Unfortunately, we cannot just make that\n  the default, because at the beginning of the tutorial, the folder does not\n  exists yet. (Generating the app is part of the tutorial.)\n\n* `src` (**required**)\n\n  The source filename (the path relative to `dist/assets`) used for creating\n  the file. Also sets the `data-filename` metadata field in the resulting code\n  block.\n\n\n* `filename` (**required**)\n\n  The filename (the path relative to `cwd`) used for creating the file. Also\n  sets the `data-filename` metadata field in the resulting code block.\n\n### `run:file:patch`\n\nEdit a file by applying a git patch.\n\nExample:\n\n    ```run:file:patch lang=js cwd=super-rentals filename=app/router.js\n    @@ -9,2 +9,3 @@\n     Router.map(function() {\n    +  this.route('about');\n     });\n    ```\n\nResult:\n\n    ```js { data-filename=\"app/router.js\" data-diff=\"+9\" }\n    import EmberRouter from '@ember/routing/router';\n    import config from './config/environment';\n\n    const Router = EmberRouter.extend({\n      location: config.locationType,\n      rootURL: config.rootURL\n    });\n\n    Router.map(function() {\n      this.router('about');\n    });\n\n    export default Router;\n    ```\n\nThe content of the source code block is the git patch to apply.\n\nA patch can be generated by modifying a file, and running `git diff -U`.\n\nIt is often a good idea to ask git to include minimal context to make the patch\nmore resilient to changes in the blueprints. You can control the number of\ncontext lines included in the diff by passing a number to `-U`, such as\n`git diff -U1`. You can also manually edit and tweak the resulting patch to\nkeep a useful amount of context for the task at hand.\n\nIt appears that the `diff ...` header line as well as the `index ...` line, as\nwell as the \"hunk context\" (the text after the `@@ ... @@`) can be safely\nomitted. The `--- filename` and `+++ filename` lines are required by git, but\ncan be omitted in the block; the directive will prepend them for you based on\nthe `filename` argument if they are not already included in the patch.\n\nA good workflow for generating patches:\n\n* Insert `run:pause` at the appropriate spot\n* Make sure the file you are editing is clean or staged (`git add file`)\n* Make the changes\n* `git diff -U1 \u003e diff.patch`, play with the context number, tweak the patch by\n  hand until you are happy with how it looks (keeping source-readability in\n  mind)\n* Undo the changes with `git checkout file`\n* Test the patch with `git apply diff.patch`\n\nEven though the patch contains line numbers, those are only used as \"hints\"\nwhen applying the diff. In practice, a well crafted patch could be quite\nresilient. For instance, the patch given in the example has been verified to\napply cleanly even if the router blueprint has been changed to this:\n\n```js\nimport EmberRouter from '@ember/routing/router';\nimport config from './config/environment';\n\nexport default class Router extends EmberRouter {\n location = config.locationType;\n rootURL = config.rootURL;\n}\n\nRouter.map(function() {\n});\n```\n\nAs you can see, even though the line numbers have shifted around, git has no\ntrouble finding the relevant router map section from the above.\n\nIf the patch fails to apply cleanly, it will fail the build.\n\nThe resulting code block will contain the \"combined\" source of the file being\nedited, with `data-diff` metadata field indicated the removed and added lines.\nWe can use this data on the client side to format the diff output. Potentially\nwe can render it using an interactive component that allows you to toggle\nbetween the before/after/combined source, as well as folding away the unchanged\nlines.\n\nOptions:\n\n* `lang`\n\n  The syntax highlight language to use in the resulting code block.\n\n* `hidden=true`\n\n  Edit the file, but omit the code block from the final markdown file entirely.\n\n* `cwd`\n\n  Specify a CWD (relative to `dist/code`) for the filename. This defaults to\n  `.` (i.e. `dist/code`), but most of the time you probably want to set it to\n  `super-rentals` (i.e. `dist/code/super-rentals`). Otherwise, the resulting\n  code block will have its `data-filename` set to `super-rentals/app/...`,\n  which is probably not what you want. Unfortunately, we cannot just make that\n  the default, because at the beginning of the tutorial, the folder does not\n  exists yet. (Generating the app is part of the tutorial.)\n\n* `filename`\n\n  The filename (the path relative to `cwd`) used for creating the file. Also\n  sets the `data-filename` metadata field in the resulting code block.\n\n  This is also used to format the patch before sending it to `git apply`, so\n  it is required unless they are already included in the patch and the block is\n  set to `hidden`.\n\n### `run:file:show`\n\nRender the content of a file ~~or a folder~~.\n\nExample:\n\n    ```run:file:show lang=handlebars cwd=super-rentals filename=app/templates/index.hbs\n    ```\n\nResult:\n\n    ```handlebars { data-filename=\"app/templates/index.hbs\" }\n    \u003cdiv class=\"jumbo\"\u003e\n      \u003cdiv class=\"right tomster\"\u003e\u003c/div\u003e\n      \u003ch2\u003eWelcome to Super Rentals!\u003c/h2\u003e\n      \u003cp\u003eWe hope you find exactly what you're looking for in a place to stay.\u003c/p\u003e\n    \u003c/div\u003e\n    ```\n\nThe content of the source code block is not used. ~~If the source is a folder,\nits structure will be rendered into the resulting code block using a format\nsimilar to the Unix `tree` command.~~\n\nOptions:\n\n* `lang`\n\n  The syntax highlight language to use in the resulting code block.\n\n* `cwd`\n\n  Specify a CWD (relative to `dist/code`) for the filename. This defaults to\n  `.` (i.e. `dist/code`), but most of the time you probably want to set it to\n  `super-rentals` (i.e. `dist/code/super-rentals`). Otherwise, the resulting\n  code block will have its `data-filename` set to `super-rentals/app/...`,\n  which is probably not what you want. Unfortunately, we cannot just make that\n  the default, because at the beginning of the tutorial, the folder does not\n  exists yet. (Generating the app is part of the tutorial.)\n\n* `filename` (**required**)\n\n  The filename (the path relative to `cwd`) used for reading the file. Also\n  sets the `data-filename` metadata field in the resulting code block.\n\n### `run:checkpoint`\n\nIndicates a checkpoint where the following steps are performed:\n\n* `yarn test`\n* Optionally, commit the current changes\n* Verify the git tree is clean (i.e. no dirty or untracked files)\n\nThis directive does not produce any output. If any of the steps failed, it will\nfail the build.\n\nExample:\n\n    ```run:checkpoint cwd=super-rentals\n    Chapter 1\n    ```\n\nThe content of the source code block is the git commit message.\n\nTo avoid failing the \"clean tree\" test, you should be adding any created or\nmodified files to the staging area as you go, using `run:command hidden=true`\ncode blocks.\n\n* `cwd`\n\n  Specify a CWD (relative to `dist/code`) for the command. This defaults to\n  `.` (i.e. `dist/code`), but most of the time you probably want to set it to\n  `super-rentals` (i.e. `dist/code/super-rentals`). Unfortunately, we cannot\n  just make that the default, because at the beginning of the tutorial, the\n  folder does not exists yet. (Generating the app is part of the tutorial.)\n\n* `commit=false`\n\n  Don't create a git commit, but still run the other checks, *including the\n  \"clean tree\" test*. This is only useful if the chapter did not make any\n  changes at all, or one of the visible `run:command` blocks already committed\n  the changes as part of the tutorial flow.\n\n### `run:ignore` (or `run:ignore:*`)\n\nIgnore the source code block, and omit it from the final markdown file\nentirely.\n\nThis is useful for temporarily disabling a directive code block for debugging,\nor because it is not working, while still keeping the code in the source file.\nEssentially, this is how you \"comment out\" a directive code block.\n\nFor your convenience, you can pass any sub-directive after `run:ignore:`, or\npass any arguments to it. This allows you to just insert `:ignore:` into an\nexisting directive code block to disable it, without making any other changes.\n\nExample:\n\n    ```run:ignore:command cwd=super-rentals\n    # FIXME: don't run this for now, since Heroku is down atm\n    git push heroku main\n    ```\n\n### `run:pause`\n\nPause the build until you are ready to resume.\n\nThis allows you to examine the state of things at a specific point in the\ntutorial, which is useful for debugging, taking screenshots or generating\ndiff patches. Essentially, this is the `this.pauseTest()` for the tutorial.\n\nExample:\n\n    ```run:pause\n    Manually record a gif of performing the following steps:\n\n    ...snip...\n    ```\n\nThe content of the source code block will be printed to the command line\nprompt. This directive does not produce any output.\n\n### `run:server:start`\n\nStart a server (background task).\n\nExample:\n\n    ```run:server:start cwd=super-rentals expect=\"Serving on http://localhost:4200/\"\n    npm start\n    ```\n\nResult:\n\n    ```shell\n    $ npm start\n    Build successful (9006ms) – Serving on http://localhost:4200/\n    ```\n\nThe content of the source code block is the command for starting the server.\nUnlike `run:command`, you can only pass a single command, thought the command\nmay span multiple lines if needed, using `\\` at the end of each line to signal\nline-continuation.\n\nLines starting with `#` and empty lines are ignored.\n\nAll servers started with this directive must be explicitly shut down with the\n`run:server:stop` directive before the end of the file, otherwise the build\nwill fail.\n\nOptions:\n\n* `id`\n\n  A unique identifier to reference this server process, which is needed when\n  shutting it down later. This is optional; by default, the command to start\n  the server is used as the id, but this allows you to specify a shorter name\n  if desired.\n\n* `lang`\n\n  The syntax highlight language to use in the resulting code block. Defaults\n  to `shell`.\n\n* `hidden=true`\n\n  Start the server, but omit the code block from the final markdown file\n  entirely.\n\n* `cwd`\n\n  Specify a CWD (relative to `dist/code`) for the command. This defaults to\n  `.` (i.e. `dist/code`), but most of the time you probably want to set it to\n  `super-rentals` (i.e. `dist/code/super-rentals`). Unfortunately, we cannot\n  just make that the default, because at the beginning of the tutorial, the\n  folder does not exists yet. (Generating the app is part of the tutorial.)\n\n* `expect`\n\n  Wait for a particular string to appear on STDOUT to ensure the server has\n  started successfully, before moving on to the next step.\n\n* `timeout`\n\n  Wait for some time to pass (specified in seconds) before moving on to the\n  next step.\n\n  If used in conjunction with the `expect` option, it will fail the step if the\n  checks are not completed before the deadline.\n\n* `captureCommand=false`\n\n  Omit the command used to start the server from the resulting code block.\n\n* `captureOutput=false`\n\n  Omit the output of the command used to start the server from the resulting\n  code block.\n\n### `run:server:stop`\n\nStop a server (background task) previously started with `run:server:start`.\n\nExample:\n\n    ```run:server:stop\n    npm start\n    ```\n\nThe content of the source code block is the command used to start the server.\nThis directive does not produce any output.\n\nOptions:\n\n* `id`\n\n  A unique identifier to reference the server process (see `run:server:start`).\n  If this option is passed, the content block is ignored.\n\n## How?\n\n* Requires `git`\n* Probably only works on Unix/bash for now (PRs welcome)\n  * Should probably run the build in a docker container anyway\n* `pnpm install`\n* `TOMTOM_ACCESS_TOKEN=your-token-here yarn build`\n  * Please note that you will need a TomTom token in order to successfully run `pnpm build`, otherwise the build will fail due to failing to load the map images. You can get your own token [here](https://developer.tomtom.com). Once you have a token, you should assign it to the `TOMTOM_ACCESS_TOKEN` environment variable.\n* Processed markdown can be found in `dist/markdown`\n* The `super-rentals` code can be found in `dist/code/super-rentals`\n\n## Future Work\n\n* `run:gif`\n* Improve the build output\n* Extract this from `super-rentals` and make it usable for building arbitrary\n  runnable tutorials\n\n## Prior Art\n\n* [RunDOC](https://github.com/schneems/rundoc)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fember-learn%2Fsuper-rentals-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fember-learn%2Fsuper-rentals-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fember-learn%2Fsuper-rentals-tutorial/lists"}