mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-24 00:27:40 +00:00
feat(developer): markdown conversion for description in package editor
This commit is contained in:
parent
47e05a7b05
commit
72efe0cd5c
9 changed files with 124 additions and 34 deletions
|
|
@ -28,7 +28,7 @@
|
|||
"@keymanapp/kmc-package": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/chai": "^4.3.5",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^20.4.1",
|
||||
"c8": "^7.12.0",
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ export class KeyboardInfoCompiler {
|
|||
// description
|
||||
|
||||
if(sources.kmpJsonData.info.description?.description) {
|
||||
keyboard_info.description = markDownToHTML(sources.kmpJsonData.info.description?.description);
|
||||
keyboard_info.description = sources.kmpJsonData.info.description?.description.trim();
|
||||
}
|
||||
|
||||
// extract the language identifiers from the language metadata arrays for
|
||||
|
|
@ -438,10 +438,5 @@ export class KeyboardInfoCompiler {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function markDownToHTML(markdown: string): string {
|
||||
// TODO
|
||||
return markdown;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
"languageName": "Khmer"
|
||||
}
|
||||
},
|
||||
"description": "Khmer Unicode keyboard layout based on the NiDA keyboard layout. Automatically corrects many common keying errors.",
|
||||
"description": "<p>Khmer Unicode keyboard layout based on the NiDA keyboard layout. Automatically corrects many common keying errors.</p>",
|
||||
"related": {
|
||||
"khmer10": {
|
||||
"deprecates": true
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@keymanapp/common-types": "*",
|
||||
"jszip": "^3.7.0"
|
||||
"jszip": "^3.7.0",
|
||||
"marked": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@keymanapp/developer-test-helpers": "*",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { transcodeToCP1252 } from './cp1252.js';
|
|||
import { MIN_LM_FILEVERSION_KMP_JSON, PackageVersionValidator } from './package-version-validator.js';
|
||||
import { PackageKeyboardTargetValidator } from './package-keyboard-target-validator.js';
|
||||
import { PackageMetadataUpdater } from './package-metadata-updater.js';
|
||||
import { markdownToHTML } from './markdown.js';
|
||||
|
||||
const KMP_JSON_FILENAME = 'kmp.json';
|
||||
const KMP_INF_FILENAME = 'kmp.inf';
|
||||
|
|
@ -246,26 +247,33 @@ export class KmpCompiler {
|
|||
|
||||
// Helper functions
|
||||
|
||||
private kpsInfoToKmpInfo(info: KpsFile.KpsFileInfo): KmpJsonFile.KmpJsonFileInfo {
|
||||
let ni: KmpJsonFile.KmpJsonFileInfo = {};
|
||||
private kpsInfoToKmpInfo(kpsInfo: KpsFile.KpsFileInfo): KmpJsonFile.KmpJsonFileInfo {
|
||||
let kmpInfo: KmpJsonFile.KmpJsonFileInfo = {};
|
||||
|
||||
const keys: [(keyof KpsFile.KpsFileInfo), (keyof KmpJsonFile.KmpJsonFileInfo)][] = [
|
||||
['author','author'],
|
||||
['copyright','copyright'],
|
||||
['name','name'],
|
||||
['version','version'],
|
||||
['webSite','website'],
|
||||
['description','description'],
|
||||
const keys: [(keyof KpsFile.KpsFileInfo), (keyof KmpJsonFile.KmpJsonFileInfo), boolean][] = [
|
||||
['author','author',false],
|
||||
['copyright','copyright',false],
|
||||
['name','name',false],
|
||||
['version','version',false],
|
||||
['webSite','website',false],
|
||||
['description','description',true],
|
||||
];
|
||||
|
||||
for (let [src,dst] of keys) {
|
||||
if (info[src]) {
|
||||
ni[dst] = {description: (info[src]._ ?? (typeof info[src] == 'string' ? info[src].toString() : '').trim())};
|
||||
if(info[src].$ && info[src].$.URL) ni[dst].url = info[src].$.URL.trim();
|
||||
for (let [src,dst,isMarkdown] of keys) {
|
||||
if (kpsInfo[src]) {
|
||||
kmpInfo[dst] = {
|
||||
description: (kpsInfo[src]._ ?? (typeof kpsInfo[src] == 'string' ? kpsInfo[src].toString() : '')).trim()
|
||||
};
|
||||
if(isMarkdown) {
|
||||
kmpInfo[dst].description = markdownToHTML(kmpInfo[dst].description, false).trim();
|
||||
}
|
||||
if(kpsInfo[src].$?.URL) {
|
||||
kmpInfo[dst].url = kpsInfo[src].$.URL.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ni;
|
||||
return kmpInfo;
|
||||
};
|
||||
|
||||
private arrayWrap(a: unknown) {
|
||||
|
|
|
|||
50
developer/src/kmc-package/src/compiler/markdown.ts
Normal file
50
developer/src/kmc-package/src/compiler/markdown.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Markdown transform for our `description` field. Tweaked to disable all inline
|
||||
* HTML, because we want descriptions to be short and sweet, and don't need any
|
||||
* of the more complex formatting that inline HTML affords.
|
||||
*/
|
||||
|
||||
//
|
||||
// Note: using marked 7.0.0.
|
||||
// https://github.com/markedjs/marked/issues/2926
|
||||
//
|
||||
// Version 7.0.1 introduced a TypeScript 5.0+ feature `export type *` which causes:
|
||||
//
|
||||
// ../../../node_modules/marked/lib/marked.d.ts:722:5 - error TS1383: Only named exports may use 'export type'.
|
||||
// 722 export type * from "MarkedOptions";
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// https://github.com/markedjs/marked/compare/v7.0.0...v7.0.1#diff-32d87a2bc59f429470ccf7afc8ae8818914d4d45c3f7c5b1767c6a0a240b55c9R449-R451
|
||||
//
|
||||
// When we move to TS 5.0, we can upgrade marked.
|
||||
//
|
||||
import { Marked } from 'marked';
|
||||
|
||||
/*
|
||||
Markdown rendering: we don't want to use the global object, because this
|
||||
pollutes the settings for all modules. So we construct our own instance,
|
||||
so that we can strip all inline HTML; we don't need any
|
||||
*/
|
||||
|
||||
const renderer = {
|
||||
html(_html:string, _block:boolean) {
|
||||
// we don't allow inline HTML
|
||||
return '';
|
||||
}
|
||||
}
|
||||
const markedStripHtml = new Marked({renderer});
|
||||
const marked = new Marked();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param markdown
|
||||
* @param allowHTML
|
||||
* @returns
|
||||
*/
|
||||
export function markdownToHTML(markdown: string, allowHTML: boolean): string {
|
||||
// <string>: .parse can return a Promise if async=true. We don't pass ths
|
||||
// option, and this sync usage isn't separated out in the types for
|
||||
// Marked.prototype.parse, so <string> avoids tsc complaints here.
|
||||
const html = <string> (allowHTML ? marked : markedStripHtml).parse(markdown.trim());
|
||||
return html;
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
"url": "https://keyman.com/keyboards/khmer_angkor"
|
||||
},
|
||||
"description": {
|
||||
"description": "# Khmer Angkor\r\n\r\nKhmer Unicode keyboard layout based on the NiDA keyboard layout. Automatically corrects many common keying errors, including:\r\n\r\n* Using wrong vowel combination\r\n* Typing clusters out of order\r\n* Typing wrong mark for consonant shifters\r\n* And more!"
|
||||
"description": "<h1>Khmer Angkor</h1>\n<p>Khmer Unicode keyboard layout based on the NiDA keyboard layout. Automatically corrects many common keying errors, including:</p>\n<ul>\n<li>Using wrong vowel combination</li>\n<li>Typing clusters out of order</li>\n<li>Typing wrong mark for consonant shifters</li>\n<li>And more!</li>\n</ul>"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
|
|
|
|||
20
developer/src/kmc-package/test/test-markdown.ts
Normal file
20
developer/src/kmc-package/test/test-markdown.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { assert } from 'chai';
|
||||
import 'mocha';
|
||||
import { markdownToHTML } from '../src/compiler/markdown.js';
|
||||
|
||||
describe('markdownToHTML', function () {
|
||||
it('should convert markdown into HTML', function() {
|
||||
const html = markdownToHTML('# heading\n\n**bold** and _beautiful_', true);
|
||||
assert.equal(html, `<h1>heading</h1>\n<p><strong>bold</strong> and <em>beautiful</em></p>\n`);
|
||||
});
|
||||
|
||||
it('should strip inline html if asked to do so', function() {
|
||||
const html = markdownToHTML(`# heading\n\n<script>alert('gotcha')</script>\n\n**bold** and _beautiful_`, false);
|
||||
assert.equal(html, `<h1>heading</h1>\n<p><strong>bold</strong> and <em>beautiful</em></p>\n`);
|
||||
});
|
||||
|
||||
it('should keep inline html if asked to do so', function() {
|
||||
const html = markdownToHTML(`# heading\n\n<script>alert('gotcha')</script>\n\n**bold** and _beautiful_`, true);
|
||||
assert.equal(html, `<h1>heading</h1>\n<script>alert('gotcha')</script>\n\n<p><strong>bold</strong> and <em>beautiful</em></p>\n`);
|
||||
});
|
||||
});
|
||||
36
package-lock.json
generated
36
package-lock.json
generated
|
|
@ -997,10 +997,11 @@
|
|||
"name": "@keymanapp/kmc-keyboard-info",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@keymanapp/common-types": "*"
|
||||
"@keymanapp/common-types": "*",
|
||||
"@keymanapp/kmc-package": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/chai": "^4.3.5",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^20.4.1",
|
||||
"c8": "^7.12.0",
|
||||
|
|
@ -2138,7 +2139,8 @@
|
|||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@keymanapp/common-types": "*",
|
||||
"jszip": "^3.7.0"
|
||||
"jszip": "^3.7.0",
|
||||
"marked": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@keymanapp/developer-test-helpers": "*",
|
||||
|
|
@ -7392,8 +7394,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.0",
|
||||
"license": "MIT",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"dependencies": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
|
|
@ -8512,6 +8515,17 @@
|
|||
"markdown-it": "bin/markdown-it.js"
|
||||
}
|
||||
},
|
||||
"node_modules/marked": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-7.0.0.tgz",
|
||||
"integrity": "sha512-7Gv1Ry8tqR352ElQOQfxdGpIh8kNZh/yYjNCxAQCN1DDbY4bCTG3qDCSkZWlRElSseeEILDxkY/G9w7cgziBNw==",
|
||||
"bin": {
|
||||
"marked": "bin/marked.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
}
|
||||
},
|
||||
"node_modules/mdurl": {
|
||||
"version": "1.0.1",
|
||||
"dev": true,
|
||||
|
|
@ -9756,8 +9770,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.1.1",
|
||||
"license": "MIT",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
|
||||
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
|
@ -11290,14 +11305,15 @@
|
|||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.5.0",
|
||||
"license": "MIT",
|
||||
"version": "8.13.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
|
||||
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue