Full Code of callmekatootie/carbonate for AI

master 76eddf4bd2b0 cached
8 files
16.0 KB
4.2k tokens
11 symbols
1 requests
Download .txt
Repository: callmekatootie/carbonate
Branch: master
Commit: 76eddf4bd2b0
Files: 8
Total size: 16.0 KB

Directory structure:
gitextract_o0qpgg0z/

├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── LICENSE
├── README.md
├── action.yml
├── constants.js
├── index.js
└── package.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/main.yml
================================================
on:
  issue_comment:
    types: [created]
  issues:
    types: [opened]

jobs:
  carbonate:
    runs-on: ubuntu-latest
    name: Generate beautiful images for code blocks present in issues
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Generate beautiful images for code blocks present in issues
        uses: ./
        id: carbonate
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          imgur-client-id: ${{ secrets.IMGUR_CLIENT_ID }}


================================================
FILE: .gitignore
================================================
# Ignoring the folder where I have the debug data, for easier reference during dev
data/


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 Mithun Kamath

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.


================================================
FILE: README.md
================================================
# Carbonate

Jazz up the code blocks in your issues. Generate beautiful images for them to make it easier to follow. Meant to be used as a Github Action.

**BEFORE**

![](https://i.imgur.com/FzLtUjP.png)

**AFTER**

![](https://i.imgur.com/B29aF97.png)

> First appeared at: https://stackoverflow.com/a/61269447/2104976

## Features

The workflow of this action is as follows:

- It extracts the code block for the issue description / comment and generates images for them
- It then inserts the image at the code block
- It also retains the original code block as a collapsed detail in the same issue / comment body

Additionally, it

- Allows formatting the code using Prettier and controlling the styling of the images generated
- Supports the following events:
  - issue_comment:
    - types: created
  - issues:
    - types: opened

## Not supported (yet)

- Generating images from multiple code blocks in the same issue description / comment
- Generating images after the issue description / comment has been edited

## Advantages of code images over code blocks

- Easy to view and understand the image of the code v/s the code block text when using a mobile device. Why? Easier to scroll images v/s text.
- Members will no longer have to rely on the issue reporters and commenters to format their code blocks correctly. Using the in built formatter, the code is always structured properly
- Maintainers can style the code blocks to suit their project's language and guidelines and not put the onus of this on the issue reporter / commenter
- [Carbon]((https://github.com/carbon-app/carbon)). Oh wow Carbon! It generates really beautiful images of code and it is aesthetically better to look at v/s plain code text

## Pre-requisites

[Register](https://api.imgur.com/oauth2/addclient) your application with Imgur to get a `client_id`. You will pass this as input to the action.

## Usage

```yaml
on:
  issue_comment:
    types: [created]
  issues:
    types: [opened]

jobs:
  carbonate:
    runs-on: ubuntu-latest
    name: Generate beautiful images for code blocks present in issues
    steps:
      - name: Generate beautiful images for code blocks present in issues
        uses: callmekatootie/carbonate@v1.0.2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          imgur-client-id: ${{ secrets.IMGUR_CLIENT_ID }}
```

More inputs are available. See below.

### Inputs

#### github-token

This is the environment variable [GITHUB_TOKEN](https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token#about-the-github_token-secret).

#### imgur-client-id

The `client_id` that you obtained after [registration](https://api.imgur.com/oauth2/addclient) with imgur. The action will be carrying out anonymous uploads. **Required**.

#### use-prettier

The action can use [Prettier](https://prettier.io/) to format the code block before the image is generated. Set this input's value to the String `'true'` if you want to use it or to the String `'false'` otherwise. **Default value is 'true'**

#### prettier-parser

This input is only read if `use-prettier` input is `'true'`. You will specify the [parser](https://prettier.io/docs/en/options.html#parser) that you want Prettier to use for formatting the code. **Default value is 'babel'**

#### prettier-options

This input is only read if `use-prettier` input is `'true'`. You can specify the format [options](https://prettier.io/docs/en/options.html) to use with Prettier. **You need to pass the options object as a JSON string**. If none is passed, the action will fall back to Prettier's default format options.

#### carbon-options

You can specify the Carbon image generation configuration options. See [this](https://github.com/petersolopov/carbonara#post-apicook) for a list of supported options. **You need to pass the options object as a JSON string**. If none is passed, the action will use the options defined in the `constants.js` file.

## References

- [Carbon](https://github.com/carbon-app/carbon) - Generate beautiful images for code
- [Carbonara](https://github.com/petersolopov/carbonara) - Unofficial API for Carbon
- [Imgur](https://apidocs.imgur.com/) - Generated images are stored in Imgur
- [Prettier](https://prettier.io) - Opinionated Code Formatter


================================================
FILE: action.yml
================================================
---
name: 'Carbonate'
description: 'Generate beautiful images for code blocks present in issues'
inputs:
  github-token:
    description: 'The GITHUB_TOKEN. Will read off the environment variable by default'
    required: false
    default: ${{ github.token }}
  imgur-client-id:
    description: 'All images are hosted on Imgur. Thus, provide your Imgur app client id'
    required: true
  use-prettier:
    description: 'Should the code block be formatted using prettier? Pass String `true` or String `false`. Default is `true`'
    required: false
    default: 'true'
  prettier-parser:
    description: 'This is read only if `use-prettier` is set to `true`. This is the parser to use with Prettier. Default value is babel'
    required: false
    default: 'babel'
  prettier-options:
    description: 'This is read only if `use-prettier` is set to `true`. This is the Prettier options object, as a JSON string. Default values are the ones defined by Prettier itself. Check out their documentation'
    required: false
  carbon-options:
    description: 'The Carbon options object, as a JSON string. See `https://github.com/petersolopov/carbonara#post-apicook` for a list of supported options. Ignores the `code` property though. For default values, please check out the constants.js file in the source code of this action'
    required: false
runs:
  using: 'node12'
  main: 'index.js'
branding:
  icon: 'code'
  color: 'blue'
...


================================================
FILE: constants.js
================================================
const IMAGE_FILE_EXT = '.png'

const IMGUR_API_URL = 'https://api.imgur.com/3/image'

const CARBON_API_URL = 'https://carbonara-42.herokuapp.com/api/cook'

const CARBON_DEFAULT_SETTINGS = {
  paddingVertical: '56px',
  paddingHorizontal: '56px',
  backgroundColor: 'rgba(74,144,226,1)',
  dropShadow: true,
  dropShadowOffsetY: '20px',
  dropShadowBlurRadius: '68px',
  theme: 'one-dark',
  windowTheme: 'none',
  language: 'auto',
  fontFamily: 'Hack',
  fontSize: '14px',
  lineHeight: '143%',
  windowControls: false,
  widthAdjustment: true,
  lineNumbers: false,
  exportSize: '2x',
  watermark: false
}

module.exports = {
  IMAGE_FILE_EXT,
  IMGUR_API_URL,
  CARBON_API_URL,
  CARBON_DEFAULT_SETTINGS
}


================================================
FILE: index.js
================================================
const core = require('@actions/core')
const github = require('@actions/github')
const gcb = require('gfm-code-blocks')
const { default: Axios } = require('axios')
const fs = require('fs')
const { v4: uuidv4 } = require('uuid')
const FormData = require('form-data')
const path = require('path')
const util = require('util')
const prettier = require('prettier')
const {
  IMAGE_FILE_EXT,
  IMGUR_API_URL,
  CARBON_API_URL,
  CARBON_DEFAULT_SETTINGS
} = require('./constants')

const unlink = util.promisify(fs.unlink)

/**
 * Formats the code using prettier
 * @param {String} code The code block to format
 * @param {Object} options The Prettier options
 * @param {String} parser The Prettier parser
 */
function formatCode (code, options, parser) {
  try {
    return prettier.format(code, { ...options, parser })
  } catch (error) {
    core.debug('An error occurred when using prettier')
    core.debug(error)

    // Return unformatted code
    return code
  }
}

/**
 * Generates the image using Carbon's API
 * @param {String} code The code to generate image for
 * @param {Object} options The {Unofficial} Carbon API options
 */
async function generateImage (code, options) {
  const uuid = uuidv4()

  core.info('Generating image from the code...')

  try {
    const res = await Axios.post(CARBON_API_URL, {
      code,
      ...CARBON_DEFAULT_SETTINGS,
      ...options
    }, {
      responseType: 'stream'
    })

    const writeStream = fs.createWriteStream(path.join(__dirname, `${uuid}${IMAGE_FILE_EXT}`))

    return new Promise((resolve, reject) => {
      let error

      res.data.pipe(writeStream)

      writeStream.on('error', (err) => {
        error = err
        core.error('An error occurred downloading the generated image from Carbon')
        core.debug(error)
        writeStream.close()
        reject(error)
      })

      writeStream.on('close', () => {
        if (!error) {
          // Return the file id
          resolve(uuid)
        }
      })
    })
  } catch (error) {
    core.error('An error occurred when trying to generate image for the code')
    core.debug(error)

    // Throw the error to abort the operation
    throw error
  }
}

/**
 * Uploads the image to Imgur
 * @param {String} imageId The uuid of the image
 */
async function uploadImage (imageId) {
  const clientId = core.getInput('imgur-client-id')

  const form = new FormData()
  form.append('image', fs.createReadStream(path.join(__dirname, `${imageId}${IMAGE_FILE_EXT}`)))

  core.info('Uploading image to imgur...')

  try {
    const res = await Axios.post(IMGUR_API_URL, form, {
      headers: {
        Authorization: `Client-ID ${clientId}`,
        ...form.getHeaders()
      }
    })

    return res.data.data.link
  } catch (error) {
    core.error('An error occurred when trying to upload image to imgur')
    core.debug(error)

    throw error
  }
}

/**
 * Replaces the code block in a comment with the
 * corresponding image's url
 * @param {String} commentBody The entire comment body
 * @param {String} imageUrl The image to replace the code block with
 */
function replaceCodeBlockWithImage (commentBody, imageUrl) {
  // TODO - Support more than one code block
  const codeblock = gcb(commentBody)[0]

  // ! DO NOT change the formatting for this constant's value
  // ! Intentionally set this way for the markdown to be correct during render
  const replaceWith = `\n<p align="center"><img src="${imageUrl}"/></p>\n\n---\n\n<details><summary>View raw code</summary>
<p>

${codeblock.block}

</p></details>\n\n---\n\n`

  return commentBody.replace(codeblock.block, replaceWith)
}

/**
 * Updates the comment
 * @param {Object} comment Details about the comment
 */
async function updateComment (comment) {
  const githubToken = core.getInput('github-token')

  const octokit = github.getOctokit(githubToken)

  core.info('Updating comment...')

  try {
    await octokit.issues.updateComment(comment)
  } catch (error) {
    core.error('Error occurred updating the comment')
    core.debug(error)

    throw error
  }
}

/**
 * Updates the issue
 * @param {Object} issue Details about the issue
 */
async function updateIssue (issue) {
  const githubToken = core.getInput('github-token')

  const octokit = github.getOctokit(githubToken)

  core.info('Updating issue...')

  try {
    await octokit.issues.update(issue)
  } catch (error) {
    core.error('Error occurred updating the issue')
    core.debug(error)

    throw error
  }
}

/**
 * Main function
 */
async function execute () {
  let imageId
  let code
  let body
  const usePrettier = core.getInput('use-prettier') === 'true'
  const prettierParser = core.getInput('prettier-parser')
  let prettierOptions = {}
  let carbonOptions = {}

  try {
    prettierOptions = JSON.parse(core.getInput('prettier-options'))
  } catch (error) {
    core.info('Prettier options is not passed or not a valid JSON string. Falling back to default')
  }

  try {
    carbonOptions = JSON.parse(core.getInput('carbon-options'))
  } catch (error) {
    core.info('Carbon options is not passed or not a valid JSON string. Falling back to default')
  }

  try {
    const { eventName, payload } = github.context

    core.debug(`Event name: ${eventName}`)
    core.debug(`Payload action: ${payload.action}`)

    if (eventName !== 'issues' && eventName !== 'issue_comment') {
      core.info(`Unsupported event ${eventName}`)

      return
    }

    core.debug('Is a supported event')

    if ((eventName === 'issues' && payload.action !== 'opened') ||
      (eventName === 'issue_comment' && payload.action !== 'created')) {
      core.info(`Unsupported type ${payload.action} for event ${eventName}`)

      return
    }

    core.debug('Is a supported type')

    if (eventName === 'issues') {
      body = payload.issue.body
    } else {
      body = payload.comment.body
    }

    core.debug(`Body is ${body}`)

    core.debug('Before extracting code blocks')

    const codeblocks = gcb(body)

    core.debug('After extracting code blocks')

    // TODO - Support more than one code block
    if (codeblocks.length !== 1) {
      core.info('No code block found or more than one code block found. Unsupported scenario for now. Quitting.')
      return
    }

    core.debug(`Is prettier active: ${usePrettier}`)

    if (usePrettier) {
      code = formatCode(codeblocks[0].code, prettierOptions, prettierParser)
    } else {
      code = codeblocks[0].code
    }

    core.debug(`Extracted code block is ${code}`)

    imageId = await generateImage(code, carbonOptions)

    const imageUrl = await uploadImage(imageId)

    core.debug(`The imgur url is ${imageUrl}`)

    const updatedComment = replaceCodeBlockWithImage(body, imageUrl)

    core.debug(`The updated comment is ${updateComment}`)

    const updates = {
      owner: payload.repository.owner.login,
      repo: payload.repository.name,
      body: updatedComment
    }

    if (eventName === 'issues') {
      updates.issue_number = payload.issue.number

      await updateIssue(updates)
    } else {
      updates.comment_id = payload.comment.id

      await updateComment(updates)
    }

    core.info('Task completed')
  } catch (error) {
    core.setFailed(error.message)
  } finally {
    core.startGroup('View event payload')
    core.debug(JSON.stringify(github, null, 4))
    core.endGroup()
    // Cleanup
    if (imageId) {
      await unlink(path.resolve(__dirname, `${imageId}${IMAGE_FILE_EXT}`))
    }
  }
}

execute()


================================================
FILE: package.json
================================================
{
  "name": "carbonate",
  "version": "1.0.1",
  "description": "Github action that generates beautiful images for code blocks present in issues",
  "main": "index.js",
  "scripts": {
    "lint": "standard index.js"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/callmekatootie/carbonate.git"
  },
  "keywords": [],
  "author": "",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/callmekatootie/carbonate/issues"
  },
  "homepage": "https://github.com/callmekatootie/carbonate#readme",
  "dependencies": {
    "@actions/core": "^1.2.4",
    "@actions/github": "^4.0.0",
    "axios": "^0.19.2",
    "form-data": "^3.0.0",
    "gfm-code-blocks": "^1.0.0",
    "prettier": "^2.0.5",
    "uuid": "^8.3.0"
  },
  "devDependencies": {
    "standard": "^14.3.4"
  }
}
Download .txt
gitextract_o0qpgg0z/

├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── LICENSE
├── README.md
├── action.yml
├── constants.js
├── index.js
└── package.json
Download .txt
SYMBOL INDEX (11 symbols across 2 files)

FILE: constants.js
  constant IMAGE_FILE_EXT (line 1) | const IMAGE_FILE_EXT = '.png'
  constant IMGUR_API_URL (line 3) | const IMGUR_API_URL = 'https://api.imgur.com/3/image'
  constant CARBON_API_URL (line 5) | const CARBON_API_URL = 'https://carbonara-42.herokuapp.com/api/cook'
  constant CARBON_DEFAULT_SETTINGS (line 7) | const CARBON_DEFAULT_SETTINGS = {

FILE: index.js
  function formatCode (line 26) | function formatCode (code, options, parser) {
  function generateImage (line 43) | async function generateImage (code, options) {
  function uploadImage (line 92) | async function uploadImage (imageId) {
  function replaceCodeBlockWithImage (line 123) | function replaceCodeBlockWithImage (commentBody, imageUrl) {
  function updateComment (line 143) | async function updateComment (comment) {
  function updateIssue (line 164) | async function updateIssue (issue) {
  function execute (line 184) | async function execute () {
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (17K chars).
[
  {
    "path": ".github/workflows/main.yml",
    "chars": 494,
    "preview": "on:\n  issue_comment:\n    types: [created]\n  issues:\n    types: [opened]\n\njobs:\n  carbonate:\n    runs-on: ubuntu-latest\n "
  },
  {
    "path": ".gitignore",
    "chars": 89,
    "preview": "# Ignoring the folder where I have the debug data, for easier reference during dev\ndata/\n"
  },
  {
    "path": "LICENSE",
    "chars": 1070,
    "preview": "MIT License\n\nCopyright (c) 2020 Mithun Kamath\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
  },
  {
    "path": "README.md",
    "chars": 4302,
    "preview": "# Carbonate\n\nJazz up the code blocks in your issues. Generate beautiful images for them to make it easier to follow. Mea"
  },
  {
    "path": "action.yml",
    "chars": 1435,
    "preview": "---\nname: 'Carbonate'\ndescription: 'Generate beautiful images for code blocks present in issues'\ninputs:\n  github-token:"
  },
  {
    "path": "constants.js",
    "chars": 710,
    "preview": "const IMAGE_FILE_EXT = '.png'\n\nconst IMGUR_API_URL = 'https://api.imgur.com/3/image'\n\nconst CARBON_API_URL = 'https://ca"
  },
  {
    "path": "index.js",
    "chars": 7480,
    "preview": "const core = require('@actions/core')\nconst github = require('@actions/github')\nconst gcb = require('gfm-code-blocks')\nc"
  },
  {
    "path": "package.json",
    "chars": 806,
    "preview": "{\n  \"name\": \"carbonate\",\n  \"version\": \"1.0.1\",\n  \"description\": \"Github action that generates beautiful images for code "
  }
]

About this extraction

This page contains the full source code of the callmekatootie/carbonate GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (16.0 KB), approximately 4.2k tokens, and a symbol index with 11 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!