Skip to content

Commit

Permalink
feat(getJsonResource and scrubControlChars): add getJsonResource and …
Browse files Browse the repository at this point in the history
…scrubControlChars

AFFECTS PACKAGES:
@esri/arcgis-rest-portal
  • Loading branch information
drewdaemon committed Sep 18, 2020
1 parent 27f162f commit 6bb9215
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/arcgis-rest-portal/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export * from "./sharing/helpers";
export * from "./util/get-portal";
export * from "./util/get-portal-settings";
export * from "./util/get-portal-url";
export * from './util/scrub-control-chars';
export * from "./util/search";
export * from "./util/SearchQueryBuilder";
// we dont export 'generic-search' because its an internal utility method
Expand Down
26 changes: 26 additions & 0 deletions packages/arcgis-rest-portal/src/items/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { IItem, IGroup } from "@esri/arcgis-rest-types";

import { getPortalUrl } from "../util/get-portal-url";
import { scrubControlChars } from '../util/scrub-control-chars';
import {
IItemDataOptions,
IItemRelationshipOptions,
Expand Down Expand Up @@ -185,6 +186,31 @@ export interface IGetItemGroupsResponse {
other?: IGroup[];
}

/**
* Fetches a JSON resource and parses to an object
*
* @param {*} itemId
* @param {*} resourceName
* @param {*} requestOptions
*/
export function getJsonResource(
itemId: string,
resourceName: string,
requestOptions: IRequestOptions
) {
const url = `${getPortalUrl(
requestOptions
)}/content/items/${itemId}/resources/${resourceName}`;

// We need the raw response because there may be control characters
// that need to be scrubbed prior to parsing the JSON
const options = Object.assign({ params: { f: "json" }, rawResponse: true }, requestOptions);
return request(url, options)
.then(res => res.text())
.then(text => JSON.parse(scrubControlChars(text)));
}


/**
* ```js
* import { getItemGroups } from "@esri/arcgis-rest-portal";
Expand Down
12 changes: 12 additions & 0 deletions packages/arcgis-rest-portal/src/util/scrub-control-chars.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const CONTROL_CHAR_MATCHER = /[\x00-\x1F\x7F-\x9F\xA0]/g;

/**
* Returns a string with all control characters removed.
*
* Doesn't remove characters
*
* @param str - the string to scrub
*/
export function scrubControlChars (str: string) {
return str.replace(CONTROL_CHAR_MATCHER, "");
}
45 changes: 44 additions & 1 deletion packages/arcgis-rest-portal/test/items/get.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
getItemParts,
getRelatedItems,
getItemInfo,
getItemMetadata
getItemMetadata, getJsonResource
} from "../../src/items/get";

import {
Expand Down Expand Up @@ -373,6 +373,49 @@ describe("get", () => {
});
});

describe('getJsonResource', function () {
it("gets JSON resource", done => {
const resourceResponse = {
foo: 'bar'
};
fetchMock.once("*", resourceResponse);

getJsonResource("3ef", "resource.json", MOCK_USER_REQOPTS)
.then(() => {
const [url, options]: [string, RequestInit] = fetchMock.lastCall("*");
expect(url).toEqual(
"https://myorg.maps.arcgis.com/sharing/rest/content/items/3ef/resources/resource.json"
);
expect(options.method).toBe("POST");
expect(options.body).toContain("f=json");
done();
})
.catch(e => {
fail(e);
});
});

it("deals with control characters", done => {
const badJson = "{\"foo\":\"foobarbaz\"}";
fetchMock.once("*", badJson);
getJsonResource("3ef", 'resource.json', MOCK_USER_REQOPTS)
.then(resource => {
const [url, options]: [string, RequestInit] = fetchMock.lastCall("*");
expect(url).toEqual(
"https://myorg.maps.arcgis.com/sharing/rest/content/items/3ef/resources/resource.json"
);
expect(options.method).toBe("POST");
expect(options.body).toContain("f=json");
debugger;
expect(resource.foo).toEqual('foobarbaz', 'removed control chars');
done();
})
.catch(e => {
fail(e);
});
});
})

it("get item groups anonymously", done => {
fetchMock.once("*", ItemGroupResponse);
getItemGroups("3ef")
Expand Down
22 changes: 22 additions & 0 deletions packages/arcgis-rest-portal/test/util/scrub-control-chars.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { scrubControlChars } from "../../src/util/scrub-control-chars";

describe('scrubControlChars', function () {
it('removes control characters', function () {
let hasAllControlChars = 'foo';
// C0
for (let i = 0; i < 32; i++) {
hasAllControlChars += String.fromCharCode(i);
}
hasAllControlChars += 'bar';
// C1
for (let i = 128; i < 159; i++) {
hasAllControlChars += String.fromCharCode(i);
}
hasAllControlChars += 'baz';

// ISO 8859 special char
hasAllControlChars += String.fromCharCode(160);

expect(scrubControlChars(hasAllControlChars)).toBe('foobarbaz', "removes all control chars")
});
});

0 comments on commit 6bb9215

Please sign in to comment.