move query-string-encoding

Change-Id: Iac755b5473e0b4d307a403db11b7c763d013be77
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/355211
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Spencer Olson <solson@instructure.com>
QA-Review: Aaron Shafovaloff <ashafovaloff@instructure.com>
Product-Review: Aaron Shafovaloff <ashafovaloff@instructure.com>
This commit is contained in:
Aaron Shafovaloff 2024-08-15 11:38:25 -06:00
parent 842b155fa9
commit a09e3372c7
22 changed files with 75 additions and 52 deletions

View File

@ -17,7 +17,7 @@
*/
import {toQueryString, encodeQueryString, decodeQueryString} from '../index'
import type {QueryParameterRecord} from '../index'
import type {QueryParameterRecord} from '../index.d'
import $ from 'jquery'
type EncodeQueryStringParams = Array<Record<string, string | null>>

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2017 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
type QueryParameterElement =
| string
| number
| boolean
| null
| undefined
| (() => string)
| Array<QueryParameterElement>
| QueryParameterRecord
export type QueryParameterRecord = {[k: string]: QueryParameterElement}
export declare function toQueryString(params: QueryParameterRecord): string
export declare function encodeQueryString(
unknownParams:
| Record<string, string | null | undefined>[]
| Record<string, string | null | undefined>
): string
export declare function decodeQueryString(string: string): Record<string, string | undefined>

View File

@ -26,32 +26,20 @@
// ... so we have to do a lot of massaging with the params object before using it
// So fun!
type QueryParameterElement =
| string
| number
| boolean
| null
| undefined
| (() => string) // n.b. for jQuery compatibility, this does not expect a generic return
| Array<QueryParameterElement>
| QueryParameterRecord
export type QueryParameterRecord = {[k: string]: QueryParameterElement}
export function toQueryString(params: QueryParameterRecord): string {
const paramsWithIndexes: Array<[k: string, v: string]> = []
export function toQueryString(params) {
const paramsWithIndexes = []
// encode each key/value pair using encodeURIComponent, to ensure that each
// key and value are properly encoded URI componeent strings. Otherwise,
// URLSearchParams will convert blanks into '+' which is not what we want.
const asStringValue = (parms: URLSearchParams): string => {
const asStringValue = parms => {
return Array.from(parms)
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&')
}
// fix up the array/object indexes to match the PHP standard
const fixIndexes = (elt: [string, string]): [string, string] => [
const fixIndexes = elt => [
elt[0]
.replace(/\[\d+\]$/, '[]')
.replace(/{/g, '[')
@ -59,7 +47,7 @@ export function toQueryString(params: QueryParameterRecord): string {
elt[1],
]
function serialize(k: string, elt: QueryParameterElement, suffix: string): void {
function serialize(k, elt, suffix) {
if (elt instanceof Function) {
paramsWithIndexes.push([k + suffix, elt()])
} else if (elt instanceof Array) {
@ -85,22 +73,18 @@ export function toQueryString(params: QueryParameterRecord): string {
// This is just to implement backward-compatibility from the old package. Almost
// nothing uses it anyway and we recommend toQueryString() for new needs.
// Need to be careful about duplicated keys, which have to be mapped into arrays.
export function encodeQueryString(
unknownParams:
| Record<string, string | null | undefined>[]
| Record<string, string | null | undefined>
): string {
let params: Record<string, string | null | undefined>[]
export function encodeQueryString(unknownParams) {
let params
if (Array.isArray(unknownParams)) {
params = unknownParams
} else if (typeof unknownParams === 'object') {
params = [unknownParams as Record<string, string | null | undefined>]
params = [unknownParams]
} else {
throw new TypeError('encodeQueryString() expects an array or object')
}
const realParms: QueryParameterRecord = {}
const realParms = {}
params.forEach(p => {
const k = Object.keys(p)[0]
const m = k.match(/(.+)\[\]/)
@ -130,7 +114,7 @@ export function encodeQueryString(
// in terms of how things like foo[]=1&foo[]=2 would be decoded. But it doesn't
// seem like any current usage cares about that kind of thing.
export function decodeQueryString(string: string) {
export function decodeQueryString(string) {
return string
.split('&')
.map(pair => pair.split('='))

View File

@ -0,0 +1,7 @@
{
"name": "@instructure/query-string-encoding",
"private": true,
"version": "1.0.0",
"author": "neme",
"main": "./index.js"
}

View File

@ -31,7 +31,7 @@ import doFetchApi from '@canvas/do-fetch-api-effect'
import CanvasDateInput from '@canvas/datetime/react/components/DateInput'
import FriendlyDatetime from '@canvas/datetime/react/components/FriendlyDatetime'
import * as tz from '@instructure/moment-utils'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
const I18n = useI18nScope('bounced_emails')

View File

@ -17,7 +17,7 @@
*/
import axios from '@canvas/axios'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
import makePromisePool from '@canvas/make-promise-pool'
const MAX_CONCURRENT_REQS = 5

View File

@ -39,7 +39,7 @@ import {
isMidnight,
} from '@instructure/moment-utils'
import * as tz from '@instructure/moment-utils'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
import {renderDatetimeField} from '@canvas/datetime/jquery/DatetimeField'
const I18n = useI18nScope('CreateAssignmentView')

View File

@ -37,7 +37,7 @@ import fcUtil from '@canvas/calendar/jquery/fcUtil'
import '@canvas/jquery/jquery.instructure_forms'
import '@canvas/jquery/jquery.instructure_misc_helpers'
import '../../fcMomentHandlebarsHelpers'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
import {renderDatetimeField} from '@canvas/datetime/jquery/DatetimeField'
const I18n = useI18nScope('calendar')

View File

@ -33,7 +33,7 @@ import reservationOverLimitDialog from '../jst/reservationOverLimitDialog.handle
import MessageParticipantsDialog from '@canvas/calendar/jquery/MessageParticipantsDialog'
import preventDefault from '@canvas/util/preventDefault'
import axios from '@canvas/axios'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
import {publish} from 'jquery-tinypubsub'
import '@canvas/jquery/jquery.ajaxJSON'
import '@canvas/jquery/jquery.instructure_misc_helpers'

View File

@ -24,7 +24,7 @@ import {useScope as useI18nScope} from '@canvas/i18n'
import $ from 'jquery'
import {map, defaults, filter, omit, each, has, last, includes} from 'lodash'
import * as tz from '@instructure/moment-utils'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
import moment from 'moment'
import {showFlashAlert} from '@canvas/alerts/react/FlashAlert'
import decodeFromHex from '@canvas/util/decodeFromHex'

View File

@ -47,7 +47,7 @@ import {
} from '@canvas/calendar/react/RecurringEvents/FrequencyPicker/utils'
import {renderUpdateCalendarEventDialog} from '@canvas/calendar/react/RecurringEvents/UpdateCalendarEventDialog'
import FrequencyPicker from '@canvas/calendar/react/RecurringEvents/FrequencyPicker/FrequencyPicker'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
const I18n = useI18nScope('calendar.edit_calendar_event')

View File

@ -30,7 +30,7 @@ import userSettingOptionsTemplate from '../../jst/userSettingOptions.handlebars'
import authenticity_token from '@canvas/authenticity-token'
import numberHelper from '@canvas/i18n/numberHelper'
import '@canvas/jquery/jquery.instructure_forms'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
import {renderDatetimeField} from '@canvas/datetime/jquery/DatetimeField'
const I18n = useI18nScope('conferences')

View File

@ -28,7 +28,7 @@ import '@canvas/jquery/jquery.ajaxJSON'
import '@canvas/jquery/jquery.disableWhileLoading'
import 'jqueryui/menu'
import 'jqueryui/autocomplete'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
const I18n = useI18nScope('content_migrations')

View File

@ -17,7 +17,7 @@
*/
import Backbone from '@canvas/backbone'
import {decodeQueryString} from '@canvas/query-string-encoding'
import {decodeQueryString} from '@instructure/query-string-encoding'
import {FormField} from '@instructure/ui-form-field'
import {useScope as useI18nScope} from '@canvas/i18n'
import PropTypes from 'prop-types'

View File

@ -38,7 +38,7 @@ import {
USER_INBOX_LABELS_QUERY,
VIEWABLE_SUBMISSIONS_QUERY,
} from '../../graphql/Queries'
import {decodeQueryString} from '@canvas/query-string-encoding'
import {decodeQueryString} from '@instructure/query-string-encoding'
import {responsiveQuerySizes} from '../../util/utils'
import {Flex} from '@instructure/ui-flex'

View File

@ -20,8 +20,8 @@
import getCookie from '@instructure/get-cookie'
import parseLinkHeader, {type Links} from '@canvas/parse-link-header'
import {defaultFetchOptions} from '@canvas/util/xhr'
import {toQueryString} from '@canvas/query-string-encoding'
import type {QueryParameterRecord} from '@canvas/query-string-encoding'
import {toQueryString} from '@instructure/query-string-encoding'
import type {QueryParameterRecord} from '@instructure/query-string-encoding/index.d'
import z from 'zod'
type RequestCredentials = 'include' | 'omit' | 'same-origin'

View File

@ -19,7 +19,7 @@
import PaginatedCollection from '@canvas/pagination/backbone/collections/PaginatedCollection'
import Group from '../models/Group'
import natcompare from '@canvas/util/natcompare'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
export default class ContextGroupCollection extends PaginatedCollection {
comparator = (x, y) =>

View File

@ -24,7 +24,7 @@ import $ from 'jquery'
import PaginatedCollection from '@canvas/pagination/backbone/collections/PaginatedCollection'
import GroupUser from '../models/GroupUser'
import h from '@instructure/html-escape'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
const I18n = useI18nScope('GroupUserCollection')

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU Affero General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
import $ from 'jquery'
import 'jquery.cookie'
import {clone, throttle} from 'lodash'

View File

@ -1,7 +0,0 @@
{
"name": "@canvas/query-string-encoding",
"private": true,
"version": "1.0.0",
"author": "neme",
"main": "./index.ts"
}

View File

@ -16,7 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
/**
* @class Common.Core.Environment

View File

@ -21,7 +21,7 @@ import {clone} from 'lodash'
import createStore, {type CanvasStore} from '@canvas/backbone/createStore'
import parseLinkHeader from 'link-header-parsing/parseLinkHeaderFromXHR'
import '@canvas/rails-flash-notifications'
import {encodeQueryString} from '@canvas/query-string-encoding'
import {encodeQueryString} from '@instructure/query-string-encoding'
const initialStoreState = {
links: {},