import { load } from 'cheerio' import { Column, CustomizableOption, Field, FieldsOrder, GoogleForm, Line, Option } from 'react-google-forms-hooks' // we currently use this separate file until the problems in react-google-forms-hooks are fixed type FormData = { formData: object fbzx: string } const toBool = (n: number): boolean => n === 1 const toString = (n: number): string => `${n}` const assertValidUrl = (formUrl: string): void => { const googleFormsHosts = ['docs.google.com', 'forms.gle'] const url = new URL(formUrl) if (!googleFormsHosts.includes(url.host)) { throw new Error( `Invalid google forms host. ${ url.host } is expected to be ${googleFormsHosts .join(', ') .replace(/, ([^,]*)$/, ' or $1')}.` ) } if (url.host === googleFormsHosts[0] && !url.pathname.endsWith('/viewform')) { throw new Error(`Please use the form's public URL.`) } } const getFormHtml = async (formUrl: string) => { const response = await fetch(formUrl) const html = await response.text() return html } const extractFormData = (html: string): FormData => { const $ = load(html) const fbzx = $('[name="fbzx"]').attr('value') if (!fbzx) { throw new Error(`Invalid form. Couldn't find fbzx field.`) } const scriptStringIdentifier = 'var FB_PUBLIC_LOAD_DATA_ =' let scriptHtml = $('script') .filter((_, el) => { return $(el).html()!.includes(scriptStringIdentifier) }) .first() .html() if (!scriptHtml) { throw new Error(`Invalid form. Couldn't find script tag.`) } scriptHtml = scriptHtml.slice(0, -1) scriptHtml = scriptHtml.replace(scriptStringIdentifier, '') const formDataRaw = JSON.parse(scriptHtml) return { formData: formDataRaw, fbzx } } const parseGridMultiSelect = (rawField: Array): 1 | 0 => { const firstLine = rawField[4][0] const canSelectMultiple = firstLine[11][0] return canSelectMultiple } const parseFieldType = (rawField: Array, fieldId: number) => { const fieldTypes = [ 'SHORT_ANSWER', 'LONG_ANSWER', 'RADIO', 'DROPDOWN', 'CHECKBOX', 'LINEAR' ] as const if (fieldId === 7) { if (parseGridMultiSelect(rawField) === 1) { return 'CHECKBOX_GRID' } else { return 'RADIO_GRID' } } if (fieldId === 9) { return 'DATE' } return fieldTypes[fieldId] } const parseOptions = (options: Array): Array