diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4e772eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/dist +/package-lock.json +/typing \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..ac99458 --- /dev/null +++ b/.npmignore @@ -0,0 +1,4 @@ +/src +/.gitignore +/test.js +/tsconfig.json \ No newline at end of file diff --git a/README.md b/README.md index c912b6e..ee86bf8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,21 @@ # yizhi-html-escape -HTML转义字符处理工具 \ No newline at end of file + +A HTML escape character util. (>_<) + + +# Usage + +```javascript +import {escape, unescape} from 'yizhi-html-escape' + +escape('
Tom&Jerry
') +//Output: +// <div>Tom&Jerry</div> + + +unescape('π=3.14, ¥¢£©®') +//Output: +// π=3.14, ¥¢£©® + +``` \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..cb3791f --- /dev/null +++ b/package.json @@ -0,0 +1,31 @@ +{ + "name": "yizhi-html-escape", + "version": "1.0.1", + "description": "HTML escape character util", + "main": "dist/index.js", + "types": "typing/index.d.ts", + "scripts": { + "build": "rm -rf dist typing && tsc" + }, + "repository": { + "type": "git", + "url": "http://git.urnas.cn/yizhi-node-lib/yizhi-html-escape.git" + }, + "keywords": [ + "html", + "special", + "entities", + "nbsp", + "lt", + "gt", + " ", + "escape", + "unescape", + "转义字符", + "character", + "parser", + "HTML转义字符" + ], + "author": "", + "license": "ISC" +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..e1c0d9e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,36 @@ +import { escapeTable, unescapeTable } from "./table" + +/** + * escape string to HTML special entities + * @param str string + * @returns + */ +export function escape(str: string) { + const buffer: Array = [] + let prev = 0 + for (let i = 0; i < str.length; ++i) { + const cc = str.charCodeAt(i) + const name = escapeTable[cc] + if (name) { + buffer.push(str.substring(prev, i)) + buffer.push(`&${name};`) + prev = i + 1 + } + } + return buffer.join('') +} + +/** + * unescape HTML special entities to normal string + * @param str string + * @returns + */ +export function unescape(str: string) { + return str.replace(/&(\w+);/g, (match, name, index) => { + const code = unescapeTable[name] + if (!code) return match + return String.fromCharCode(code) + }) +} + +export default { escape, unescape } \ No newline at end of file diff --git a/src/table.ts b/src/table.ts new file mode 100644 index 0000000..aa8d4cd --- /dev/null +++ b/src/table.ts @@ -0,0 +1,80 @@ +/** ISO 8859-1 (Latin-1)字符集 */ +const latin1 = { + nbsp: 160, iexcl: 161, cent: 162, pound: 163, curren: 164, + yen: 165, brvbar: 166, sect: 167, uml: 168, copy: 169, + ordf: 170, laquo: 171, not: 172, shy: 173, reg: 174, + macr: 175, deg: 176, plusmn: 177, sup2: 178, sup3: 179, + acute: 180, micro: 181, para: 182, middot: 183, cedil: 184, + sup1: 185, ordm: 186, raquo: 187, frac14: 188, frac12: 189, + frac34: 190, iquest: 191, Agrave: 192, Aacute: 193, Acirc: 194, + Atilde: 195, Auml: 196, Aring: 197, AElig: 198, Ccedil: 199, + Egrave: 200, Eacute: 201, Ecirc: 202, Euml: 203, Igrave: 204, + Iacute: 205, Icirc: 206, Iuml: 207, ETH: 208, Ntilde: 209, + Ograve: 210, Oacute: 211, Ocirc: 212, Otilde: 213, Ouml: 214, + times: 215, Oslash: 216, Ugrave: 217, Uacute: 218, Ucirc: 219, + Uuml: 220, Yacute: 221, THORN: 222, szlig: 223, agrave: 224, + aacute: 225, acirc: 226, atilde: 227, auml: 228, aring: 229, + aelig: 230, ccedil: 231, egrave: 232, eacute: 233, ecirc: 234, + euml: 235, igrave: 236, iacute: 237, icirc: 238, iuml: 239, + eth: 240, ntilde: 241, ograve: 242, oacute: 243, ocirc: 244, + otilde: 245, ouml: 246, divide: 247, oslash: 248, ugrave: 249, + uacute: 250, ucirc: 251, uuml: 252, yacute: 253, thorn: 254, + yuml: 255, +} + +/** + * 数学和希腊字母标志 + * + * symbols, mathematical symbols, and Greek letters + */ +const symbols = { + fnof: 402, Alpha: 913, Beta: 914, Gamma: 915, Delta: 916, + Epsilon: 917, Zeta: 918, Eta: 919, Theta: 920, Iota: 921, + Kappa: 922, Lambda: 923, Mu: 924, Nu: 925, Xi: 926, + Omicron: 927, Pi: 928, Rho: 929, Sigma: 931, Tau: 932, + Upsilon: 933, Phi: 934, Chi: 935, Psi: 936, Omega: 937, + alpha: 945, beta: 946, gamma: 947, delta: 948, epsilon: 949, + zeta: 950, eta: 951, theta: 952, iota: 953, kappa: 954, + lambda: 955, mu: 956, nu: 957, xi: 958, omicron: 959, + pi: 960, rho: 961, sigmaf: 962, sigma: 963, tau: 964, + upsilon: 965, phi: 966, chi: 967, psi: 968, omega: 969, + thetasym: 977, upsih: 978, piv: 982, bull: 8226, hellip: 8230, + prime: 8242, Prime: 8243, oline: 8254, frasl: 8260, weierp: 8472, + image: 8465, real: 8476, trade: 8482, alefsym: 8501, larr: 8592, + uarr: 8593, rarr: 8594, darr: 8595, harr: 8596, crarr: 8629, + lArr: 8656, uArr: 8657, rArr: 8658, dArr: 8659, hArr: 8660, + forall: 8704, part: 8706, exist: 8707, empty: 8709, nabla: 8711, + isin: 8712, notin: 8713, ni: 8715, prod: 8719, sum: 8721, + minus: 8722, lowast: 8727, radic: 8730, prop: 8733, infin: 8734, + ang: 8736, and: 8743, or: 8744, cap: 8745, cup: 8746, + int: 8747, there4: 8756, sim: 8764, cong: 8773, asymp: 8776, + ne: 8800, equiv: 8801, le: 8804, ge: 8805, sub: 8834, + sup: 8835, nsub: 8836, sube: 8838, supe: 8839, oplus: 8853, + otimes: 8855, perp: 8869, sdot: 8901, lceil: 8968, rceil: 8969, + lfloor: 8970, rfloor: 8971, lang: 9001, rang: 9002, loz: 9674, + spades: 9824, clubs: 9827, hearts: 9829, diams: 9830, +} + + +/** + * 重要的国际标记 + * + * markup-significant and internationalization characters + */ +const markup = { + quot: 34, amp: 38, lt: 60, gt: 62, OElig: 338, + oelig: 339, Scaron: 352, scaron: 353, Yuml: 376, circ: 710, + tilde: 732, ensp: 8194, emsp: 8195, thinsp: 8201, zwnj: 8204, + zwj: 8205, lrm: 8206, rlm: 8207, ndash: 8211, mdash: 8212, + lsquo: 8216, rsquo: 8217, sbquo: 8218, ldquo: 8220, rdquo: 8221, + bdquo: 8222, dagger: 8224, Dagger: 8225, permil: 8240, lsaquo: 8249, + rsaquo: 8250, euro: 8364, +} + +const unescapeTable: { [K: string]: number } = { ...latin1, ...symbols, ...markup } + +const escapeTable: { [K: number]: string } = {} + +Object.keys(unescapeTable).forEach(key => { escapeTable[unescapeTable[key]] = key }) + +export { escapeTable, unescapeTable } \ No newline at end of file diff --git a/test.js b/test.js new file mode 100644 index 0000000..c62cc1d --- /dev/null +++ b/test.js @@ -0,0 +1,7 @@ +const {escape, unescape} = require('./dist/index') + +const str = `π=3.14, ¥¢£©®` +const str1 = escape(str) +const str2 = unescape(str1) +console.log(str1) +console.log(str2) \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9a50570 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,92 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Language and Environment */ + "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + "rootDir": "./src", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "resolveJsonModule": true, /* Enable importing .json files */ + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + /* Emit */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + "declarationDir": "./typing", /* Specify the output directory for generated declaration files. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} \ No newline at end of file