initial commit

This commit is contained in:
Vladimir Enchev
2015-07-10 10:32:43 +03:00
parent 782c39050f
commit 44e6014d3c
7 changed files with 1183 additions and 0 deletions

View File

@@ -288,6 +288,10 @@
</TypeScriptCompile>
<TypeScriptCompile Include="es-collections.d.ts" />
<TypeScriptCompile Include="es6-promise.d.ts" />
<TypeScriptCompile Include="fetch\body.ts" />
<TypeScriptCompile Include="fetch\fetch.ts" />
<TypeScriptCompile Include="fetch\headers.ts" />
<TypeScriptCompile Include="fetch\webidl.d.ts" />
<TypeScriptCompile Include="file-system\file-name-resolver.d.ts" />
<TypeScriptCompile Include="file-system\file-name-resolver.ts">
<DependentUpon>file-name-resolver.d.ts</DependentUpon>
@@ -1670,6 +1674,8 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="apps\action-bar-demo\package.json" />
<Content Include="fetch\package.json" />
<Content Include="fetch\README.md" />
<None Include="js-libs\esprima\LICENSE.BSD" />
<Content Include="source-control.md" />
<Content Include="ui\segmented-bar\package.json">

17
fetch/README.md Normal file
View File

@@ -0,0 +1,17 @@
# Isomorphic Fetch Implementation
## status
WIP
## motivation
implementation of [fetch API](https://fetch.spec.whatwg.org/) in pure javascript.
polyfill for browser, and implemnt for node.js.
make network http access isomorphic.
## License
The MIT License (MIT)
Copyright (c) 2013 Jxck

100
fetch/body.ts Normal file
View File

@@ -0,0 +1,100 @@
// https://fetch.spec.whatwg.org/#json
type object = JSON;
type body = Object; // byte stream
// https://fetch.spec.whatwg.org/#bodyinit
type BodyInit = Blob | BufferSource | FormData | URLSearchParams | USVString
// https://fetch.spec.whatwg.org/#body
interface IBody {
// readonly property
bodyUsed: boolean;
// method
arrayBuffer(): Promise<ArrayBuffer>;
blob(): Promise<Blob>;
formData(): Promise<FormData>;
json(): Promise<JSON>;
text(): Promise<USVString>;
};
// https://fetch.spec.whatwg.org/#body
class Body implements IBody {
private _bodyUsed: boolean;
private _body: body;
private _usedFlag: boolean;
private _mimeType: string;
get bodyUsed(): boolean {
return this._bodyUsed;
}
get body(): body {
return this._body;
}
get usedFlag(): boolean {
return this._usedFlag;
}
get mimeType(): string {
return this._mimeType;
}
consumeBody(_type: string): any {
// step 1
var p = new Promise((resolve, reject) => {
// step 2
if (this._bodyUsed == true) {
return reject(new TypeError("body was already used"));
}
// step 3
this._bodyUsed = true;
// step 3-1
var stream = this._body;
// step 3-2
if (stream == null) {
stream = [];
}
// step 3-3
// TODO: Let bytes be the result of reading from stream until it returns end-of-stream.
var bytes;
// step 4
// TODO: implement me
switch(_type) {
case "ArrayBuffer":
case "Blob":
case "FormData":
case "JSON":
case "text":
}
});
return p;
}
arrayBuffer(): Promise<ArrayBuffer> {
return this.consumeBody("ArrayBuffer");
}
blob(): Promise<Blob> {
return this.consumeBody("Blob");
}
formData(): Promise<FormData> {
return this.consumeBody("FormData");
}
json(): Promise<JSON> {
return this.consumeBody("JSON");
}
text(): Promise<USVString> {
return this.consumeBody("text");
}
}

677
fetch/fetch.ts Normal file
View File

@@ -0,0 +1,677 @@
/// <reference path="webidl.d.ts" />
/// <reference path="headers.ts" />
/// <reference path="body.ts" />
// http://heycam.github.io/webidl/#common-BufferSource
class BufferSource {
}
// https://url.spec.whatwg.org/#urlsearchparams
class URLSearchParams {
}
// https://fetch.spec.whatwg.org/#concept-method
enum MethodEnum {
OPTIONS,
GET,
HEAD,
POST,
PUT,
DELETE,
TRACE,
CONNECT,
}
// https://fetch.spec.whatwg.org/#simple-method
enum SimpleMethodEnum {
GET,
HEAD,
POST
}
function isSimpleMethod(method: ByteString): boolean {
if (SimpleMethodEnum[method] !== undefined) {
return true;
}
return false;
}
// https://fetch.spec.whatwg.org/#forbidden-method
enum ForbiddenMethodEnum {
CONNECT,
TRACE,
TRACK
}
function isForbiddenMethod(method: ByteString): boolean {
if (ForbiddenMethodEnum[method] !== undefined) {
return true;
}
return false
}
// https://fetch.spec.whatwg.org/#requestcontext
type RequestContext = string;
enum RequestContextEnum {
"audio", "beacon",
"cspreport", "download",
"embed", "eventsource",
"favicon", "fetch",
"font", "form",
"frame", "hyperlink",
"iframe", "image",
"imageset", "import",
"internal", "location",
"manifest", "object",
"ping", "plugin",
"prefetch", "script",
"serviceworker", "sharedworker",
"subresource", "style",
"track", "video",
"worker", "xmlhttprequest",
"xslt"
};
// https://fetch.spec.whatwg.org/#concept-request-context-frame-type
enum ContextFrameTypeEnum {
"auxiliary",
"top-level",
"nested",
"none"
}
// https://fetch.spec.whatwg.org/#concept-request-mode
type RequestMode = string;
enum RequestModeEnum {
"same-origin",
"no-cors",
"cors"
};
// https://fetch.spec.whatwg.org/#concept-request-credentials-mode
type RequestCredentials = string;
enum RequestCredentialsEnum {
"omit",
"same-origin",
"include"
};
// https://fetch.spec.whatwg.org/#concept-request-cache-mode
type RequestCache = string;
enum RequestCacheEnum {
"default",
"bypass",
"reload",
"revalidate",
"force-cache",
"offline"
};
// https://fetch.spec.whatwg.org/#concept-response-type
type ResponseType = string;
enum ResponseTypeEnum {
"basic",
"cors",
"default",
"error",
"opaque"
};
/////////////////////////////
/// Request
/////////////////////////////
// https://fetch.spec.whatwg.org/#requestinfo
type RequestInfo = Request | USVString;
// https://fetch.spec.whatwg.org/#request
interface IRequest extends IBody {
// readonly property
method: ByteString;
url: USVString;
headers: Headers;
context: RequestContext;
referrer: DOMString;
mode: RequestMode;
credentials: RequestCredentials;
cache: RequestCache;
// method
clone(): IRequest;
};
// https://fetch.spec.whatwg.org/#requestinit
// dictionary RequestInit
interface RequestInit {
method: ByteString;
headers: HeadersInit;
body: BodyInit;
mode: RequestMode;
credentials: RequestCredentials;
cache: RequestCache;
};
type Client = Object;
type Referrer = Object;
type Context = Object;
type request = {
method: string;
url: string;
headerList: Header[];
unsafeRequestFlag: boolean;
body: body;
//TODO: client: Client;
context: Context;
//TODO: origin: string;
forceOriginHeaderFlag: boolean;
sameOriginDataURLFlag: boolean;
//TODO: referrer: Referrer;
mode: string;
credentialsMode: string;
cacheMode: string;
}
class Request implements IRequest {
// readonly property on IRequest
private _method: ByteString;
private _url: USVString;
private _headers: Headers;
private _context: RequestContext;
private _referrer: DOMString;
private _mode: ByteString;
private _credentials: RequestCredentials;
private _cache: RequestCache;
// readonly property on IBody
private _bodyUsed: boolean;
// https://fetch.spec.whatwg.org/#dom-request-method
get method(): ByteString {
return this._method;
}
// https://fetch.spec.whatwg.org/#dom-request-url
get url(): USVString {
return this._url;
}
// https://fetch.spec.whatwg.org/#dom-request-headers
get headers(): Headers {
return this._headers;
}
// https://fetch.spec.whatwg.org/#dom-request-context
get context(): RequestContext {
return this._context;
}
// https://fetch.spec.whatwg.org/#dom-request-referrer
get referrer(): DOMString {
return null;
}
// https://fetch.spec.whatwg.org/#dom-request-mode
get mode(): RequestMode {
return null;
}
// https://fetch.spec.whatwg.org/#dom-request-credentials
get credentials(): RequestCredentials {
return this._credentials;
}
// https://fetch.spec.whatwg.org/#dom-request-cache
get cache(): RequestCache {
return null;
}
// https://fetch.spec.whatwg.org/#dom-body-bodyused
get bodyUsed(): boolean {
return this._bodyUsed;
}
// https://fetch.spec.whatwg.org/#dom-request-clone
// method on IRequest
public clone(): IRequest {
return null;
}
// https://fetch.spec.whatwg.org/#dom-body-arraybuffer
// method on IBody
public arrayBuffer(): Promise<ArrayBuffer> {
return null;
}
// https://fetch.spec.whatwg.org/#dom-body-blob
public blob(): Promise<Blob> {
return null;
}
// https://fetch.spec.whatwg.org/#dom-body-formdata
public formData(): Promise<FormData> {
return null;
}
// https://fetch.spec.whatwg.org/#dom-body-json
public json(): Promise<JSON> {
return null;
}
// https://fetch.spec.whatwg.org/#dom-body-text
public text(): Promise<USVString> {
return null;
}
// Request
public request: request;
public body: body;
public usedFlag: boolean;
public mimeType: string;
// https://fetch.spec.whatwg.org/#dom-request
constructor(input: RequestInfo, init?: RequestInit) {
// can't detect class by instanceof
// if (input instanceof Request) { }
var request: request;
// step 1
if (typeof input === "object" && input.body !== null) { // Request
// step 1-1
if (input.usedFlag) {
throw new TypeError("Request already used");
}
// step 1-2
input.usedFlag = true;
// step 2
request = input.request;
} else {
// step 2
// new request otherwise
request = {
url: null,
method: MethodEnum[MethodEnum.GET],
headerList: [],
unsafeRequestFlag: false,
body: null,
//TODO: client: entry settings object,
//TODO: origin: entry settings object.origin,
forceOriginHeaderFlag: false,
sameOriginDataURLFlag: false,
referrer: null,
context: null,
mode: RequestModeEnum[RequestModeEnum["no-cors"]],
credentialsMode: RequestCredentialsEnum[RequestCredentialsEnum.omit],
cacheMode: RequestCacheEnum[RequestCacheEnum.default],
}
}
// step 3
request = {
url: request.url,
method: request.method,
headerList: request.headerList,
unsafeRequestFlag: true,
body: request.body,
//TODO: client: entry settings object,
//TODO: origin: entry settings object.origin,
forceOriginHeaderFlag: true,
sameOriginDataURLFlag: true,
//TODO: referrer : request.client,
context: 'fetch',
mode: request.mode,
credentialsMode: request.credentialsMode,
cacheMode: request.cacheMode
}
// step 4, 5, 6
var fallbackMode: RequestMode = null;
var fallbackCredentials: RequestCredentials = null;
var fallbackCache: RequestCache = null;
//TODO:
function parseURL(url: string): string {
return url;
}
// step 7
if (typeof input === "string") {
// step 7-1
var parsedURL;
try {
parsedURL = parseURL(input);
} catch(err) {
// step 7-2
throw new TypeError(err);
}
// step 7-3
request.url = parsedURL;
// step 7-4, 7-5, 7-6
fallbackMode = RequestModeEnum[RequestModeEnum.cors];
fallbackCredentials = RequestCredentialsEnum[RequestCredentialsEnum.omit];
fallbackCache = RequestCacheEnum[RequestCacheEnum.default];
}
// step 8
var mode = init.mode? init.mode: fallbackMode;
// step 9
if (mode !== null) request.mode = mode;
// step 10
var credentials = init.credentials? init.credentials: fallbackCredentials;
// step 11
if (credentials !== null) request.credentialsMode = credentials;
// step 12
var cache = init.cache? init.cache: fallbackCache;
// step 13
if (cache !== null) request.cacheMode = cache;
// step 14
if (init.method) {
var method = init.method;
// step 14-1
if(isForbiddenMethod(method)) {
throw new TypeError("forbidden method " + method);
}
// step 14-2
method = method.toUpperCase();
// step 14-3
request.method = method;
}
// step 15
var r = this;
r.request = request;
r._headers = new Headers();
// step 16
var headers = r.headers;
// step 17
if (init.headers) {
headers = <Headers>init.headers;
}
// step 18
r.request.headerList = [];
// step 19
if (r.request.mode === "no-cors") {
// 19-1
if (!isSimpleMethod(this.request.method)) {
throw new TypeError("not simple method" + method);
}
// 19-2
r.headers.guard = "request-no-CORS";
}
// step 20
r._headers = headers;
// step 21
if (init.body) {
// step 21-1
var result = extract(init.body);
// step 21-2
r.request.body = result.stream;
// step 21-3
if (result.contentType !== null) {
var hasContentType = request.headerList.some((header) => {
return header.name === "Content-Type";
});
if (!hasContentType) {
r._headers.append("Content-Type", result.contentType);
}
}
}
// step 22
// FIXME implement mime type extract
r.mimeType = null;
}
}
// https://fetch.spec.whatwg.org/#concept-bodyinit-extract
function extract(object: any): any {
// step 1
var stream = [];
// step 2
var contentType = null;
// step 3
switch(object.constructor) {
// Blob
case Blob:
stream = object.contents;
if (object.type) {
contentType = object.type;
}
case BufferSource:
// TODO: stream = copy(object);
case FormData:
// TODO:
case URLSearchParams:
stream = object.list.toString();
contentType = "application/x-www-form-urlencoded;charset=UTF-8";
case String: // USVString
// stream = encode(object);
contentType = "text/plain;charset=UTF-8";
}
// step 4
return { stream: stream, contentType: contentType };
}
// https://fetch.spec.whatwg.org/#response
interface IResponse extends IBody { // Response implements Body;
// static Response error();
// static Response redirect(USVString url, optional unsigned short status = 302);
type: ResponseType; // readonly
url: USVString; // readonly
status: number; // readonly
statusText: ByteString; // readonly
headers: Headers; // readonly
// Response clone();
};
// https://fetch.spec.whatwg.org/#responseinit
class ResponseInit {
status: number = 200;
statusText: ByteString = "OK";
headers: HeadersInit;
};
class response {
type: string;
terminationReason: string;
url: string;
status: number;
statusMessage: string;
headerList: Header[];
body: Body;
cacheState: string;
TLSState: string;
constructor() {
this.type = "default";
this.terminationReason = "timeout";
this.url = null;
this.status = 200;
this.statusMessage = "OK";
this.headerList = [];
this.body = null;
this.cacheState = "none";
this.TLSState = "unauthenticated";
}
}
// https://fetch.spec.whatwg.org/#response
class Response implements IResponse {
// implements body
_bodyUsed: boolean;
_type: ResponseType; // readonly
_url: USVString; // readonly
_status: number; // readonly
_statusText: ByteString; // readonly
_headers: Headers; // readonly
_response: response;
// https://fetch.spec.whatwg.org/#dom-response
// [Constructor(optional BodyInit body, optional ResponseInit init), Exposed=(Window,Worker)]
constructor(body?: BodyInit, init?: ResponseInit) {
if (init !== undefined) {
// step 1
if (init.status < 200 && init.status > 599) {
throw new RangeError("status is not in the range 200 to 599");
}
// step 2
if (init.statusText.indexOf("\r") < 0 || init.statusText.indexOf("\n") < 0) {
throw new TypeError("Invalid Reason-Phrase token production");
}
}
// step 3
var r = this;
r._response = new response();
r._headers = new Headers();
if (init !== undefined) {
// step 4
r._response.status = init.status;
// step 5
r._response.statusMessage = init.statusText;
}
// step 6
if (init.headers) {
// step 6-1
r._response.headerList = [];
// step 6-2
// TODO: implements fill
// r._response.headerList =;
}
// step 7
if (body) {
// step 7-1
var extracted = extract(body);
var stream = extracted.stream;
var contentType = extracted.contentType;
// step 7-2
r._response.body = stream;
// step 7-3
if (contentType !== null) {
var hasContentType = r._response.headerList.some((header) => {
return header.name === "Content-Type";
});
if (!hasContentType) {
// TODO: append
// r._response.headerList.append(Header("Content-Type", contentType));
}
}
// step 8
// TODO: extracting MIME type
// step 9
// TODO: TLS state
// step 10
return r;
}
}
get bodyUsed(): boolean {
return this._bodyUsed;
}
get type(): ResponseType {
return this._type;
}
get url(): USVString {
return this._url;
}
get status(): number {
return this._status;
}
get statusText(): ByteString {
return this._statusText;
}
get headers(): Headers {
return this._headers;
}
arrayBuffer(): Promise<ArrayBuffer> {
return null;
}
blob(): Promise<Blob> {
return null;
}
formData(): Promise<FormData> {
return null;
}
json(): Promise<JSON> {
return null;
}
text(): Promise<USVString> {
return null;
}
}
// https://fetch.spec.whatwg.org/#globalfetch
// Window implements GlobalFetch;
interface Window {
fetch(input: RequestInfo, init?: RequestInit): Promise<IResponse>;
};
// WorkerGlobalScope implements GlobalFetch;
this.fetch = function(input: RequestInfo, init?: RequestInit): Promise<IResponse> {
// step 1
var p = new Promise<IResponse>((resolve, reject) => {
try {
// step 2
var r = (new Request(input, init)).request;
} catch(e) {
reject(e);
}
});
// step 4
return p
}
// WorkerGlobalScope implements GlobalFetch;

341
fetch/headers.ts Normal file
View File

@@ -0,0 +1,341 @@
/// <reference path="webidl.d.ts" />
// https://fetch.spec.whatwg.org/#forbidden-header-name
var ForbiddenHeaderName = {
"Accept-Charset": "Accept-Charset",
"Accept-Encoding": "Accept-Encoding",
"Access-Control-Request-Headers": "Access-Control-Request-Headers",
"Access-Control-Request-Method": "Access-Control-Request-Method",
"Connection": "Connection",
"Content-Length": "Content-Length",
"Cookie": "Cookie",
"Cookie2": "Cookie2",
"Date": "Date",
"DNT": "DNT",
"Expect": "Expect",
"Host": "Host",
"Keep-Alive": "Keep-Alive",
"Origin": "Origin",
"Referer": "Referer",
"TE": "TE",
"Trailer": "Trailer",
"Transfer-Encoding": "Transfer-Encoding",
"Upgrade": "Upgrade",
"User-Agent": "User-Agent",
"Via": "Via"
};
function isForbiddenHeaderName(name: ByteString): boolean {
if (ForbiddenHeaderName[name] !== undefined) {
return true;
}
var reg = /^(Proxy\-|Sec\-)/
if (reg.exec(name)) {
return true;
}
return false;
}
// https://fetch.spec.whatwg.org/#forbidden-response-header-name
var ForbiddenResponseHeaderName = {
"Set-Cookie": "Set-Cookie",
"Set-Cookie2": "Set-Cookie2"
}
function isForbiddenResponseHeaderName(name: ByteString): boolean {
return ForbiddenResponseHeaderName[name] !== undefined;
}
// https://fetch.spec.whatwg.org/#simple-header
var SimpleHeaderName = {
"Accept": "Accept",
"Accept-Language": "Accept-Language",
"Content-Language": "Content-Language"
}
var SimpleHeaderValue = {
"application/x-www-form-urlencoded": "application/x-www-form-urlencoded",
"multipart/form-data": "multipart/form-data",
"text/plain": "text/plain"
}
function isSimpleHeader(name, value: ByteString): boolean {
if (SimpleHeaderName[name] !== undefined) {
return true;
}
if (name === "Content-Type") {
// TODO: parse value https://fetch.spec.whatwg.org/#concept-header-parse
if (SimpleHeaderValue[value] !== undefined) {
return true;
}
}
return false;
}
// https://fetch.spec.whatwg.org/#headersinit
// typedef (Headers or sequence<sequence<ByteString>> or OpenEndedDictionary<ByteString>) HeadersInit;
type HeadersInit = Headers | ByteString[][] | OpenEndedDictionary;
// https://fetch.spec.whatwg.org/#headers
interface IHeaders {
append(name, value: ByteString): void;
delete(name: ByteString): void;
get(name: ByteString): ByteString;
getAll(name: ByteString): ByteString[];
has(name: ByteString): boolean;
set(name, value: ByteString): void;
// iterable<ByteString, ByteString>;
};
// https://fetch.spec.whatwg.org/#concept-header
class Header {
name: ByteString;
value: ByteString;
constructor(name, value: ByteString) {
// TODO: validation
this.name = name;
this.value = value;
}
}
var Guard = {
"immutable": "immutable",
"request": "request",
"request-no-CORS": "request-no-CORS",
"response": "response",
"none": "none",
}
function copy<T>(obj: T): T {
return JSON.parse(JSON.stringify(obj));
}
// https://fetch.spec.whatwg.org/#headers
class Headers implements IHeaders{
public headerList: Header[] = [];
public guard: string = Guard.none;
// https://fetch.spec.whatwg.org/#dom-headers
constructor(init?: HeadersInit) {
// step 1
var headers = this; // new Headers object
// step 2
if (init !== undefined) {
this.fill(headers, init);
}
// step 3
return headers;
}
// https://fetch.spec.whatwg.org/#concept-headers-fill
private fill(headers: Headers, object: HeadersInit) {
// step 1 Headers
if (object instanceof Headers) {
var headerListCopy: Header[] = copy(object.headerList);
headerListCopy.forEach((header: Header) => {
headers.append(header.name, header.value);
});
return;
}
// step 2 ByteString[][]
if (Array.isArray(object)) {
var headerSequence = <ByteString[][]> object;
headerSequence.forEach((header) => {
if(header.length !== 2) {
throw new TypeError("init for Headers was incorrect BytesString Sequence");
}
headers.append(header[0], header[1]);
});
return;
}
// step 3 OpenEndedDictionary
if (typeof object === "object") {
Object.keys(object).forEach((key) => {
headers.append(key.toString(), object[key]);
});
}
}
// https://fetch.spec.whatwg.org/#dom-headers-append
append(name, value: ByteString): void {
// https://fetch.spec.whatwg.org/#concept-headers-append
// step 1
if (!name || !value) {
// TODO name/value validation
throw new TypeError("invalid name/value");
}
// step 2, 3, 4, 5
switch(this.guard) {
case Guard.immutable:
throw new TypeError("operation to immutable headers");
case Guard.request:
if (isForbiddenHeaderName(name)) {
return;
}
case Guard["request-no-CORS"]:
if (!isSimpleHeader(name, value)) {
return;
}
case Guard.response:
if (isForbiddenResponseHeaderName(name)) {
return;
}
}
// step 6
name = name.toLowerCase();
this.headerList.push(new Header(name, value));
}
// https://fetch.spec.whatwg.org/#dom-headers-delete
delete(name: ByteString): void {
// step 1
if (!name) {
throw new TypeError("invalid name");
}
// step 2, 3, 4, 5
switch(this.guard) {
case Guard.immutable:
throw new TypeError("operation to immutable headers");
case Guard.request:
if (isForbiddenHeaderName(name)) {
return;
}
case Guard["request-no-CORS"]:
if (!isSimpleHeader(name, "invalid")) {
return;
}
case Guard.response:
if (isForbiddenResponseHeaderName(name)) {
return;
}
}
name = name.toLowerCase();
// step 6
this.headerList = this.headerList.filter((header: Header) => {
return header.name !== name;
});
}
// https://fetch.spec.whatwg.org/#dom-headers-get
get(name: ByteString) :ByteString {
// step 1
if (!name) {
throw new TypeError("invalid name");
}
// step 2
var value: ByteString = null;
this.headerList.forEach((header: Header) => {
if (header.name === name) {
value = header.value;
return;
}
});
return value;
}
// https://fetch.spec.whatwg.org/#dom-headers-getall
getAll(name: ByteString) :ByteString[] {
// step 1
if (!name) {
throw new TypeError("invalid name");
}
// step 2
var result: ByteString[] = this.headerList.reduce((acc: ByteString[], header: Header) => {
if (header.name === name) {
acc.push(header.value);
}
return acc;
}, []);
return result;
}
// https://fetch.spec.whatwg.org/#dom-headers-has
has(name: ByteString) :boolean {
// step 1
if (!name) {
throw new TypeError("invalid name");
}
// step 2
return this.headerList.some((header: Header) => {
return header.name === name;
});
}
// https://fetch.spec.whatwg.org/#dom-headers-set
set(name, value: ByteString): void {
// step 1
if (!name || !value) {
throw new TypeError("invalid name/value");
}
switch(this.guard) {
// step 2
case Guard.immutable:
throw new TypeError("operation to immutable headers");
// step 3
case Guard.request:
if (isForbiddenHeaderName(name)) {
return;
}
// step 4
case Guard["request-no-CORS"]:
if (!isSimpleHeader(name, "invalid")) {
return;
}
// step 5
case Guard.response:
if (isForbiddenResponseHeaderName(name)) {
return;
}
}
// step 6
// see https://fetch.spec.whatwg.org/#concept-header-list-set
// step 6-1
name = name.toLowerCase();
// find the all indexes of headers whos key is supplyed key
var indexes: number[] = this.headerList.reduce((acc: number[], header: Header, index: number) => {
if (header.name === name) {
acc.push(index);
}
return acc;
}, []);
// count of existing headers
var len = indexes.length;
// step 6-3
// if there are no key
if (len === 0) {
// append to last and return
return this.append(name, value);
}
// step 6-2
// remove the headers in indexes from the last(because splice chenges index)
// and change first header value
indexes.reverse().forEach((e, i: number) => {
if(i === len - 1) {
// only replace first entry
this.headerList[e].value = value;
} else {
// remove duplicate from last
this.headerList.splice(e, 1);
}
});
}
}

28
fetch/package.json Normal file
View File

@@ -0,0 +1,28 @@
{
"name": "fetch-standard",
"author": "Jxck",
"license": "MIT",
"version": "0.0.0",
"description": "implementaion of https://fetch.spec.whatwg.org/",
"homepage": "https://github.com/Jxck/fetch",
"bugs": {
"url": "https://github.com/Jxck/fetch/issues"
},
"keywords": [
"fetch",
"whatwg"
],
"repository": {
"type": "git",
"url": "https://github.com/Jxck/fetch"
},
"main": "fetch.ts",
"scripts": {
"clean": "rm *.js",
"build": "tsc fetch.ts --target ES5",
"test": "npm run build && node fetch.js"
},
"devDependencies": {
"typescript": "^1.4.1"
}
}

14
fetch/webidl.d.ts vendored Normal file
View File

@@ -0,0 +1,14 @@
// http://heycam.github.io/webidl/#idl-ByteString
declare type ByteString = string;
// http://heycam.github.io/webidl/#idl-USVString
declare type USVString = string;
// http://heycam.github.io/webidl/#idl-DOMString
declare type DOMString = string;
// see: https://fetch.spec.whatwg.org/#headersinit
declare type OpenEndedDictionary = Object;
declare class FormData { }
declare class Blob { }