diff --git a/packages/app-cli/tests/services_PluginService.ts b/packages/app-cli/tests/services_PluginService.ts index 4f0a21ed1..33d210fec 100644 --- a/packages/app-cli/tests/services_PluginService.ts +++ b/packages/app-cli/tests/services_PluginService.ts @@ -170,7 +170,9 @@ describe('services_PluginService', function() { const tempDir = await createTempDir(); const contentScriptPath = `${tempDir}/markdownItTestPlugin.js`; + const contentScriptCssPath = `${tempDir}/markdownItTestPlugin.css`; await shim.fsDriver().copy(`${testPluginDir}/content_script/src/markdownItTestPlugin.js`, contentScriptPath); + await shim.fsDriver().copy(`${testPluginDir}/content_script/src/markdownItTestPlugin.css`, contentScriptCssPath); const service = newPluginService(); @@ -205,7 +207,7 @@ describe('services_PluginService', function() { const mdToHtml = new MdToHtml(); const module = require(contentScript.path).default; - mdToHtml.loadExtraRendererRule(contentScript.id, module({})); + mdToHtml.loadExtraRendererRule(contentScript.id, tempDir, module({})); const result = await mdToHtml.render([ '```justtesting', @@ -213,6 +215,11 @@ describe('services_PluginService', function() { '```', ].join('\n')); + const asset = result.pluginAssets.find(a => a.name === 'justtesting/markdownItTestPlugin.css'); + const assetContent: string = await shim.fsDriver().readFile(asset.path, 'utf8'); + + expect(assetContent.includes('.just-testing')).toBe(true); + expect(assetContent.includes('background-color: red;')).toBe(true); expect(result.html.includes('JUST TESTING: something')).toBe(true); await shim.fsDriver().remove(tempDir); diff --git a/packages/app-cli/tests/support/plugins/content_script/package.json b/packages/app-cli/tests/support/plugins/content_script/package.json index a7ad2623f..761cec9f9 100644 --- a/packages/app-cli/tests/support/plugins/content_script/package.json +++ b/packages/app-cli/tests/support/plugins/content_script/package.json @@ -20,4 +20,4 @@ "webpack": "^4.43.0", "webpack-cli": "^3.3.11" } -} \ No newline at end of file +} diff --git a/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.css b/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.css new file mode 100644 index 000000000..a168fce07 --- /dev/null +++ b/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.css @@ -0,0 +1,4 @@ +.just-testing { + background-color: red; + color: yellow; +} \ No newline at end of file diff --git a/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.js b/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.js index bc6bc2aac..a294bfb25 100644 --- a/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.js +++ b/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.js @@ -6,7 +6,7 @@ function plugin(markdownIt, _options) { markdownIt.renderer.rules.fence = function(tokens, idx, options, env, self) { const token = tokens[idx]; if (token.info !== 'justtesting') return defaultRender(tokens, idx, options, env, self); - return `JUST TESTING: ${token.content}`; + return `
JUST TESTING: ${token.content}
`; }; } @@ -14,6 +14,11 @@ module.exports = { default: function(_context) { return { plugin: plugin, + assets: function() { + return [ + { name: 'markdownItTestPlugin.css' } + ]; + }, } }, } diff --git a/packages/renderer/MdToHtml.ts b/packages/renderer/MdToHtml.ts index 1b71b3577..f257105f6 100644 --- a/packages/renderer/MdToHtml.ts +++ b/packages/renderer/MdToHtml.ts @@ -9,6 +9,7 @@ interface RendererRule { install(context: any, ruleOptions: any): any; assets?(theme: any): any; plugin?: any; + assetPath?: string; } interface RendererRules { @@ -197,7 +198,7 @@ export default class MdToHtml { if (options.extraRendererRules) { for (const rule of options.extraRendererRules) { - this.loadExtraRendererRule(rule.id, rule.module); + this.loadExtraRendererRule(rule.id, rule.assetPath, rule.module); } } } @@ -232,15 +233,28 @@ export default class MdToHtml { } // `module` is a file that has already been `required()` - public loadExtraRendererRule(id: string, module: any) { + public loadExtraRendererRule(id: string, assetPath: string, module: any) { if (this.extraRendererRules_[id]) throw new Error(`A renderer rule with this ID has already been loaded: ${id}`); - this.extraRendererRules_[id] = module; + this.extraRendererRules_[id] = { + ...module, + assetPath, + }; + } + + private ruleByKey(key: string): RendererRule { + if (rules[key]) return rules[key]; + if (this.extraRendererRules_[key]) return this.extraRendererRules_[key]; + if (key === 'highlight.js') return null; + throw new Error(`No such rule: ${key}`); } private processPluginAssets(pluginAssets: PluginAssets): RenderResult { const files: RenderResultPluginAsset[] = []; const cssStrings = []; for (const pluginName in pluginAssets) { + + const rule = this.ruleByKey(pluginName); + for (const asset of pluginAssets[pluginName]) { let mime = asset.mime; @@ -263,10 +277,18 @@ export default class MdToHtml { throw new Error(`Unsupported inline mime type: ${mime}`); } } else { + // TODO: we should resolve the path using + // resolveRelativePathWithinDir() for increased + // security, but the shim is not accessible from the + // renderer, and React Native doesn't have this + // function, so for now use the provided path as-is. + const name = `${pluginName}/${asset.name}`; + const assetPath = rule?.assetPath ? `${rule.assetPath}/${asset.name}` : `pluginAssets/${name}`; + files.push(Object.assign({}, asset, { name: name, - path: `pluginAssets/${name}`, + path: assetPath, mime: mime, })); } @@ -282,7 +304,7 @@ export default class MdToHtml { // This return all the assets for all the plugins. Since it is called // on each render, the result is cached. - private allProcessedAssets(theme: any, codeTheme: string) { + private allProcessedAssets(rules: RendererRules, theme: any, codeTheme: string) { const cacheKey: string = theme.cacheKey + codeTheme; if (this.allProcessedAssets_[cacheKey]) return this.allProcessedAssets_[cacheKey]; @@ -501,7 +523,7 @@ export default class MdToHtml { let cssStrings = noteStyle(options.theme); - let output = { ...this.allProcessedAssets(options.theme, options.codeTheme) }; + let output = { ...this.allProcessedAssets(allRules, options.theme, options.codeTheme) }; cssStrings = cssStrings.concat(output.cssStrings); if (options.userCss) cssStrings.push(options.userCss);