Skip to content

Instantly share code, notes, and snippets.

@george-gca
Last active March 13, 2024 19:06
Show Gist options
  • Save george-gca/fbc4664dce3e97796d1fa212f769c6bb to your computer and use it in GitHub Desktop.
Save george-gca/fbc4664dce3e97796d1fa212f769c6bb to your computer and use it in GitHub Desktop.
markdown-to-google-forms.ipynb
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": [],
"authorship_tag": "ABX9TyPzY3GhiaMSCsuGwOdeHk86",
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/george-gca/fbc4664dce3e97796d1fa212f769c6bb/markdown-to-google-forms.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"source": [
"## Introduction"
],
"metadata": {
"id": "mLuqAQDqRMi0"
}
},
{
"cell_type": "markdown",
"source": [
"This is not the best solution possible, but it is a solution. One can probably implement something more robust by using libraries like [marko](https://github.com/frostming/marko) or [mistletoe](https://github.com/miyuchina/mistletoe).\n",
"\n",
"This solution converts a markdown style document into a Google Apps Script code that in turn creates a Google Forms."
],
"metadata": {
"id": "2vqh_UBFRORi"
}
},
{
"cell_type": "markdown",
"source": [
"## Creating functions"
],
"metadata": {
"id": "DC63lWMq2T6g"
}
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"id": "OuVnnzpyAmTO"
},
"outputs": [],
"source": [
"import logging\n",
"import re\n",
"from typing import Any\n",
"# from IPython.display import HTML\n",
"# from ipywidgets import HTML"
]
},
{
"cell_type": "code",
"source": [
"_logger = logging.getLogger(__name__)\n",
"\n",
"\n",
"def begin_create_form():\n",
" _logger.debug('Creating form')\n",
" return 'function createForm() {\\n'\n",
"\n",
"\n",
"def end_create_form():\n",
" _logger.debug('Form created')\n",
" return '}'\n",
"\n",
"\n",
"def _concatenate_lines(lines: list[str] | tuple[str], identation_level: int = 1, identation: str = 2 * ' '):\n",
" return '\\n'.join([f'{identation * identation_level}{line}' for line in lines])\n",
"\n",
"\n",
"def create_form(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" confirmation_message = kwargs.get('confirmation_message', '')\n",
"\n",
" lines = [f'var form = FormApp.create(\"{title}\")']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setDescription(\"{description}\")')\n",
"\n",
" if len(confirmation_message) > 0:\n",
" lines.append(f' .setConfirmationMessage(\"{confirmation_message}\")')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" lines.append('var sections = {};\\n')\n",
"\n",
" return _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_section(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addpagebreakitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
"\n",
" lines = ['var section = form.addPageBreakItem()',\n",
" f' .setTitle(\"{title}\");\\n',\n",
" f'sections[\"{title}\"] = section;\\n']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" _logger.debug(f'Creating section: {title} - {description}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def edit_section(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addpagebreakitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
"\n",
" lines = [f'sections[\"{title}\"]',\n",
" f' .setTitle(\"{title}\")']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Editing section: {title} - {description}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_title_and_description_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addsectionheaderitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
"\n",
" lines = ['form.addSectionHeaderItem()',\n",
" f' .setTitle(\"{title}\")']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating title and description item: {title} - {description}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_short_text_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addtextitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
"\n",
" lines = ['form.addTextItem()',\n",
" f' .setTitle(\"{title}\")']\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating short text item: {title}{\" (required)\" if required else \"\"} - {description}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_paragraph_text_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addparagraphtextitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
"\n",
" lines = ['form.addParagraphTextItem()',\n",
" f' .setTitle(\"{title}\")']\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating paragraph text item: {title}{\" (required)\" if required else \"\"} - {description}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_multiple_choice_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addmultiplechoiceitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
" choices = kwargs.get('choices', [])\n",
"\n",
" if any(c.startswith('item.createChoice(') for c in choices):\n",
" lines = ['var item = form.addMultipleChoiceItem()',\n",
" f' .setTitle(\"{title}\");\\n']\n",
"\n",
" lines.append('item.setChoices([')\n",
" for choice in choices:\n",
" lines.append(f' {choice},')\n",
"\n",
" lines[-1] = lines[-1][:-1]\n",
" lines.append(' ])')\n",
"\n",
" else:\n",
" lines = ['form.addMultipleChoiceItem()',\n",
" f' .setTitle(\"{title}\")',\n",
" f' .setChoiceValues({choices})']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" # TODO .showOtherOption(true);\n",
"\n",
" _logger.debug(f'Creating multiple choice item: {title}{\" (required)\" if required else \"\"} - {description}\\nchoices: {choices}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_checkbox_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addcheckboxitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
" choices = kwargs.get('choices', [])\n",
"\n",
" if any(c.startswith('item.createChoice(') for c in choices):\n",
" lines = ['var item = form.addMultipleChoiceItem()',\n",
" f' .setTitle(\"{title}\");']\n",
"\n",
" lines.append('item.setChoices([')\n",
" for choice in choices:\n",
" lines.append(f' {choice},')\n",
"\n",
" lines[-1] = lines[-1][:-1]\n",
" lines.append(' ])')\n",
"\n",
" else:\n",
" lines = ['form.addMultipleChoiceItem()',\n",
" f' .setTitle(\"{title}\")',\n",
" f' .setChoiceValues({choices})']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating checkbox item: {title}{\" (required)\" if required else \"\"} - {description}\\nchoices: {choices}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_list_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addlistitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
" choices = kwargs.get('choices', [])\n",
"\n",
" if any(c.startswith('item.createChoice(') for c in choices):\n",
" lines = ['var item = form.addMultipleChoiceItem()',\n",
" f' .setTitle(\"{title}\");']\n",
"\n",
" lines.append('item.setChoices([')\n",
" for choice in choices:\n",
" lines.append(f' {choice},')\n",
"\n",
" lines[-1] = lines[-1][:-1]\n",
" lines.append(' ])')\n",
"\n",
" else:\n",
" lines = ['form.addMultipleChoiceItem()',\n",
" f' .setTitle(\"{title}\")',\n",
" f' .setChoiceValues({choices})']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating list item: {title}{\" (required)\" if required else \"\"} - {description}\\nchoices: {choices}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_scale_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addscaleitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
" min_label = kwargs.get('min_label', '')\n",
" max_label = kwargs.get('max_label', '')\n",
" min_value = kwargs.get('min', 0)\n",
" max_value = kwargs.get('max', -1)\n",
"\n",
" lines = ['form.addScaleItem()',\n",
" f' .setTitle(\"{title}\")',\n",
" f' .setBounds({min_value}, {max_value})',\n",
" f' .setLabels(\"{min_label}\", \"{max_label}\")']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating scale item: {title}{\" (required)\" if required else \"\"} - {description}\\nmin ({min_label}): {min_value} - max ({max_label}): {max_value}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_date_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#adddateitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
"\n",
" lines = ['form.addDateItem()',\n",
" f' .setTitle(\"{title}\")']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating date item: {title}{\" (required)\" if required else \"\"} - {description}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_time_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addtimeitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
"\n",
" lines = ['form.addTimeItem()',\n",
" f' .setTitle(\"{title}\")']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating time item: {title}{\" (required)\" if required else \"\"} - {description}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_date_time_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#adddatetimeitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
"\n",
" lines = ['form.addDateTimeItem()',\n",
" f' .setTitle(\"{title}\")']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating date time item: {title}{\" (required)\" if required else \"\"} - {description}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_duration_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#adddurationitem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
"\n",
" lines = ['form.addDurationItem()',\n",
" f' .setTitle(\"{title}\")']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating duration item: {title}{\" (required)\" if required else \"\"} - {description}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_grid_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addgriditem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
" rows = kwargs.get('rows', [])\n",
" columns = kwargs.get('columns', [])\n",
"\n",
" lines = ['form.addGridItem()',\n",
" f' .setTitle(\"{title}\")',\n",
" f' .setRows({rows})',\n",
" f' .setColumns({columns})']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating grid item: {title}{\" (required)\" if required else \"\"} - {description}\\nrows: {rows}\\ncolumns: {columns}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def create_checkbox_grid_item(**kwargs) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#addcheckboxgriditem\n",
" title = kwargs.get('title', '')\n",
" description = kwargs.get('description', '')\n",
" required = kwargs.get('required', False)\n",
" rows = kwargs.get('rows', [])\n",
" columns = kwargs.get('columns', [])\n",
"\n",
" lines = ['form.addCheckboxGridItem()',\n",
" f' .setTitle(\"{title}\")',\n",
" f' .setRows({rows})',\n",
" f' .setColumns({columns})']\n",
"\n",
" if len(description) > 0:\n",
" lines.append(f' .setHelpText(\"{description}\")')\n",
"\n",
" if required:\n",
" lines.append(' .setRequired(true)')\n",
"\n",
" lines[-1] += ';\\n'\n",
"\n",
" _logger.debug(f'Creating checkbox grid item: {title}{\" (required)\" if required else \"\"} - {description}\\nrows: {rows}\\ncolumns: {columns}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def move_section_to_end_of_form(title: str) -> str:\n",
" # https://developers.google.com/apps-script/reference/forms/form#moveitemto\n",
"\n",
" lines = [f'form.moveItem(form.getItemById(sections[\"{title}\"].getId()), form.getItems().length - 1);\\n']\n",
" # lines = [f'form.moveItem(sections[\"{title}\"], form.getItems().length - 1);\\n']\n",
"\n",
" _logger.debug(f'Moving section to end of form: {title}')\n",
"\n",
" return '\\n' + _concatenate_lines(lines)\n",
"\n",
"\n",
"def _reset_args(args: dict[str, Any]) -> None:\n",
" args['title'] = ''\n",
" args['description'] = ''\n",
" args['required'] = False\n",
" args['choices'] = []\n",
" args['rows'] = []\n",
" args['columns'] = []\n",
"\n",
"\n",
"def main(markdown_file: str) -> None:\n",
" main_title_regex = re.compile(r'^#[\\s]*(.*)$')\n",
" confirmation_message_regex = re.compile(r'^_(.*)_$')\n",
" section_regex = re.compile(r'^##[\\s]*(.*)$')\n",
" title_regex = re.compile(r'^###[\\s]*(.*)$')\n",
" combobox_regex = re.compile(r'^-[\\s]*(.*)$')\n",
" radio_button_regex = re.compile(r'^\\*[\\s]*(.*)$')\n",
" checkbox_regex = re.compile(r'^([-*][\\s]*)?\\[[\\s]*\\] (.*)$')\n",
" navigation_regex = re.compile(r'^(.*) \\[(.*)\\]$')\n",
" paragraph_regex = re.compile(r'^[\\s]*```(.|\\s)*```[\\s]*$')\n",
" short_text_regex = re.compile(r'^`(.*)`$')\n",
" required_regex = re.compile(r'^\\*\\*(.*)\\*\\*$')\n",
" scale_regex = re.compile(r'^(.*) (\\d)+ --- (\\d)+ (.*)$')\n",
" date_regex = re.compile(r'^dd|[\\d]{2}/mm|[\\d]{2}/yyyy|[\\d]{4}$')\n",
" time_regex = re.compile(r'^hh|[\\d]{2}:mm|[\\d]{2}$')\n",
" date_time_regex = re.compile(r'^dd|[\\d]{2}/mm|[\\d]{2}/yyyy|[\\d]{4} hh|[\\d]{2}:mm|[\\d]{2}$')\n",
" duration_regex = re.compile(r'^hh|[\\d]{2}:mm|[\\d]{2}:ss|[\\d]{2}$')\n",
" column_row_radio_button_grid_regex = re.compile(r'^####[\\s]*(.*)$')\n",
" column_row_checkbox_grid_regex = re.compile(r'^####[\\s]*\\[[\\s]*\\] (.*)$')\n",
"\n",
"\n",
" current_function = None\n",
" grid = False\n",
" code = begin_create_form()\n",
" created_main_title = False\n",
" created_first_item = False\n",
"\n",
" row = False\n",
"\n",
" args = {\n",
" 'title': '',\n",
" 'confirmation_message': '',\n",
" 'description': '',\n",
" 'required': False,\n",
" 'choices': [],\n",
" 'rows': [],\n",
" 'columns': [],\n",
" 'min': -1,\n",
" 'max': -1,\n",
" 'min_label': '',\n",
" 'max_label': '',\n",
" }\n",
"\n",
" for i, line in enumerate(markdown_file.split('\\n')):\n",
" _logger.debug(f'Processing line {i}: {line}')\n",
" # the order of function calls here matters\n",
" line = line.strip()\n",
" if len(line) == 0:\n",
" continue\n",
"\n",
" match = column_row_checkbox_grid_regex.match(line)\n",
" if match is not None:\n",
" row = match.group(1).strip().lower() == 'rows'\n",
" current_function = create_checkbox_grid_item\n",
" grid = True\n",
" continue\n",
"\n",
" match = column_row_radio_button_grid_regex.match(line)\n",
" if match is not None:\n",
" row = match.group(1).strip().lower() == 'rows'\n",
" current_function = create_grid_item\n",
" grid = True\n",
" continue\n",
"\n",
" # when reaching a new title or section, create the previous item\n",
" match = title_regex.match(line)\n",
" if match is not None:\n",
" if current_function is not None:\n",
" if current_function == create_form:\n",
" created_main_title = True\n",
"\n",
" code += current_function(**args)\n",
" grid = False\n",
"\n",
" if current_function == edit_section:\n",
" code += move_section_to_end_of_form(args['title'])\n",
"\n",
" _reset_args(args)\n",
" current_function = None\n",
"\n",
" elif created_first_item:\n",
" code += create_title_and_description_item(**args)\n",
" grid = False\n",
" _reset_args(args)\n",
"\n",
" else:\n",
" created_first_item = True\n",
"\n",
" line = match.group(1)\n",
" match = required_regex.match(line)\n",
" if match is not None:\n",
" args['required'] = True\n",
" args['title'] = match.group(1)\n",
"\n",
" else:\n",
" args['title'] = line\n",
" continue\n",
"\n",
" match = section_regex.match(line)\n",
" if match is not None:\n",
" if current_function is not None:\n",
" if current_function == create_form:\n",
" created_main_title = True\n",
"\n",
" code += current_function(**args)\n",
" grid = False\n",
" _reset_args(args)\n",
" current_function = None\n",
"\n",
" elif created_first_item:\n",
" code += create_title_and_description_item(**args)\n",
" grid = False\n",
" _reset_args(args)\n",
"\n",
" else:\n",
" created_first_item = True\n",
"\n",
" args['title'] = match.group(1)\n",
" current_function = edit_section\n",
" continue\n",
"\n",
" match = main_title_regex.match(line)\n",
" if match is not None:\n",
" if created_main_title:\n",
" raise Exception('Main title already created')\n",
"\n",
" args['title'] = match.group(1)\n",
" current_function = create_form\n",
" continue\n",
"\n",
" match = confirmation_message_regex.match(line)\n",
" if match is not None:\n",
" confirmation_message = match.group(1)\n",
" args['confirmation_message'] = confirmation_message\n",
" continue\n",
"\n",
" match = paragraph_regex.match(line)\n",
" if match is not None:\n",
" current_function = create_paragraph_text_item\n",
" continue\n",
"\n",
" match = short_text_regex.match(line)\n",
" if match is not None:\n",
" current_function = create_short_text_item\n",
" continue\n",
"\n",
" match = checkbox_regex.match(line)\n",
" if match is not None:\n",
" if created_first_item:\n",
" if grid:\n",
" if row:\n",
" args['rows'].append(match.group(2))\n",
" else:\n",
" args['columns'].append(match.group(2))\n",
"\n",
" else:\n",
" option = match.group(2)\n",
" match = navigation_regex.match(option)\n",
" if match is not None:\n",
" option = match.group(1)\n",
" section = match.group(2)\n",
" args['choices'].append(f'item.createChoice(\"{option}\", sections[\"{section}\"])')\n",
"\n",
" else:\n",
" args['choices'].append(option)\n",
"\n",
" current_function = create_checkbox_item\n",
"\n",
" else:\n",
" if current_function == create_form:\n",
" created_main_title = True\n",
" code += current_function(**args)\n",
" _reset_args(args)\n",
" current_function = None\n",
" grid = False\n",
"\n",
" code += create_section(title=match.group(2))\n",
"\n",
" continue\n",
"\n",
" match = radio_button_regex.match(line)\n",
" if match is not None:\n",
" if created_first_item:\n",
" if grid:\n",
" if row:\n",
" args['rows'].append(match.group(1))\n",
" else:\n",
" args['columns'].append(match.group(1))\n",
"\n",
" else:\n",
" option = match.group(1)\n",
" match = navigation_regex.match(option)\n",
" if match is not None:\n",
" option = match.group(1)\n",
" section = match.group(2)\n",
" args['choices'].append(f'item.createChoice(\"{option}\", sections[\"{section}\"])')\n",
"\n",
" else:\n",
" args['choices'].append(option)\n",
"\n",
" current_function = create_multiple_choice_item\n",
"\n",
" else:\n",
" if current_function == create_form:\n",
" created_main_title = True\n",
" code += current_function(**args)\n",
" _reset_args(args)\n",
" current_function = None\n",
" grid = False\n",
"\n",
" code += create_section(title=match.group(1))\n",
"\n",
" continue\n",
"\n",
" match = combobox_regex.match(line)\n",
" if match is not None:\n",
" if created_first_item:\n",
" if grid:\n",
" if row:\n",
" args['rows'].append(match.group(1))\n",
" else:\n",
" args['columns'].append(match.group(1))\n",
"\n",
" else:\n",
" option = match.group(1)\n",
" match = navigation_regex.match(option)\n",
" if match is not None:\n",
" option = match.group(1)\n",
" section = match.group(2)\n",
" args['choices'].append(f'item.createChoice(\"{option}\", sections[\"{section}\"])')\n",
"\n",
" else:\n",
" args['choices'].append(option)\n",
" current_function = create_list_item\n",
"\n",
" else:\n",
" if current_function == create_form:\n",
" created_main_title = True\n",
" code += current_function(**args)\n",
" _reset_args(args)\n",
" current_function = None\n",
" grid = False\n",
"\n",
" code += create_section(title=match.group(1))\n",
"\n",
" continue\n",
"\n",
" match = scale_regex.match(line)\n",
" if match is not None:\n",
" args['min_label'] = match.group(1)\n",
" args['min'] = match.group(2)\n",
" args['max'] = match.group(3)\n",
" args['max_label'] = match.group(4)\n",
" current_function = create_scale_item\n",
" continue\n",
"\n",
" match = date_time_regex.match(line)\n",
" if match is not None:\n",
" current_function = create_date_time_item\n",
" continue\n",
"\n",
" match = date_regex.match(line)\n",
" if match is not None:\n",
" current_function = create_date_item\n",
" continue\n",
"\n",
" match = duration_regex.match(line)\n",
" if match is not None:\n",
" current_function = create_duration_item\n",
" continue\n",
"\n",
" match = time_regex.match(line)\n",
" if match is not None:\n",
" current_function = create_time_item\n",
" continue\n",
"\n",
" args['description'] = line\n",
"\n",
" # finished reading the file, create the last item\n",
" if current_function is not None:\n",
" code += current_function(**args)\n",
" _reset_args(args)\n",
" current_function = None\n",
"\n",
" code += end_create_form()\n",
"\n",
" return code"
],
"metadata": {
"id": "AOlOwYD_2IiX"
},
"execution_count": 2,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Creating markdown"
],
"metadata": {
"id": "QAD4g2Hi2Zm9"
}
},
{
"cell_type": "code",
"source": [
"markdown_file = \"\"\"\n",
"# Forms Title\n",
"\n",
"_Thanks for testing this script!_\n",
"\n",
"This is a test script to convert a markdown file to a Google Forms script. It is still in development, so it may not work as expected. If you want to have more than one section, you must first explicit their names here:\n",
"\n",
"- Section 2\n",
"- Section 3\n",
"\n",
"### **Radio buttons**\n",
"\n",
"Use `*` at the start of each line to indicate that the list is a radio button list. If you want any item to be required, write the text between `**`.\n",
"\n",
"* Radio Navigation Option 1 [Section 2]\n",
"* Radio Navigation Option 2 [Section 3]\n",
"\n",
"### Title and description\n",
"\n",
"Use this to add a title and a description to the form.\n",
"\n",
"\n",
"\n",
"## Section 2\n",
"\n",
"Section 2 description\n",
"\n",
"### Short text 1\n",
"\n",
"`This indicates a short text field, and its contents will be ignored.`\n",
"\n",
"### Long text 1\n",
"\n",
"```\n",
"This indicates a long text field, and its contents will be ignored.\n",
"```\n",
"\n",
"### Title and description 1\n",
"\n",
"Use this to add a title and a description to the form.\n",
"\n",
"### **Radio buttons 1**\n",
"\n",
"Use `*` at the start of each line to indicate that the list is a radio button list. If you want any item to be required, write the text between `**`.\n",
"\n",
"* Radio Option 1\n",
"* Radio Option 2\n",
"* Radio Option 3\n",
"\n",
"### Combobox 1\n",
"\n",
"Use `-` at the start of each line to indicate that the list is a radio button list.\n",
"\n",
"- Combo Option 1\n",
"- Combo Option 2\n",
"- Combo Option 3\n",
"\n",
"### Checkboxes 1\n",
"\n",
"Use `[]` at the start of each line to indicate that the list is a checkbox list. It doesn't matter if it starts with `-` or `*`, or even if the checkoxes have a space or not inside.\n",
"\n",
"- [ ] Check Option 1\n",
"[ ] Check Option 2\n",
"[] Check Option 3\n",
"\n",
"### Scale 1\n",
"\n",
"To create a scale, simply write the lowest label and its value, then a `---`, and finally the highest value and its label, in this order.\n",
"\n",
"Lowest 1 --- 5 Highest\n",
"\n",
"### Date 1\n",
"\n",
"To create a date item, simply write this date format.\n",
"\n",
"dd/mm/yyyy\n",
"\n",
"### Time 1\n",
"\n",
"To create a time item, simply write this time format.\n",
"\n",
"hh:mm\n",
"\n",
"### Date and time 1\n",
"\n",
"To create a date and time item, simply write this date and time format.\n",
"\n",
"dd/mm/yyyy hh:mm\n",
"\n",
"### Duration 1\n",
"\n",
"To create a duration item, simply write this duration format.\n",
"\n",
"hh:mm:ss\n",
"\n",
"### RadioButton Grid\n",
"\n",
"To create a radio button grid, simply write the rows and columns. Note that the rows **MUST BE** written as `#### rows` and the columns **MUST BE** written as `#### columns`, ignoring case.\n",
"\n",
"#### Rows\n",
"\n",
"- Row 1\n",
"- Row 2\n",
"- Row 3\n",
"\n",
"#### Columns\n",
"\n",
"- Column 1\n",
"- Column 2\n",
"- Column 3\n",
"\n",
"### Checkbox Grid\n",
"\n",
"To create a checkbox grid, simply write the rows and columns. Note that the rows **MUST BE** written as `#### [] rows` and the columns **MUST BE** written as `#### [] columns`, ignoring case.\n",
"\n",
"#### [] Rows\n",
"\n",
"- Row 1\n",
"- Row 2\n",
"- Row 3\n",
"\n",
"#### [] Columns\n",
"\n",
"- Column 1\n",
"- Column 2\n",
"- Column 3\n",
"\n",
"\n",
"\n",
"## Section 3\n",
"\n",
"Section 3 description\n",
"\n",
"### Short text 2\n",
"\n",
"`This indicates a short text field, and its contents will be ignored.`\n",
"\n",
"### Long text 2\n",
"\n",
"```\n",
"This indicates a long text field, and its contents will be ignored.\n",
"```\n",
"\n",
"### Title and description 2\n",
"\n",
"Use this to add a title and a description to the form.\n",
"\n",
"### **Radio buttons 2**\n",
"\n",
"Use `*` at the start of each line to indicate that the list is a radio button list. If you want any item to be required, write the text between `**`.\n",
"\n",
"* Radio Option 1\n",
"* Radio Option 2\n",
"* Radio Option 3\n",
"\n",
"### Combobox 2\n",
"\n",
"Use `-` at the start of each line to indicate that the list is a radio button list.\n",
"\n",
"- Combo Option 1\n",
"- Combo Option 2\n",
"- Combo Option 3\n",
"\n",
"### Checkboxes 2\n",
"\n",
"Use `[]` at the start of each line to indicate that the list is a checkbox list. It doesn't matter if it starts with `-` or `*`, or even if the checkoxes have a space or not inside.\n",
"\n",
"- [ ] Check Option 1\n",
"[ ] Check Option 2\n",
"[] Check Option 3\n",
"\n",
"### Scale 2\n",
"\n",
"To create a scale, simply write the lowest label and its value, then a `---`, and finally the highest value and its label, in this order.\n",
"\n",
"Lowest 1 --- 5 Highest\n",
"\n",
"### Date 2\n",
"\n",
"To create a date item, simply write this date format.\n",
"\n",
"dd/mm/yyyy\n",
"\n",
"### Time 2\n",
"\n",
"To create a time item, simply write this time format.\n",
"\n",
"hh:mm\n",
"\n",
"### Date and time 2\n",
"\n",
"To create a date and time item, simply write this date and time format.\n",
"\n",
"dd/mm/yyyy hh:mm\n",
"\n",
"### Duration 2\n",
"\n",
"To create a duration item, simply write this duration format.\n",
"\n",
"hh:mm:ss\n",
"\n",
"### RadioButton Grid\n",
"\n",
"To create a radio button grid, simply write the rows and columns. Note that the rows **MUST BE** written as `#### rows` and the columns **MUST BE** written as `#### columns`, ignoring case.\n",
"\n",
"#### Rows\n",
"\n",
"- Row 1\n",
"- Row 2\n",
"- Row 3\n",
"\n",
"#### Columns\n",
"\n",
"- Column 1\n",
"- Column 2\n",
"- Column 3\n",
"\n",
"### Checkbox Grid\n",
"\n",
"To create a checkbox grid, simply write the rows and columns. Note that the rows **MUST BE** written as `#### [] rows` and the columns **MUST BE** written as `#### [] columns`, ignoring case.\n",
"\n",
"#### [] Rows\n",
"\n",
"- Row 1\n",
"- Row 2\n",
"- Row 3\n",
"\n",
"#### [] Columns\n",
"\n",
"- Column 1\n",
"- Column 2\n",
"- Column 3\n",
"\n",
"\"\"\""
],
"metadata": {
"id": "gGAf6WZK2cU1"
},
"execution_count": 3,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Converting to Google Apps Script"
],
"metadata": {
"id": "4bBUQFHBRB-A"
}
},
{
"cell_type": "code",
"source": [
"javascript_code = main(markdown_file)\n",
"print(javascript_code)\n",
"# print()\n",
"# HTML(data=f\"<button onclick=navigator.clipboard.writeText('{javascript_code}')>Copy code</button>\")"
],
"metadata": {
"id": "V1U0xM_X4dZ2",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "b59986af-30d4-4c3f-c0d1-744d337e9107"
},
"execution_count": 4,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"function createForm() {\n",
" var form = FormApp.create(\"Forms Title\")\n",
" .setDescription(\"This is a test script to convert a markdown file to a Google Forms script. It is still in development, so it may not work as expected. If you want to have more than one section, you must first explicit their names here:\")\n",
" .setConfirmationMessage(\"Thanks for testing this script!\");\n",
"\n",
" var sections = {};\n",
"\n",
" var section = form.addPageBreakItem()\n",
" .setTitle(\"Section 2\");\n",
"\n",
" sections[\"Section 2\"] = section;\n",
"\n",
" var section = form.addPageBreakItem()\n",
" .setTitle(\"Section 3\");\n",
"\n",
" sections[\"Section 3\"] = section;\n",
"\n",
" var item = form.addMultipleChoiceItem()\n",
" .setTitle(\"Radio buttons\");\n",
"\n",
" item.setChoices([\n",
" item.createChoice(\"Radio Navigation Option 1\", sections[\"Section 2\"]),\n",
" item.createChoice(\"Radio Navigation Option 2\", sections[\"Section 3\"])\n",
" ])\n",
" .setHelpText(\"Use `*` at the start of each line to indicate that the list is a radio button list. If you want any item to be required, write the text between `**`.\")\n",
" .setRequired(true);\n",
"\n",
" form.addSectionHeaderItem()\n",
" .setTitle(\"Title and description\")\n",
" .setHelpText(\"Use this to add a title and a description to the form.\");\n",
"\n",
" sections[\"Section 2\"]\n",
" .setTitle(\"Section 2\")\n",
" .setHelpText(\"Section 2 description\");\n",
"\n",
" form.moveItem(form.getItemById(sections[\"Section 2\"].getId()), form.getItems().length - 1);\n",
"\n",
" form.addTextItem()\n",
" .setTitle(\"Short text 1\");\n",
"\n",
" form.addTextItem()\n",
" .setTitle(\"Long text 1\")\n",
" .setHelpText(\"This indicates a long text field, and its contents will be ignored.\");\n",
"\n",
" form.addSectionHeaderItem()\n",
" .setTitle(\"Title and description 1\")\n",
" .setHelpText(\"Use this to add a title and a description to the form.\");\n",
"\n",
" form.addMultipleChoiceItem()\n",
" .setTitle(\"Radio buttons 1\")\n",
" .setChoiceValues(['Radio Option 1', 'Radio Option 2', 'Radio Option 3'])\n",
" .setHelpText(\"Use `*` at the start of each line to indicate that the list is a radio button list. If you want any item to be required, write the text between `**`.\")\n",
" .setRequired(true);\n",
"\n",
" form.addMultipleChoiceItem()\n",
" .setTitle(\"Combobox 1\")\n",
" .setChoiceValues(['Combo Option 1', 'Combo Option 2', 'Combo Option 3'])\n",
" .setHelpText(\"Use `-` at the start of each line to indicate that the list is a radio button list.\");\n",
"\n",
" form.addMultipleChoiceItem()\n",
" .setTitle(\"Checkboxes 1\")\n",
" .setChoiceValues(['Check Option 1', 'Check Option 2', 'Check Option 3'])\n",
" .setHelpText(\"Use `[]` at the start of each line to indicate that the list is a checkbox list. It doesn't matter if it starts with `-` or `*`, or even if the checkoxes have a space or not inside.\");\n",
"\n",
" form.addScaleItem()\n",
" .setTitle(\"Scale 1\")\n",
" .setBounds(1, 5)\n",
" .setLabels(\"Lowest\", \"Highest\")\n",
" .setHelpText(\"To create a scale, simply write the lowest label and its value, then a `---`, and finally the highest value and its label, in this order.\");\n",
"\n",
" form.addDateTimeItem()\n",
" .setTitle(\"Date 1\")\n",
" .setHelpText(\"To create a date item, simply write this date format.\");\n",
"\n",
" form.addDurationItem()\n",
" .setTitle(\"Time 1\")\n",
" .setHelpText(\"To create a time item, simply write this time format.\");\n",
"\n",
" form.addDateTimeItem()\n",
" .setTitle(\"Date and time 1\")\n",
" .setHelpText(\"To create a date and time item, simply write this date and time format.\");\n",
"\n",
" form.addDurationItem()\n",
" .setTitle(\"Duration 1\")\n",
" .setHelpText(\"To create a duration item, simply write this duration format.\");\n",
"\n",
" form.addGridItem()\n",
" .setTitle(\"RadioButton Grid\")\n",
" .setRows(['Row 1', 'Row 2', 'Row 3'])\n",
" .setColumns(['Column 1', 'Column 2', 'Column 3'])\n",
" .setHelpText(\"To create a radio button grid, simply write the rows and columns. Note that the rows **MUST BE** written as `#### rows` and the columns **MUST BE** written as `#### columns`, ignoring case.\");\n",
"\n",
" form.addCheckboxGridItem()\n",
" .setTitle(\"Checkbox Grid\")\n",
" .setRows(['Row 1', 'Row 2', 'Row 3'])\n",
" .setColumns(['Column 1', 'Column 2', 'Column 3'])\n",
" .setHelpText(\"To create a checkbox grid, simply write the rows and columns. Note that the rows **MUST BE** written as `#### [] rows` and the columns **MUST BE** written as `#### [] columns`, ignoring case.\");\n",
"\n",
" sections[\"Section 3\"]\n",
" .setTitle(\"Section 3\")\n",
" .setHelpText(\"Section 3 description\");\n",
"\n",
" form.moveItem(form.getItemById(sections[\"Section 3\"].getId()), form.getItems().length - 1);\n",
"\n",
" form.addTextItem()\n",
" .setTitle(\"Short text 2\");\n",
"\n",
" form.addTextItem()\n",
" .setTitle(\"Long text 2\")\n",
" .setHelpText(\"This indicates a long text field, and its contents will be ignored.\");\n",
"\n",
" form.addSectionHeaderItem()\n",
" .setTitle(\"Title and description 2\")\n",
" .setHelpText(\"Use this to add a title and a description to the form.\");\n",
"\n",
" form.addMultipleChoiceItem()\n",
" .setTitle(\"Radio buttons 2\")\n",
" .setChoiceValues(['Radio Option 1', 'Radio Option 2', 'Radio Option 3'])\n",
" .setHelpText(\"Use `*` at the start of each line to indicate that the list is a radio button list. If you want any item to be required, write the text between `**`.\")\n",
" .setRequired(true);\n",
"\n",
" form.addMultipleChoiceItem()\n",
" .setTitle(\"Combobox 2\")\n",
" .setChoiceValues(['Combo Option 1', 'Combo Option 2', 'Combo Option 3'])\n",
" .setHelpText(\"Use `-` at the start of each line to indicate that the list is a radio button list.\");\n",
"\n",
" form.addMultipleChoiceItem()\n",
" .setTitle(\"Checkboxes 2\")\n",
" .setChoiceValues(['Check Option 1', 'Check Option 2', 'Check Option 3'])\n",
" .setHelpText(\"Use `[]` at the start of each line to indicate that the list is a checkbox list. It doesn't matter if it starts with `-` or `*`, or even if the checkoxes have a space or not inside.\");\n",
"\n",
" form.addScaleItem()\n",
" .setTitle(\"Scale 2\")\n",
" .setBounds(1, 5)\n",
" .setLabels(\"Lowest\", \"Highest\")\n",
" .setHelpText(\"To create a scale, simply write the lowest label and its value, then a `---`, and finally the highest value and its label, in this order.\");\n",
"\n",
" form.addDateTimeItem()\n",
" .setTitle(\"Date 2\")\n",
" .setHelpText(\"To create a date item, simply write this date format.\");\n",
"\n",
" form.addDurationItem()\n",
" .setTitle(\"Time 2\")\n",
" .setHelpText(\"To create a time item, simply write this time format.\");\n",
"\n",
" form.addDateTimeItem()\n",
" .setTitle(\"Date and time 2\")\n",
" .setHelpText(\"To create a date and time item, simply write this date and time format.\");\n",
"\n",
" form.addDurationItem()\n",
" .setTitle(\"Duration 2\")\n",
" .setHelpText(\"To create a duration item, simply write this duration format.\");\n",
"\n",
" form.addGridItem()\n",
" .setTitle(\"RadioButton Grid\")\n",
" .setRows(['Row 1', 'Row 2', 'Row 3'])\n",
" .setColumns(['Column 1', 'Column 2', 'Column 3'])\n",
" .setHelpText(\"To create a radio button grid, simply write the rows and columns. Note that the rows **MUST BE** written as `#### rows` and the columns **MUST BE** written as `#### columns`, ignoring case.\");\n",
"\n",
" form.addCheckboxGridItem()\n",
" .setTitle(\"Checkbox Grid\")\n",
" .setRows(['Row 1', 'Row 2', 'Row 3'])\n",
" .setColumns(['Column 1', 'Column 2', 'Column 3'])\n",
" .setHelpText(\"To create a checkbox grid, simply write the rows and columns. Note that the rows **MUST BE** written as `#### [] rows` and the columns **MUST BE** written as `#### [] columns`, ignoring case.\");\n",
"}\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"Then, paste the generated code on a [new project](https://script.google.com/home/projects/create) in Google Apps Script and execute it. On the first run of this new project it will ask for permissions to your Google Drive, which should be conceded so it can create the new form. A new file will be created on your [Google Drive](https://drive.google.com/) with the name you used as title. Note that the form is not ready to use, but at least the basic structure will be done"
],
"metadata": {
"id": "7XcgHYIXAth1"
}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment