first commit

This commit is contained in:
2026-09-08 20:28:54 +08:00
commit 2ada8d3d5a
37380 changed files with 4886169 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Jam3
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.
+61
View File
@@ -0,0 +1,61 @@
# load-bmfont
[![stable](http://badges.github.io/stability-badges/dist/stable.svg)](http://github.com/badges/stability-badges)
Loads an [AngelCode BMFont](http://www.angelcode.com/products/bmfont/) file in browser (with XHR) and node (with fs and [phin](https://github.com/ethanent/phin)), returning a [JSON representation](json-spec.md).
```js
var load = require("load-bmfont");
load("fonts/Arial-32.fnt", function (err, font) {
if (err) throw err;
//The BMFont spec in JSON form
console.log(font.common.lineHeight);
console.log(font.info);
console.log(font.chars);
console.log(font.kernings);
});
```
Currently supported BMFont formats:
- ASCII (text)
- JSON
- XML
- binary
## See Also
See [text-modules](https://github.com/mattdesl/text-modules) for related modules.
## Usage
[![NPM](https://nodei.co/npm/load-bmfont.png)](https://www.npmjs.com/package/load-bmfont)
#### `load(opt, cb)`
Loads a BMFont file with the `opt` settings and fires the callback with `(err, font)` params once finished. If `opt` is a string, it is used as the URI. Otherwise the options can be:
- `uri` or `url` the path (in Node) or URI
- `binary` boolean, whether the data should be read as binary, default false
- (in node) options for `fs.readFile` or [phin](https://www.npmjs.com/package/phin)
- (in browser) options for [xhr](https://github.com/Raynos/xhr)
To support binary files in the browser and Node, you should use `binary: true`. Otherwise the XHR request might come in the form of a UTF8 string, which will not work with binary files. This also sets up the XHR object to override mime type in older browsers.
```js
load(
{
uri: "fonts/Arial.bin",
binary: true,
},
function (err, font) {
console.log(font);
}
);
```
## License
MIT, see [LICENSE.md](http://github.com/Jam3/load-bmfont/blob/master/LICENSE.md) for details.
+97
View File
@@ -0,0 +1,97 @@
var xhr = require('xhr')
var noop = function(){}
var parseASCII = require('parse-bmfont-ascii')
var parseXML = require('parse-bmfont-xml')
var readBinary = require('parse-bmfont-binary')
var isBinaryFormat = require('./lib/is-binary')
var xtend = require('xtend')
var xml2 = (function hasXML2() {
return self.XMLHttpRequest && "withCredentials" in new XMLHttpRequest
})()
module.exports = function(opt, cb) {
cb = typeof cb === 'function' ? cb : noop
if (typeof opt === 'string')
opt = { uri: opt }
else if (!opt)
opt = {}
var expectBinary = opt.binary
if (expectBinary)
opt = getBinaryOpts(opt)
xhr(opt, function(err, res, body) {
if (err)
return cb(err)
if (!/^2/.test(res.statusCode))
return cb(new Error('http status code: '+res.statusCode))
if (!body)
return cb(new Error('no body result'))
var binary = false
//if the response type is an array buffer,
//we need to convert it into a regular Buffer object
if (isArrayBuffer(body)) {
var array = new Uint8Array(body)
body = Buffer.from(array, 'binary')
}
//now check the string/Buffer response
//and see if it has a binary BMF header
if (isBinaryFormat(body)) {
binary = true
//if we have a string, turn it into a Buffer
if (typeof body === 'string')
body = Buffer.from(body, 'binary')
}
//we are not parsing a binary format, just ASCII/XML/etc
if (!binary) {
//might still be a buffer if responseType is 'arraybuffer'
if (Buffer.isBuffer(body))
body = body.toString(opt.encoding)
body = body.trim()
}
var result
try {
var type = res.headers['content-type']
if (binary)
result = readBinary(body)
else if (/json/.test(type) || body.charAt(0) === '{')
result = JSON.parse(body)
else if (/xml/.test(type) || body.charAt(0) === '<')
result = parseXML(body)
else
result = parseASCII(body)
} catch (e) {
cb(new Error('error parsing font '+e.message))
cb = noop
}
cb(null, result)
})
}
function isArrayBuffer(arr) {
var str = Object.prototype.toString
return str.call(arr) === '[object ArrayBuffer]'
}
function getBinaryOpts(opt) {
//IE10+ and other modern browsers support array buffers
if (xml2)
return xtend(opt, { responseType: 'arraybuffer' })
if (typeof self.XMLHttpRequest === 'undefined')
throw new Error('your browser does not support XHR loading')
//IE9 and XML1 browsers could still use an override
var req = new self.XMLHttpRequest()
req.overrideMimeType('text/plain; charset=x-user-defined')
return xtend({
xhr: req
}, opt)
}
+57
View File
@@ -0,0 +1,57 @@
var fs = require('fs')
var url = require('url')
var path = require('path')
var request = require('phin')
var parseASCII = require('parse-bmfont-ascii')
var parseXML = require('parse-bmfont-xml')
var readBinary = require('parse-bmfont-binary')
var mime = require('mime')
var noop = function() {}
var isBinary = require('./lib/is-binary')
function parseFont(file, data, cb) {
var result, binary
if (isBinary(data)) {
if (typeof data === 'string') data = Buffer.from(data, 'binary')
binary = true
} else data = data.toString().trim()
try {
if (binary) result = readBinary(data)
else if (/json/.test(mime.lookup(file)) || data.charAt(0) === '{')
result = JSON.parse(data)
else if (/xml/.test(mime.lookup(file)) || data.charAt(0) === '<')
result = parseXML(data)
else result = parseASCII(data)
} catch (e) {
cb(e)
cb = noop
}
cb(null, result)
}
module.exports = function loadFont(opt, cb) {
cb = typeof cb === 'function' ? cb : noop
if (typeof opt === 'string') opt = { uri: opt, url: opt }
else if (!opt) opt = {}
var file = opt.uri || opt.url
function handleData(err, data) {
if (err) return cb(err)
parseFont(file, data.body || data, cb)
}
if (url.parse(file).host) {
request(opt).then(function (res) {
handleData(null, res)
}).catch(function (err) {
handleData(err)
})
} else {
fs.readFile(file, opt, handleData)
}
}
+84
View File
@@ -0,0 +1,84 @@
The spec for the JSON output is consistent with the rest of the [BMFont file spec](http://www.angelcode.com/products/bmfont/doc/file_format.html).
Here is what a typical output looks like, omitting the full list of glyphs/kernings for brevity.
```json
{
"pages": [
"sheet.png"
],
"chars": [
{
"id": 10,
"x": 281,
"y": 9,
"width": 0,
"height": 0,
"xoffset": 0,
"yoffset": 24,
"xadvance": 8,
"page": 0,
"chnl": 0
},
{
"id": 32,
"x": 0,
"y": 0,
"width": 0,
"height": 0,
"xoffset": 0,
"yoffset": 0,
"xadvance": 9,
"page": 0,
"chnl": 0
},
...
],
"kernings": [
{
"first": 34,
"second": 65,
"amount": -2
},
{
"first": 34,
"second": 67,
"amount": 1
},
...
],
"info": {
"face": "Nexa Light",
"size": 32,
"bold": 0,
"italic": 0,
"charset": "",
"unicode": 1,
"stretchH": 100,
"smooth": 1,
"aa": 2,
"padding": [
0,
0,
0,
0
],
"spacing": [
0,
0
]
},
"common": {
"lineHeight": 32,
"base": 24,
"scaleW": 1024,
"scaleH": 2048,
"pages": 1,
"packed": 0,
"alphaChnl": 0,
"redChnl": 0,
"greenChnl": 0,
"blueChnl": 0
}
}
```
+8
View File
@@ -0,0 +1,8 @@
var equal = require('buffer-equal')
var HEADER = Buffer.from([66, 77, 70, 3])
module.exports = function(buf) {
if (typeof buf === 'string')
return buf.substring(0, 3) === 'BMF'
return buf.length > 4 && equal(buf.slice(0, 4), HEADER)
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Ethan Davis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+129
View File
@@ -0,0 +1,129 @@
<p align="center" style="text-align: center"><img src="https://raw.githubusercontent.com/ethanent/phin/master/media/phin-textIncluded.png" width="250" alt="phin logo"/></p>
---
> The lightweight Node.js HTTP client
[Full documentation](https://ethanent.github.io/phin/global.html) | [GitHub](https://github.com/ethanent/phin) | [NPM](https://www.npmjs.com/package/phin)
## Deprecated
This package is deprecated and should not be used. Please see [#91](https://github.com/ethanent/phin/issues/91) for more information.
## Simple Usage
```javascript
const p = require('phin')
const res = await p('https://ethanent.me')
console.log(res.body)
```
Note that the above should be in an async context! Phin also provides an unpromisified version of the library.
## Install
```
npm install phin
```
## Why Phin?
Phin is relied upon by important projects and large companies. The hundreds of contributors at [Less](https://github.com/less/less.js), for example, depend on Phin as part of their development process.
Also, Phin is very lightweight. To compare to other libraries, see [Phin vs. the Competition](https://github.com/ethanent/phin/blob/master/README.md#phin-vs-the-competition).
## Quick Demos
Simple POST:
```js
await p({
url: 'https://ethanent.me',
method: 'POST',
data: {
hey: 'hi'
}
})
```
### Unpromisified Usage
```js
const p = require('phin').unpromisified
p('https://ethanent.me', (err, res) => {
if (!err) console.log(res.body)
})
```
Simple parsing of JSON:
```js
// (In async function in this case.)
const res = await p({
'url': 'https://ethanent.me/name',
'parse': 'json'
})
console.log(res.body.first)
```
### Default Options
```js
const ppostjson = p.defaults({
'method': 'POST',
'parse': 'json',
'timeout': 2000
})
// In async function...
const res = await ppostjson('https://ethanent.me/somejson')
// ^ An options object could also be used here to set other options.
// Do things with res.body?
```
### Custom Core HTTP Options
Phin allows you to set [core HTTP options](https://nodejs.org/api/http.html#http_http_request_url_options_callback).
```js
await p({
'url': 'https://ethanent.me/name',
'core': {
'agent': myAgent // Assuming you'd already created myAgent earlier.
}
})
```
## Full Documentation
There's a lot more which can be done with the Phin library.
See [the Phin documentation](https://ethanent.github.io/phin/global.html).
## Phin vs. the Competition
Phin is a very lightweight library, yet it contains all of the common HTTP client features included in competing libraries!
Here's a size comparison table:
Package | Size
--- | ---
request | [![request package size](https://packagephobia.now.sh/badge?p=request)](https://packagephobia.now.sh/result?p=request)
superagent | [![superagent package size](https://packagephobia.now.sh/badge?p=superagent)](https://packagephobia.now.sh/result?p=superagent)
got | [![got package size](https://packagephobia.now.sh/badge?p=got)](https://packagephobia.now.sh/result?p=got)
axios | [![axios package size](https://packagephobia.now.sh/badge?p=axios)](https://packagephobia.now.sh/result?p=axios)
isomorphic-fetch | [![isomorphic-fetch package size](https://packagephobia.now.sh/badge?p=isomorphic-fetch)](https://packagephobia.now.sh/result?p=isomorphic-fetch)
r2 | [![r2 package size](https://packagephobia.now.sh/badge?p=r2)](https://packagephobia.now.sh/result?p=r2)
node-fetch | [![node-fetch package size](https://packagephobia.now.sh/badge?p=node-fetch)](https://packagephobia.now.sh/result?p=node-fetch)
phin | [![phin package size](https://packagephobia.now.sh/badge?p=phin)](https://packagephobia.now.sh/result?p=phin)
+121
View File
@@ -0,0 +1,121 @@
const {URL} = require('url')
const centra = require('centra')
const unspecifiedFollowRedirectsDefault = 20
/**
* phin options object. phin also supports all options from <a href="https://nodejs.org/api/http.html#http_http_request_options_callback">http.request(options, callback)</a> by passing them on to this method (or similar).
* @typedef {Object} phinOptions
* @property {string} url - URL to request (autodetect infers from this URL)
* @property {string} [method=GET] - Request method ('GET', 'POST', etc.)
* @property {string|Buffer|object} [data] - Data to send as request body (phin may attempt to convert this data to a string if it isn't already)
* @property {Object} [form] - Object to send as form data (sets 'Content-Type' and 'Content-Length' headers, as well as request body) (overwrites 'data' option if present)
* @property {Object} [headers={}] - Request headers
* @property {Object} [core={}] - Custom core HTTP options
* @property {string} [parse=none] - Response parsing. Errors will be given if the response can't be parsed. 'none' returns body as a `Buffer`, 'json' attempts to parse the body as JSON, and 'string' attempts to parse the body as a string
* @property {boolean} [followRedirects=false] - Enable HTTP redirect following
* @property {boolean} [stream=false] - Enable streaming of response. (Removes body property)
* @property {boolean} [compression=false] - Enable compression for request
* @property {?number} [timeout=null] - Request timeout in milliseconds
* @property {string} [hostname=autodetect] - URL hostname
* @property {Number} [port=autodetect] - URL port
* @property {string} [path=autodetect] - URL path
*/
/**
* Response data
* @callback phinResponseCallback
* @param {?(Error|string)} error - Error if any occurred in request, otherwise null.
* @param {?http.serverResponse} phinResponse - phin response object. Like <a href='https://nodejs.org/api/http.html#http_class_http_serverresponse'>http.ServerResponse</a> but has a body property containing response body, unless stream. If stream option is enabled, a stream property will be provided to callback with a readable stream.
*/
/**
* Sends an HTTP request
* @param {phinOptions|string} options - phin options object (or string for auto-detection)
* @returns {Promise<http.serverResponse>} - phin-adapted response object
*/
const phin = async (opts) => {
if (typeof(opts) !== 'string') {
if (!opts.hasOwnProperty('url')) {
throw new Error('Missing url option from options for request method.')
}
}
const req = centra(typeof opts === 'object' ? opts.url : opts, opts.method || 'GET')
if (opts.headers) req.header(opts.headers)
if (opts.stream) req.stream()
if (opts.timeout) req.timeout(opts.timeout)
if (opts.data) req.body(opts.data)
if (opts.form) req.body(opts.form, 'form')
if (opts.compression) req.compress()
if (opts.followRedirects) {
if (opts.followRedirects === true) {
req.followRedirects(unspecifiedFollowRedirectsDefault)
} else if (typeof opts.followRedirects === 'number') {
req.followRedirects(opts.followRedirects)
}
}
if (typeof opts.core === 'object') {
Object.keys(opts.core).forEach((optName) => {
req.option(optName, opts.core[optName])
})
}
const res = await req.send()
if (opts.stream) {
res.stream = res
return res
}
else {
res.coreRes.body = res.body
if (opts.parse) {
if (opts.parse === 'json') {
res.coreRes.body = await res.json()
return res.coreRes
}
else if (opts.parse === 'string') {
res.coreRes.body = res.coreRes.body.toString()
return res.coreRes
}
}
return res.coreRes
}
}
// If we're running Node.js 8+, let's promisify it
phin.promisified = phin
phin.unpromisified = (opts, cb) => {
phin(opts).then((data) => {
if (cb) cb(null, data)
}).catch((err) => {
if (cb) cb(err, null)
})
}
// Defaults
phin.defaults = (defaultOpts) => async (opts) => {
const nops = typeof opts === 'string' ? {'url': opts} : opts
Object.keys(defaultOpts).forEach((doK) => {
if (!nops.hasOwnProperty(doK) || nops[doK] === null) {
nops[doK] = defaultOpts[doK]
}
})
return await phin(nops)
}
module.exports = phin
+40
View File
@@ -0,0 +1,40 @@
{
"name": "phin",
"version": "3.7.1",
"description": "The ultra-lightweight Node.js HTTP client",
"main": "lib/phin.js",
"types": "types.d.ts",
"scripts": {
"test": "node ./tests/test.js",
"prepublishOnly": "npm test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ethanent/phin.git"
},
"keywords": [
"http",
"https",
"request",
"fetch",
"ajax",
"url",
"uri"
],
"author": "Ethan Davis",
"license": "MIT",
"bugs": {
"url": "https://github.com/ethanent/phin/issues"
},
"homepage": "https://github.com/ethanent/phin",
"files": [
"lib/phin.js",
"types.d.ts"
],
"engines": {
"node": ">= 8"
},
"dependencies": {
"centra": "^2.7.0"
}
}
+122
View File
@@ -0,0 +1,122 @@
// Default Options feature is not supported because it's basically impossible to write strongly-typed definitions for it.
import * as http from 'http'
import { URL } from 'url';
interface IOptionsBase {
url: string | URL
method?: string
headers?: object
core?: http.ClientRequestArgs
followRedirects?: boolean
stream?: boolean
compression?: boolean
timeout?: number
hostname?: string
port?: number
path?: string
}
declare function phin<T>(options:
phin.IJSONResponseOptions |
phin.IWithData<phin.IJSONResponseOptions> |
phin.IWithForm<phin.IJSONResponseOptions>): Promise<phin.IJSONResponse<T>>
declare function phin(options:
phin.IStringResponseOptions |
phin.IWithData<phin.IStringResponseOptions> |
phin.IWithForm<phin.IStringResponseOptions>): Promise<phin.IStringResponse>
declare function phin(options:
phin.IStreamResponseOptions |
phin.IWithData<phin.IStreamResponseOptions> |
phin.IWithForm<phin.IStreamResponseOptions>): Promise<phin.IStreamResponse>
declare function phin(options:
phin.IOptions |
phin.IWithData<phin.IOptions> |
phin.IWithForm<phin.IOptions> |
string): Promise<phin.IResponse>
declare namespace phin {
// Form and data property has been written this way so they're mutually exclusive.
export type IWithData<T extends IOptionsBase> = T & {
data: string | Buffer | object;
}
export type IWithForm<T extends IOptionsBase> = T & {
form: {
[index: string]: string
}
}
export interface IJSONResponseOptions extends IOptionsBase {
parse: 'json'
}
export interface IStringResponseOptions extends IOptionsBase {
parse: 'string';
}
export interface IStreamResponseOptions extends IOptionsBase {
stream: true
}
export interface IOptions extends IOptionsBase {
parse?: 'none'
}
export interface IJSONResponse<T> extends http.IncomingMessage {
body: T
}
export interface IStringResponse extends http.IncomingMessage {
body: string;
}
export interface IStreamResponse extends http.IncomingMessage {
stream: http.IncomingMessage
}
export interface IResponse extends http.IncomingMessage {
body: Buffer;
}
// NOTE: Typescript cannot infer type of union callback on the consumer side
// https://github.com/Microsoft/TypeScript/pull/17819#issuecomment-363636904
type IErrorCallback = (error: Error | string, response: null) => void
type ICallback<T> = (error: null, response: NonNullable<T>) => void
export let promisified: typeof phin
export function unpromisified<T>(
options:
IJSONResponseOptions |
IWithData<IJSONResponseOptions> |
IWithForm<IJSONResponseOptions>,
callback: IErrorCallback | ICallback<IJSONResponse<T>>): void
export function unpromisified(
options:
IStringResponseOptions |
IWithData<IStringResponseOptions> |
IWithForm<IStringResponseOptions>,
callback: IErrorCallback | ICallback<IStringResponse>): void
export function unpromisified(
options:
IStreamResponseOptions |
IWithData<IStreamResponseOptions> |
IWithForm<IStreamResponseOptions>,
callback: IErrorCallback | ICallback<IStreamResponse>): void
export function unpromisified(
options:
IOptions |
IWithData<IOptions> |
IWithForm<IOptions> |
string,
callback: IErrorCallback | ICallback<IResponse>): void
}
export = phin
+55
View File
@@ -0,0 +1,55 @@
{
"name": "load-bmfont",
"version": "1.4.2",
"description": "loads a BMFont file in Node and the browser",
"main": "index.js",
"browser": "browser.js",
"license": "MIT",
"author": {
"name": "Matt DesLauriers",
"email": "dave.des@gmail.com",
"url": "https://github.com/mattdesl"
},
"dependencies": {
"buffer-equal": "0.0.1",
"mime": "^1.3.4",
"parse-bmfont-ascii": "^1.0.3",
"parse-bmfont-binary": "^1.0.5",
"parse-bmfont-xml": "^1.1.4",
"phin": "^3.7.1",
"xhr": "^2.0.1",
"xtend": "^4.0.0"
},
"devDependencies": {
"browserify": "^9.0.3",
"tap-spec": "^2.2.2",
"tape": "^3.5.0",
"testling": "^1.7.1"
},
"scripts": {
"test-node": "(node test.js; node test-server.js) | tap-spec",
"test-browser": "browserify test.js | testling | tap-spec",
"test": "npm run test-node && npm run test-browser"
},
"keywords": [
"bmfont",
"bitmap",
"font",
"angel",
"code",
"angelcode",
"parse",
"ascii",
"xml",
"text",
"json"
],
"repository": {
"type": "git",
"url": "git://github.com/Jam3/load-bmfont.git"
},
"homepage": "https://github.com/Jam3/load-bmfont",
"bugs": {
"url": "https://github.com/Jam3/load-bmfont/issues"
}
}
+26
View File
@@ -0,0 +1,26 @@
var test = require('tape')
var load = require('./')
var expectedArial = require('./fnt/Arial.json')
var fs = require('fs')
var http = require('http')
var arialBin = fs.readFileSync('fnt/Arial.bin')
test('should load from server URL', function (t) {
t.plan(1)
const server = http.createServer((req,res) => {
res.end(arialBin)
})
server.listen(8003, () => {
load({
url: 'http://localhost:8003',
binary: true
}, (err, res) => {
if (err) t.fail(err)
else t.deepEqual(res, expectedArial)
server.close()
})
})
})