Compare commits
76 commits
Author | SHA1 | Date | |
---|---|---|---|
|
35c1cd6141 | ||
|
6a4308cb11 | ||
|
a865a53327 | ||
|
e5bcf84b3c | ||
|
3d93c7fdf5 | ||
|
050e4515ca | ||
|
dd783a0daf | ||
|
6c26d381f0 | ||
|
e1ba5039e4 | ||
|
1defdcd4ca | ||
|
ccf16ab7c6 | ||
|
3eee5ebd60 | ||
|
8bd46774dd | ||
|
b7216ab089 | ||
|
a182883320 | ||
|
fd04dc508d | ||
|
953ca11aa8 | ||
|
9d528485ab | ||
|
32c109f1d0 | ||
|
122471a52f | ||
|
fbecff633a | ||
|
5ec93ba9e4 | ||
|
9f43fc595c | ||
|
b363818364 | ||
|
f5a283ba72 | ||
|
ec76650a93 | ||
|
6ca8858d64 | ||
|
6944ff1b82 | ||
|
7fbd5b5d8b | ||
|
a31ddbe203 | ||
|
2f3d7ae4c6 | ||
|
49d16ec079 | ||
|
d29f006090 | ||
|
0b098983b5 | ||
|
5f7c2dfb4b | ||
|
06ab09f278 | ||
|
110c8ca82a | ||
|
d9bea2feb2 | ||
|
76c9a1e67f | ||
|
9685b5d8b8 | ||
|
1d9ce38eb4 | ||
|
e4549711f1 | ||
|
3a312385f6 | ||
|
19b41d9c22 | ||
|
6461e84fe7 | ||
|
cc2da7398e | ||
|
294e9c1f83 | ||
|
20008c9834 | ||
|
381caf644d | ||
|
a901a0ad68 | ||
|
fcdfb50698 | ||
|
ca6e88159e | ||
|
af91c38a02 | ||
|
40011569ab | ||
|
03f89b2196 | ||
|
1f5e0fdab8 | ||
|
e1b817b13b | ||
|
e7402a80ea | ||
|
498112834c | ||
|
e6b9ecf96b | ||
|
ad741eaf48 | ||
|
6eebe39b4d | ||
|
c13cb544cb | ||
|
bbbcd2398e | ||
|
7e35810c7f | ||
|
4c47e54acf | ||
|
dbd6bc8821 | ||
|
51e625dd55 | ||
|
ea852d43f7 | ||
|
47dc53b1a7 | ||
|
a17cbefa51 | ||
|
001219b173 | ||
|
56608c2704 | ||
|
ddef7d0da5 | ||
|
1e0400a160 | ||
|
38048f84de |
49 changed files with 2539 additions and 2136 deletions
94
.eslintrc.js
94
.eslintrc.js
|
@ -1,4 +1,6 @@
|
||||||
const tsconfigs = [
|
const tsconfigs = [
|
||||||
|
'tsconfig.json',
|
||||||
|
'*/tsconfig.json',
|
||||||
'packages/*/tsconfig.json',
|
'packages/*/tsconfig.json',
|
||||||
'packages/*/test/tsconfig.json',
|
'packages/*/test/tsconfig.json',
|
||||||
]
|
]
|
||||||
|
@ -18,15 +20,14 @@ module.exports = {
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
'import/resolver': {
|
'import/resolver': {
|
||||||
// Use eslint-import-resolver-ts to obey "paths" in tsconfig.json.
|
// Use eslint-import-resolver-typescript to obey "paths" in tsconfig.json.
|
||||||
ts: {
|
typescript: {
|
||||||
directory: tsconfigs,
|
directory: tsconfigs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
extends: [
|
extends: [
|
||||||
'eslint:recommended',
|
'eslint:recommended',
|
||||||
'plugin:@typescript-eslint/eslint-recommended',
|
|
||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||||
'standard-with-typescript',
|
'standard-with-typescript',
|
||||||
|
@ -35,48 +36,63 @@ module.exports = {
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
'comma-dangle': ['error', 'always-multiline'],
|
'comma-dangle': ['error', 'always-multiline'],
|
||||||
// Disable in favour of TypeScript rule.
|
|
||||||
'func-call-spacing': 'off',
|
|
||||||
'linebreak-style': ['error', 'unix'],
|
'linebreak-style': ['error', 'unix'],
|
||||||
'lines-between-class-members': 'off',
|
// Changed from error to warn and enabled ignoreEOLComments.
|
||||||
// Disable in favour of TypeScript rule.
|
|
||||||
'no-extra-semi': 'off',
|
|
||||||
'no-multi-spaces': ['warn', {
|
'no-multi-spaces': ['warn', {
|
||||||
ignoreEOLComments: true,
|
ignoreEOLComments: true,
|
||||||
}],
|
}],
|
||||||
|
// Changed from error to warn and adjusted options.
|
||||||
'no-multiple-empty-lines': ['warn', {
|
'no-multiple-empty-lines': ['warn', {
|
||||||
max: 2,
|
max: 2,
|
||||||
maxEOF: 1,
|
maxEOF: 1,
|
||||||
maxBOF: 1,
|
maxBOF: 1,
|
||||||
}],
|
}],
|
||||||
'no-template-curly-in-string': 'off',
|
'no-template-curly-in-string': 'off',
|
||||||
|
// Changed from 'after' to 'before'.
|
||||||
'operator-linebreak': ['error', 'before'],
|
'operator-linebreak': ['error', 'before'],
|
||||||
|
// Changed from error and all 'never' to warn and switches 'never'.
|
||||||
'padded-blocks': ['warn', {
|
'padded-blocks': ['warn', {
|
||||||
switches: 'never',
|
switches: 'never',
|
||||||
}],
|
}],
|
||||||
|
// Changed from 'as-needed' to 'consistent-as-needed'.
|
||||||
'quote-props': ['error', 'consistent-as-needed'],
|
'quote-props': ['error', 'consistent-as-needed'],
|
||||||
// Disable in favour of TypeScript rule.
|
|
||||||
'semi': 'off',
|
|
||||||
|
|
||||||
// Import
|
// Import
|
||||||
|
|
||||||
|
// Some packages have wrong type declarations.
|
||||||
'import/default': 'off',
|
'import/default': 'off',
|
||||||
'import/newline-after-import': 'warn',
|
'import/newline-after-import': 'warn',
|
||||||
'import/no-absolute-path': 'error',
|
|
||||||
// This rule disallows using both wildcard and selective imports from the same module.
|
// This rule disallows using both wildcard and selective imports from the same module.
|
||||||
'import/no-duplicates': 'off',
|
'import/no-duplicates': 'off',
|
||||||
// Some packages has it wrong in type declarations (e.g. katex, marked).
|
// Some packages have it wrong in type declarations (e.g. katex, marked).
|
||||||
'import/no-named-as-default-member': 'off',
|
'import/no-named-as-default-member': 'off',
|
||||||
|
|
||||||
// TypeScript
|
// TypeScript
|
||||||
|
|
||||||
|
// Changed options.
|
||||||
|
'@typescript-eslint/ban-types': ['error', {
|
||||||
|
// Allow to use {} and object - they are actually useful.
|
||||||
|
types: {
|
||||||
|
'{}': false,
|
||||||
|
'object': false,
|
||||||
|
},
|
||||||
|
extendDefaults: true,
|
||||||
|
}],
|
||||||
|
'@typescript-eslint/class-literal-property-style': ['error', 'fields'],
|
||||||
|
// Changed from error to off.
|
||||||
'@typescript-eslint/consistent-type-definitions': 'off',
|
'@typescript-eslint/consistent-type-definitions': 'off',
|
||||||
|
// Changed from error to off.
|
||||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
'@typescript-eslint/explicit-member-accessibility': ['warn', {
|
'@typescript-eslint/explicit-member-accessibility': ['error', {
|
||||||
accessibility: 'no-public',
|
accessibility: 'no-public',
|
||||||
overrides: {
|
overrides: {
|
||||||
parameterProperties: 'off',
|
parameterProperties: 'off',
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
'@typescript-eslint/func-call-spacing': ['error', 'never'],
|
// Changed from warn to error and adjusted options.
|
||||||
|
'@typescript-eslint/explicit-module-boundary-types': ['error', {
|
||||||
|
allowArgumentsExplicitlyTypedAsAny: true,
|
||||||
|
}],
|
||||||
'@typescript-eslint/indent': ['error', 2, {
|
'@typescript-eslint/indent': ['error', 2, {
|
||||||
SwitchCase: 1,
|
SwitchCase: 1,
|
||||||
VariableDeclarator: 1,
|
VariableDeclarator: 1,
|
||||||
|
@ -95,33 +111,58 @@ module.exports = {
|
||||||
flatTernaryExpressions: true,
|
flatTernaryExpressions: true,
|
||||||
ignoreComments: false,
|
ignoreComments: false,
|
||||||
}],
|
}],
|
||||||
|
// Changed from error to warn.
|
||||||
|
'@typescript-eslint/lines-between-class-members': 'warn',
|
||||||
|
// Changed delimiter for type literals from none to comma.
|
||||||
|
// The reason is just aesthetic symmetry with object literals.
|
||||||
'@typescript-eslint/member-delimiter-style': ['error', {
|
'@typescript-eslint/member-delimiter-style': ['error', {
|
||||||
multiline: { delimiter: 'comma', requireLast: true },
|
multiline: { delimiter: 'comma', requireLast: true },
|
||||||
singleline: { delimiter: 'comma', requireLast: false },
|
singleline: { delimiter: 'comma', requireLast: false },
|
||||||
|
overrides: {
|
||||||
|
interface: {
|
||||||
|
multiline: { delimiter: 'none' },
|
||||||
|
},
|
||||||
|
},
|
||||||
}],
|
}],
|
||||||
|
'@typescript-eslint/member-ordering': 'warn',
|
||||||
|
// Changed from warn to off.
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
// Changed from error to warn.
|
||||||
|
'@typescript-eslint/no-extra-semi': 'warn',
|
||||||
|
// It disallows using void even in valid cases.
|
||||||
|
'@typescript-eslint/no-invalid-void-type': 'off',
|
||||||
|
// Changed from error to warn.
|
||||||
'@typescript-eslint/no-namespace': 'warn',
|
'@typescript-eslint/no-namespace': 'warn',
|
||||||
|
// Changed from error to warn.
|
||||||
|
'@typescript-eslint/no-non-null-assertion': 'warn',
|
||||||
'@typescript-eslint/no-require-imports': 'error',
|
'@typescript-eslint/no-require-imports': 'error',
|
||||||
'@typescript-eslint/no-unused-vars': ['error', {
|
// Changed from error to warn.
|
||||||
argsIgnorePattern: '^_',
|
'@typescript-eslint/no-unsafe-assignment': 'warn',
|
||||||
}],
|
// Changed from error to warn.
|
||||||
|
'@typescript-eslint/no-unsafe-member-access': 'warn',
|
||||||
|
// Disabled in favour of the next rule.
|
||||||
|
'@typescript-eslint/no-unused-vars': 'off',
|
||||||
|
'@typescript-eslint/no-unused-vars-experimental': 'error',
|
||||||
|
// Changed options.
|
||||||
'@typescript-eslint/no-use-before-define': ['error', {
|
'@typescript-eslint/no-use-before-define': ['error', {
|
||||||
classes: true,
|
|
||||||
functions: false,
|
functions: false,
|
||||||
typedefs: false,
|
typedefs: false,
|
||||||
variables: true,
|
|
||||||
}],
|
}],
|
||||||
'@typescript-eslint/prefer-for-of': 'warn',
|
'@typescript-eslint/prefer-for-of': 'warn',
|
||||||
|
// Changed from error to warn.
|
||||||
'@typescript-eslint/prefer-includes': 'warn',
|
'@typescript-eslint/prefer-includes': 'warn',
|
||||||
|
// Changed from error to warn.
|
||||||
'@typescript-eslint/prefer-regexp-exec': 'warn',
|
'@typescript-eslint/prefer-regexp-exec': 'warn',
|
||||||
'@typescript-eslint/prefer-string-starts-ends-with': 'warn',
|
'@typescript-eslint/prefer-string-starts-ends-with': 'warn',
|
||||||
'@typescript-eslint/promise-function-async': ['error', {
|
|
||||||
allowAny: true,
|
|
||||||
}],
|
|
||||||
// It has too many false positives.
|
// It has too many false positives.
|
||||||
'@typescript-eslint/restrict-template-expressions': 'off',
|
'@typescript-eslint/restrict-template-expressions': 'off',
|
||||||
'@typescript-eslint/semi': ['error', 'never'],
|
// Changed from error to off.
|
||||||
'@typescript-eslint/strict-boolean-expressions': 'off',
|
'@typescript-eslint/strict-boolean-expressions': 'off',
|
||||||
|
'@typescript-eslint/switch-exhaustiveness-check': 'error',
|
||||||
|
// Changed from error to warn and adjusted options.
|
||||||
|
'@typescript-eslint/unbound-method': ['warn', {
|
||||||
|
ignoreStatic: true,
|
||||||
|
}],
|
||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
|
@ -134,9 +175,9 @@ module.exports = {
|
||||||
objects: 'always-multiline',
|
objects: 'always-multiline',
|
||||||
imports: 'always-multiline',
|
imports: 'always-multiline',
|
||||||
exports: 'always-multiline',
|
exports: 'always-multiline',
|
||||||
|
// Changed to not require comma in a multiline expect().
|
||||||
functions: 'only-multiline',
|
functions: 'only-multiline',
|
||||||
}],
|
}],
|
||||||
'comma-spacing': 'off',
|
|
||||||
'object-curly-spacing': 'off',
|
'object-curly-spacing': 'off',
|
||||||
'no-multi-spaces': 'off',
|
'no-multi-spaces': 'off',
|
||||||
'standard/array-bracket-even-spacing': 'off',
|
'standard/array-bracket-even-spacing': 'off',
|
||||||
|
@ -144,7 +185,10 @@ module.exports = {
|
||||||
'space-in-parens': 'off',
|
'space-in-parens': 'off',
|
||||||
// jest.mock() must be above imports.
|
// jest.mock() must be above imports.
|
||||||
'import/first': 'off',
|
'import/first': 'off',
|
||||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
'@typescript-eslint/comma-spacing': 'off',
|
||||||
|
// False positive on expect() functions.
|
||||||
|
'@typescript-eslint/no-unsafe-call': 'off',
|
||||||
|
'@typescript-eslint/no-unsafe-return': 'warn',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: jirutka
|
68
.github/workflows/ci.yml
vendored
Normal file
68
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
name: CI
|
||||||
|
on:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Test on Node.js ${{ matrix.node-version }}
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [10, 12, 13, 14]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # fetch all history to make `git describe` work
|
||||||
|
|
||||||
|
- name: Setup Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
|
||||||
|
- run: yarn install
|
||||||
|
- run: yarn build
|
||||||
|
- run: yarn bundle
|
||||||
|
- run: yarn test
|
||||||
|
- run: yarn lint
|
||||||
|
|
||||||
|
publish:
|
||||||
|
name: Publish to npmjs and GitHub Releases
|
||||||
|
needs: [test]
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # fetch all history to make `git describe` work
|
||||||
|
|
||||||
|
- run: sudo apt-get install asciidoctor pandoc
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 14
|
||||||
|
registry-url: https://registry.npmjs.org
|
||||||
|
|
||||||
|
- run: yarn install
|
||||||
|
|
||||||
|
- name: Generate source tarball
|
||||||
|
run: ./scripts/create-src-tarball dist/ipynb2html-${GITHUB_REF/refs\/tags\//}-src.tar.gz
|
||||||
|
|
||||||
|
- run: yarn build
|
||||||
|
- run: yarn bundle
|
||||||
|
|
||||||
|
- name: Publish packages to npmjs
|
||||||
|
run: yarn publish-all --non-interactive
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|
||||||
|
- name: Upload tarballs to Releases
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
fail_on_unmatched_files: true
|
||||||
|
files: |
|
||||||
|
dist/*.tar.gz
|
||||||
|
packages/ipynb2html-cli/dist/*.tar.gz
|
||||||
|
packages/ipynb2html-cli/dist/*.zip
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,6 +7,7 @@
|
||||||
/.*cache/
|
/.*cache/
|
||||||
/.tmp/
|
/.tmp/
|
||||||
node_modules/
|
node_modules/
|
||||||
|
.eslintcache
|
||||||
.tsbuildinfo
|
.tsbuildinfo
|
||||||
tsconfig.tsbuildinfo
|
tsconfig.tsbuildinfo
|
||||||
*.log
|
*.log
|
||||||
|
|
54
.travis.yml
54
.travis.yml
|
@ -1,54 +0,0 @@
|
||||||
dist: bionic
|
|
||||||
|
|
||||||
language: node_js
|
|
||||||
node_js:
|
|
||||||
- '10'
|
|
||||||
- '12'
|
|
||||||
- node
|
|
||||||
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- asciidoctor
|
|
||||||
- pandoc
|
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- secure: "DrPA1eYBRjS+1/w/sRq/r5wQyOewuh1PGPzFtQR62TJeAyO6AvKQ6wfesxMA898b+0D3SCNxrCVK12XB3auySEOZocQuN7N51hsteA/QtPoBBbnoHy8Dap2YbiJ5fbCVnM/Wl/Z2rZmQWFBM3rmqXggCyEhKEw3kkz8WMm/7UCGVxmoHUelpMnDEII0RiJdPCGT19IA90KpJDsqbSzTVY+TsqjSNuN91LQ23ApwSHKklvbvKWxcgrtAzJDXLeS9CS3QqSHucurOM2Kpv0umOkBzds4da+NtWKYZC3XxThmMB5wT7b60EZPIc/iFftQFy2qiDAFxeGN+j9kwsNX68aXl4MuCGlzdvGj0KkeXYYhl1Jusc30uTzXYMlz2b3u+AcsMLLxFs2HvUU94SpAfe9VrarSnQK+6CZz0eCtF/NCCi6J9GqlBTsqzZDmdVaJpFDG1FidC4Ka9FcteKcWXqffowQ5KjIhqaearSmRESMqepV7T8tDUCb217PE0C+L0NGfg6RaY4DtGsJAawDeh/09aXrP6NakAKjWUfaJqjhkMexB8JTb+yanjVXsgj4VUfvTgvWjMi+yU3DIfopL+mawvgckRRL9DTEIf5ICjSruyEH8FWEz+kMzas41zboabR12YMLuorHfgZu31DiDsJkSD292t/lwWW6oybRl0iJBk=" # NPM_TOKEN=ceed......2bf2
|
|
||||||
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
install:
|
|
||||||
- yarn install
|
|
||||||
- test -z "$TRAVIS_TAG" || ./scripts/create-src-tarball dist/ipynb2html-$TRAVIS_TAG-src.tar.gz
|
|
||||||
|
|
||||||
script:
|
|
||||||
- yarn run build
|
|
||||||
- yarn run bundle
|
|
||||||
- yarn run test
|
|
||||||
- yarn run lint
|
|
||||||
|
|
||||||
before_deploy:
|
|
||||||
- echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' >> "$HOME"/.npmrc
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
- provider: script
|
|
||||||
script: yarn publish-all --non-interactive
|
|
||||||
skip_cleanup: true
|
|
||||||
on:
|
|
||||||
repo: jirutka/ipynb2html
|
|
||||||
tags: true
|
|
||||||
node_js: '10'
|
|
||||||
- provider: releases
|
|
||||||
api_key:
|
|
||||||
secure: j5Ks+lUUE2NkUKKC4A+FRKVia3oRyanMKp25jZwF2jLOQxZp0/BggNOduw7zMLzPizmMbz7CkYV/pLyXH+rwCjOdQPnSGLorzfp6ztzG49SqPUK5i5PdSctYT7+C2HdYR25xtw6f06HXzLWTIeYb0JG+5pUCkI4R+z1JEqZhx3PMOkAx9Ec9UoYNKcbHe1E78y8zH0pDccVJ1ejrbmizEqZALpYNR+qCWhTfLVbwYlpJJGIKCIXVYI9tU/3y/6JOO+gCX2m8jqNVBPrwWWD//gGExn2lR6BK0WiXTE71FbM7GyVjoeh93Zg1WifF+7DBtaTI9qs+928afLn28AcWqB6P/HgoRgt/4oLvJU2hkdkIoNqQONqYZeglW1A5qYp6T3nURLpcn1cg2yBD6vNi8cet4ntgOsPu9Soa8pzsm9xcITMJNUlFOEWyYPyvgTXHUjZwbZvrZHRVYeHrDOuq9EEAz+11u1FYG49uSBZf3+H6CmL7n2qeoYhlMhT94bgIkF4ByFmP+OTUcMcWvDdA7uD8JqPMaxQI0hhjrszxPT7C5YNXsJ1Q0vU2zZSMF74fygsXlnr6VeqwxSzgF/6mAAuSwtKSg/pFPPLdevIeehw4oLCz+ZdxVk5kpfymKvqvueDdMMoV4Fse4Yhv81Z76tAPM35TtqJa77DJwqOVOCE=
|
|
||||||
file_glob: true
|
|
||||||
file:
|
|
||||||
- dist/*.tar.gz
|
|
||||||
- packages/ipynb2html-cli/dist/*.tar.gz
|
|
||||||
- packages/ipynb2html-cli/dist/*.zip
|
|
||||||
skip_cleanup: true
|
|
||||||
on:
|
|
||||||
repo: jirutka/ipynb2html
|
|
||||||
tags: true
|
|
||||||
node_js: '10'
|
|
12
README.adoc
12
README.adoc
|
@ -2,15 +2,15 @@
|
||||||
:npm-name: ipynb2html
|
:npm-name: ipynb2html
|
||||||
:gh-name: jirutka/{npm-name}
|
:gh-name: jirutka/{npm-name}
|
||||||
:gh-branch: master
|
:gh-branch: master
|
||||||
:version: 0.1.0
|
:version: 0.3.0
|
||||||
:ansiup-version: 4.0.4
|
:ansiup-version: 5.0.1
|
||||||
:hljs-version: 9.15.10
|
:hljs-version: 10.7.3
|
||||||
:katex-version: 0.11.1
|
:katex-version: 0.13.11
|
||||||
:marked-version: 0.7.0
|
:marked-version: 2.0.7
|
||||||
:vs-marketplace-uri: https://marketplace.visualstudio.com/items?itemName=
|
:vs-marketplace-uri: https://marketplace.visualstudio.com/items?itemName=
|
||||||
|
|
||||||
ifdef::env-github[]
|
ifdef::env-github[]
|
||||||
image:https://travis-ci.com/{gh-name}.svg?branch={gh-branch}[Build Status, link="https://travis-ci.com/{gh-name}"]
|
image:https://github.com/{gh-name}/workflows/CI/badge.svg[CI Status, link=https://github.com/{gh-name}/actions?query=workflow%3A%22CI%22]
|
||||||
endif::env-github[]
|
endif::env-github[]
|
||||||
|
|
||||||
{npm-name} is a converter (renderer) of the https://nbformat.readthedocs.io/en/stable/[Jupyter Notebook Format] 4.0+ to static HTML.
|
{npm-name} is a converter (renderer) of the https://nbformat.readthedocs.io/en/stable/[Jupyter Notebook Format] 4.0+ to static HTML.
|
||||||
|
|
|
@ -7,11 +7,11 @@
|
||||||
<link rel="stylesheet" href="../packages/ipynb2html/dist/notebook.min.css">
|
<link rel="stylesheet" href="../packages/ipynb2html/dist/notebook.min.css">
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css"
|
href="https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.css"
|
||||||
crossorigin="anonymous">
|
crossorigin="anonymous">
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.15.10/build/styles/default.min.css"
|
href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.7.3/build/styles/default.min.css"
|
||||||
crossorigin="anonymous">
|
crossorigin="anonymous">
|
||||||
<script defer src="../packages/ipynb2html/dist/ipynb2html-full.js" onload="ipynb2html.autoRender();"></script>
|
<script defer src="../packages/ipynb2html/dist/ipynb2html-full.js" onload="ipynb2html.autoRender();"></script>
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -7,16 +7,16 @@
|
||||||
<link rel="stylesheet" href="../packages/ipynb2html/dist/notebook.min.css">
|
<link rel="stylesheet" href="../packages/ipynb2html/dist/notebook.min.css">
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css"
|
href="https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.css"
|
||||||
crossorigin="anonymous">
|
crossorigin="anonymous">
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.15.10/build/styles/default.min.css"
|
href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.7.3/build/styles/default.min.css"
|
||||||
crossorigin="anonymous">
|
crossorigin="anonymous">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/marked@0.7.0/marked.min.js" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/marked@2.0.7/marked.min.js" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/ansi_up@4.0.4/ansi_up.js" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/ansi_up@5.0.1/ansi_up.js" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.15.10/build/highlight.min.js" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.7.3/build/highlight.min.js" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.js" crossorigin="anonymous"></script>
|
||||||
<script defer src="../packages/ipynb2html/dist/ipynb2html.js" onload="ipynb2html.autoRender();"></script>
|
<script defer src="../packages/ipynb2html/dist/ipynb2html.js" onload="ipynb2html.autoRender();"></script>
|
||||||
<style>
|
<style>
|
||||||
html, body {
|
html, body {
|
||||||
|
|
|
@ -63,7 +63,7 @@ module.exports = {
|
||||||
globals: {
|
globals: {
|
||||||
'ts-jest': {
|
'ts-jest': {
|
||||||
compiler: 'ttypescript',
|
compiler: 'ttypescript',
|
||||||
tsConfig: '<rootDir>/tsconfig.json',
|
tsConfig: '<rootDir>/test/tsconfig.json',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
71
package.json
71
package.json
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "ipynb2html-parent",
|
"name": "ipynb2html-parent",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "ttsc --build",
|
"build": "ttsc --build",
|
||||||
"bundle": "wsrun --exclude-missing bundle",
|
"bundle": "wsrun --exclude-missing bundle",
|
||||||
"clean": "rimraf coverage/ dist/ lib/ *.log && wsrun clean",
|
"clean": "rimraf coverage/ dist/ lib/ .eslintcache *.log && wsrun clean",
|
||||||
"lint": "eslint --ext .ts,.tsx,.js .",
|
"lint": "eslint --cache --ext .ts,.tsx,.js .",
|
||||||
"postinstall": "patch-package && run-s build",
|
"postinstall": "patch-package && run-s build",
|
||||||
"publish-all": "wsrun --serial publish",
|
"publish-all": "wsrun --serial publish",
|
||||||
"test": "jest --detectOpenHandles --coverage --verbose",
|
"test": "jest --detectOpenHandles --coverage --verbose",
|
||||||
|
@ -17,55 +17,52 @@
|
||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.8.3",
|
"@babel/core": "^7.10.3",
|
||||||
"@babel/preset-env": "^7.8.3",
|
"@babel/preset-env": "^7.10.3",
|
||||||
"@rollup/plugin-commonjs": "^11.0.1",
|
"@rollup/plugin-babel": "^5.0.3",
|
||||||
"@rollup/plugin-node-resolve": "^7.0.0",
|
"@rollup/plugin-commonjs": "^13.0.0",
|
||||||
|
"@rollup/plugin-node-resolve": "^8.0.1",
|
||||||
"@types/dedent": "^0.7.0",
|
"@types/dedent": "^0.7.0",
|
||||||
"@types/highlightjs": "^9.12.0",
|
"@types/jest": "^24.9.1",
|
||||||
"@types/jest": "^24.9.0",
|
"@types/node": "^10.17.25",
|
||||||
"@types/katex": "^0.11.0",
|
"@typescript-eslint/eslint-plugin": "^3.3.0",
|
||||||
"@types/marked": "^0.7.2",
|
"@typescript-eslint/parser": "^3.3.0",
|
||||||
"@types/node": "^10.13.0",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^2.17.0",
|
|
||||||
"@typescript-eslint/parser": "^2.17.0",
|
|
||||||
"ansi_up": "^4.0.4",
|
|
||||||
"arrify": "^2.0.1",
|
"arrify": "^2.0.1",
|
||||||
"common-path-prefix": "^3.0.0",
|
"common-path-prefix": "^3.0.0",
|
||||||
"core-js": "^3.6.4",
|
"core-js": "^3.6.5",
|
||||||
"csso-cli": "^3.0.0",
|
"csso-cli": "^3.0.0",
|
||||||
"dedent": "^0.7.0",
|
"dedent": "^0.7.0",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^7.3.0",
|
||||||
"eslint-config-standard-with-typescript": "^12.0.1",
|
"eslint-config-standard-with-typescript": "^18.0.2",
|
||||||
"eslint-import-resolver-ts": "^0.4.0",
|
"eslint-import-resolver-typescript": "^2.0.0",
|
||||||
"eslint-plugin-import": "^2.20.0",
|
"eslint-plugin-import": "^2.21.2",
|
||||||
"eslint-plugin-node": "^11.0.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
"eslint-plugin-standard": "^4.0.0",
|
"eslint-plugin-standard": "^4.0.0",
|
||||||
"fs-extra": "^8.1.0",
|
"fs-extra": "^8.1.0",
|
||||||
"jest": "^25.1.0",
|
"jest": "^25.5.4",
|
||||||
"jest-chain": "^1.1.2",
|
"jest-chain": "^1.1.5",
|
||||||
|
"node-html-parser": "^1.2.19",
|
||||||
"nodom": "^2.3.0",
|
"nodom": "^2.3.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"patch-package": "^6.2.0",
|
"patch-package": "^6.2.2",
|
||||||
"postinstall-postinstall": "^2.0.0",
|
"postinstall-postinstall": "^2.1.0",
|
||||||
"rimraf": "^3.0.0",
|
"rimraf": "^3.0.2",
|
||||||
"rollup": "^1.29.1",
|
"rollup": "^2.17.1",
|
||||||
"rollup-plugin-add-git-msg": "^1.1.0",
|
"rollup-plugin-add-git-msg": "^1.1.0",
|
||||||
"rollup-plugin-babel": "^4.3.3",
|
"rollup-plugin-executable": "^1.6.0",
|
||||||
"rollup-plugin-executable": "^1.5.2",
|
"rollup-plugin-node-externals": "^2.2.0",
|
||||||
"rollup-plugin-node-externals": "^2.1.3",
|
|
||||||
"rollup-plugin-node-license": "^0.2.0",
|
"rollup-plugin-node-license": "^0.2.0",
|
||||||
"rollup-plugin-terser": "^5.2.0",
|
"rollup-plugin-terser": "^6.1.0",
|
||||||
"rollup-plugin-typescript2": "^0.25.3",
|
"rollup-plugin-typescript2": "^0.27.1",
|
||||||
"tar": "^5.0.5",
|
"tar": "^5.0.10",
|
||||||
"ts-jest": "^25.0.0",
|
"ts-jest": "^25.5.1",
|
||||||
"ts-node": "^8.6.2",
|
"ts-node": "^8.10.2",
|
||||||
"ts-transformer-export-default-name": "^0.1.0",
|
"ts-transformer-export-default-name": "^0.1.0",
|
||||||
"ts-transformer-inline-file": "^0.1.1",
|
"ts-transformer-inline-file": "^0.1.1",
|
||||||
"ttypescript": "^1.5.10",
|
"ttypescript": "^1.5.10",
|
||||||
"typescript": "~3.7.5",
|
"typescript": "~3.9.5",
|
||||||
"wsrun": "^5.2.0",
|
"wsrun": "^5.2.1",
|
||||||
"yarn-version-bump": "^0.0.3",
|
"yarn-version-bump": "^0.0.3",
|
||||||
"yazl": "^2.5.1"
|
"yazl": "^2.5.1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ipynb2html-cli",
|
"name": "ipynb2html-cli",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"description": "CLI tool for converting Jupyter Notebooks to static HTML",
|
"description": "CLI tool for converting Jupyter Notebooks to static HTML",
|
||||||
"author": "Jakub Jirutka <jakub@jirutka.cz>",
|
"author": "Jakub Jirutka <jakub@jirutka.cz>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@ -31,8 +31,8 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "ttsc --build",
|
"build": "ttsc --build",
|
||||||
"bundle": "rollup -c && ./scripts/pack-bundle",
|
"bundle": "rollup -c && ./scripts/pack-bundle",
|
||||||
"clean": "rimraf coverage/ dist/ lib/ .tsbuildinfo",
|
"clean": "rimraf coverage/ dist/ lib/ .eslintcache .tsbuildinfo",
|
||||||
"lint": "eslint --ext .ts,.tsx,.js .",
|
"lint": "PKGDIR=$PWD; cd ../../ && eslint --cache --ext .ts,.tsx,.js $PKGDIR",
|
||||||
"prepublishOnly": "run-s readme2md",
|
"prepublishOnly": "run-s readme2md",
|
||||||
"readme2md": "../../scripts/adoc2md -a npm-readme ../../README.adoc > README.md",
|
"readme2md": "../../scripts/adoc2md -a npm-readme ../../README.adoc > README.md",
|
||||||
"watch-ts": "ttsc --build --watch"
|
"watch-ts": "ttsc --build --watch"
|
||||||
|
@ -41,8 +41,8 @@
|
||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ipynb2html": "0.1.0",
|
"ipynb2html": "0.3.0",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.6",
|
||||||
"minimist-options": "^4.0.2",
|
"minimist-options": "^4.0.2",
|
||||||
"nodom": "^2.3.0",
|
"nodom": "^2.3.0",
|
||||||
"source-map-support": "^0.5.16"
|
"source-map-support": "^0.5.16"
|
||||||
|
|
|
@ -26,9 +26,6 @@ export default {
|
||||||
incremental: true,
|
incremental: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// This is needed for node-license plugin. :(
|
|
||||||
// https://github.com/ezolenko/rollup-plugin-typescript2#plugins-using-asyncawait
|
|
||||||
objectHashIgnoreUnknownHack: true,
|
|
||||||
clean: true,
|
clean: true,
|
||||||
}),
|
}),
|
||||||
// Make node builtins external.
|
// Make node builtins external.
|
||||||
|
|
|
@ -3,14 +3,17 @@ import minimist from 'minimist'
|
||||||
import minimistOptions from 'minimist-options'
|
import minimistOptions from 'minimist-options'
|
||||||
import { Document } from 'nodom'
|
import { Document } from 'nodom'
|
||||||
import { exit } from 'process'
|
import { exit } from 'process'
|
||||||
import { $INLINE_JSON } from 'ts-transformer-inline-file'
|
import { $INLINE_FILE, $INLINE_JSON } from 'ts-transformer-inline-file'
|
||||||
|
|
||||||
import * as ipynb2html from 'ipynb2html'
|
import * as ipynb2html from 'ipynb2html'
|
||||||
|
|
||||||
import renderPage from './page'
|
import renderPage from './page'
|
||||||
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
const { version, bugs: bugsUrl } = $INLINE_JSON('../package.json')
|
const { version, bugs: bugsUrl } = $INLINE_JSON('../package.json')
|
||||||
|
const notebookCss = $INLINE_FILE('../../ipynb2html/styles/notebook.css')
|
||||||
|
const pageCss = $INLINE_FILE('./page.css')
|
||||||
const progName = 'ipynb2html'
|
const progName = 'ipynb2html'
|
||||||
|
|
||||||
const helpMsg = `\
|
const helpMsg = `\
|
||||||
|
@ -25,7 +28,14 @@ Arguments:
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-d --debug Print debug messages.
|
-d --debug Print debug messages.
|
||||||
|
|
||||||
|
-s --style <file,...> Comma separated stylesheet(s) to embed into the output
|
||||||
|
HTML. The stylesheet may be a path to a CSS file,
|
||||||
|
"@base" for the base ipynb2html style, or "@default"
|
||||||
|
for the default full page style. Default is @default.
|
||||||
|
|
||||||
-h --help Show this message and exit.
|
-h --help Show this message and exit.
|
||||||
|
|
||||||
-V --version Print version and exit.
|
-V --version Print version and exit.
|
||||||
|
|
||||||
Exit Codes:
|
Exit Codes:
|
||||||
|
@ -39,9 +49,14 @@ function logErr (msg: string): void {
|
||||||
console.error(`${progName}: ${msg}`)
|
console.error(`${progName}: ${msg}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function arrify <T> (obj: T | T[]): T[] {
|
||||||
|
return Array.isArray(obj) ? obj : [obj]
|
||||||
|
}
|
||||||
|
|
||||||
function parseCliArgs (argv: string[]) {
|
function parseCliArgs (argv: string[]) {
|
||||||
const opts = minimist(argv, minimistOptions({
|
const opts = minimist(argv, minimistOptions({
|
||||||
debug: { alias: 'd', type: 'boolean' },
|
debug: { alias: 'd', type: 'boolean' },
|
||||||
|
style: { alias: 's', type: 'string', default: '@default' },
|
||||||
version: { alias: 'V', type: 'boolean' },
|
version: { alias: 'V', type: 'boolean' },
|
||||||
help: { alias: 'h', type: 'boolean' },
|
help: { alias: 'h', type: 'boolean' },
|
||||||
arguments: 'string',
|
arguments: 'string',
|
||||||
|
@ -73,24 +88,35 @@ function parseCliArgs (argv: string[]) {
|
||||||
const [input, output] = opts._
|
const [input, output] = opts._
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
styles: arrify(opts.style).join(',').split(/,\s*/),
|
||||||
debug: opts.debug as boolean,
|
debug: opts.debug as boolean,
|
||||||
input: input === '-' ? 0 : input, // 0 = stdin
|
input: input === '-' ? 0 : input, // 0 = stdin
|
||||||
output,
|
output,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadStyle (name: string): string {
|
||||||
|
switch (name) {
|
||||||
|
case '@base': return notebookCss
|
||||||
|
case '@default': return pageCss + notebookCss
|
||||||
|
default: return fs.readFileSync(name, 'utf8')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default (argv: string[]): void => {
|
export default (argv: string[]): void => {
|
||||||
const opts = parseCliArgs(argv)
|
const opts = parseCliArgs(argv)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
const notebook = JSON.parse(fs.readFileSync(opts.input, 'utf-8'))
|
const notebook = JSON.parse(fs.readFileSync(opts.input, 'utf-8'))
|
||||||
|
const style = opts.styles.map(loadStyle).join('\n')
|
||||||
|
|
||||||
const title = ipynb2html.readNotebookTitle(notebook) ?? 'Notebook'
|
const title = ipynb2html.readNotebookTitle(notebook) || 'Notebook'
|
||||||
|
|
||||||
const renderNotebook = ipynb2html.createRenderer(new Document())
|
const renderNotebook = ipynb2html.createRenderer(new Document())
|
||||||
const contents = renderNotebook(notebook).outerHTML
|
const contents = renderNotebook(notebook).outerHTML
|
||||||
|
|
||||||
const html = renderPage(contents, title)
|
const html = renderPage({ contents, title, style })
|
||||||
|
|
||||||
if (opts.output) {
|
if (opts.output) {
|
||||||
fs.writeFileSync(opts.output, html)
|
fs.writeFileSync(opts.output, html)
|
||||||
|
@ -101,7 +127,7 @@ export default (argv: string[]): void => {
|
||||||
if (opts.debug) {
|
if (opts.debug) {
|
||||||
console.debug(err)
|
console.debug(err)
|
||||||
} else {
|
} else {
|
||||||
logErr(err.message)
|
logErr((err as Error).message)
|
||||||
}
|
}
|
||||||
return exit(1)
|
return exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,32 @@ pre {
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
h1, h2, h3, h4, h5, h6 {
|
||||||
margin-top: 1.6em;
|
margin-top: 1.6em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 .anchor,
|
||||||
|
h2 .anchor,
|
||||||
|
h3 .anchor,
|
||||||
|
h4 .anchor,
|
||||||
|
h5 .anchor,
|
||||||
|
h6 .anchor {
|
||||||
|
display: block;
|
||||||
|
width: 1em;
|
||||||
|
left: -1em;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1:hover .anchor,
|
||||||
|
h2:hover .anchor,
|
||||||
|
h3:hover .anchor,
|
||||||
|
h4:hover .anchor,
|
||||||
|
h5:hover .anchor,
|
||||||
|
h6:hover .anchor {
|
||||||
|
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50'%3E%3Cg fill='none' stroke='%23000' stroke-width='3'%3E%3Cpath d='M26.1 22a5.8 5.8 0 00-8.1 0l-9.6 9.5a5.8 5.8 0 008.2 8.2l5.8-5.9'/%3E%3Cpath d='M23.6 28a5.8 5.8 0 008.2 0l9.5-9.5a5.8 5.8 0 00-8.1-8.2l-5.8 5.9'/%3E%3C/g%3E%3C/svg%3E") no-repeat 100% center;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
|
|
|
@ -1,26 +1,30 @@
|
||||||
import { $INLINE_FILE } from 'ts-transformer-inline-file'
|
import { version } from 'ipynb2html'
|
||||||
|
|
||||||
const notebookCss = $INLINE_FILE('../../ipynb2html/styles/notebook.css')
|
|
||||||
const pageCss = $INLINE_FILE('./page.css')
|
|
||||||
|
|
||||||
|
|
||||||
export default (contents: string, title: string): string => `\
|
export type Options = {
|
||||||
|
contents: string,
|
||||||
|
title: string,
|
||||||
|
style: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ({ contents, title, style }: Options): string => `\
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="initial-scale=1">
|
<meta name="viewport" content="initial-scale=1">
|
||||||
|
<meta name="generator" content="ipynb2html ${version}">
|
||||||
<title>${title}</title>
|
<title>${title}</title>
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.15.10/build/styles/default.min.css"
|
href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.7.3/build/styles/default.min.css"
|
||||||
integrity="sha384-ut3ELVx81ErZQaaMTknSmGb0CEGAKoBFTamRcY1ddG4guN0aoga4C+B6B7Kv1Ll1"
|
integrity="sha384-s4RLYRjGGbVqKOyMGGwfxUTMOO6D7r2eom7hWZQ6BjK2Df4ZyfzLXEkonSm0KLIQ"
|
||||||
crossorigin="anonymous">
|
crossorigin="anonymous">
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
href="https://cdn.jsdelivr.net/npm/katex@0.11.0/dist/katex.min.css"
|
href="https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.css"
|
||||||
integrity="sha384-BdGj8xC2eZkQaxoQ8nSLefg4AV4/AwB3Fj+8SUSo7pnKP6Eoy18liIKTPn9oBYNG"
|
integrity="sha384-Um5gpz1odJg5Z4HAmzPtgZKdTBHZdw8S29IecapCSB31ligYPhHQZMIlWLYQGVoc"
|
||||||
crossorigin="anonymous">
|
crossorigin="anonymous">
|
||||||
<style>
|
<style>
|
||||||
${(pageCss + notebookCss).slice(0, -1).replace(/\n\n/g, '\n').replace(/^/gm, ' ')}
|
${style.replace(/\n\n/g, '\n').replace(/\n$/, '').replace(/^/gm, ' ')}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -5,11 +5,6 @@
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"tsBuildInfoFile": "./.tsbuildinfo",
|
"tsBuildInfoFile": "./.tsbuildinfo",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
|
||||||
"*": ["../../types/*"],
|
|
||||||
"@/*": ["./src/*"],
|
|
||||||
"~/*": ["../../*"],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./src",
|
"./src",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ipynb2html-core",
|
"name": "ipynb2html-core",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"description": "Convert Jupyter Notebook to static HTML",
|
"description": "Convert Jupyter Notebook to static HTML",
|
||||||
"author": "Jakub Jirutka <jakub@jirutka.cz>",
|
"author": "Jakub Jirutka <jakub@jirutka.cz>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@ -25,8 +25,8 @@
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "ttsc --build",
|
"build": "ttsc --build",
|
||||||
"clean": "rimraf coverage/ lib/ .tsbuildinfo",
|
"clean": "rimraf coverage/ lib/ .eslintcache .tsbuildinfo",
|
||||||
"lint": "eslint --ext .ts,.tsx,.js .",
|
"lint": "PKGDIR=$PWD; cd ../../ && eslint --cache --ext .ts,.tsx,.js $PKGDIR",
|
||||||
"prepublishOnly": "run-s readme2md",
|
"prepublishOnly": "run-s readme2md",
|
||||||
"test": "jest --detectOpenHandles --coverage --verbose",
|
"test": "jest --detectOpenHandles --coverage --verbose",
|
||||||
"readme2md": "../../scripts/adoc2md -a npm-readme ../../README.adoc > README.md",
|
"readme2md": "../../scripts/adoc2md -a npm-readme ../../README.adoc > README.md",
|
||||||
|
|
|
@ -4,8 +4,8 @@ type Attributes = { [k: string]: string }
|
||||||
// for this module's function.
|
// for this module's function.
|
||||||
export type MinimalElement = {
|
export type MinimalElement = {
|
||||||
innerHTML: string,
|
innerHTML: string,
|
||||||
setAttribute (name: string, value: string): void,
|
setAttribute: (name: string, value: string) => void,
|
||||||
appendChild (child: any): any,
|
appendChild: (child: any) => unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ElementCreator<TElement = HTMLElement> =
|
export type ElementCreator<TElement = HTMLElement> =
|
||||||
|
|
|
@ -1,22 +1,27 @@
|
||||||
|
|
||||||
const htmlEntities = {
|
const htmlEntities: Record<string, string> = {
|
||||||
'&': '&',
|
'&': '&',
|
||||||
'<': '<',
|
'<': '<',
|
||||||
'>': '>',
|
'>': '>',
|
||||||
}
|
}
|
||||||
|
|
||||||
type CallableConstructor = new <T> () => T extends { __call__: Function }
|
type Callable = (...args: any[]) => any
|
||||||
|
|
||||||
|
type CallableConstructor = new <T> () => T extends { __call__: Callable }
|
||||||
? T['__call__']
|
? T['__call__']
|
||||||
: 'subclass does not implement method __call__'
|
: 'subclass does not implement method __call__'
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment,
|
||||||
|
@typescript-eslint/no-unsafe-member-access,
|
||||||
|
@typescript-eslint/ban-types */
|
||||||
export const CallableInstance: CallableConstructor = function Callable (
|
export const CallableInstance: CallableConstructor = function Callable (
|
||||||
this: object,
|
this: object,
|
||||||
): Function {
|
): Callable {
|
||||||
|
|
||||||
const func = this.constructor.prototype.__call__ as Function
|
const func = this.constructor.prototype.__call__ as Callable
|
||||||
|
|
||||||
const cls = function (...args: any[]) {
|
const cls = function (...args: any[]) {
|
||||||
return func.apply(cls, args)
|
return func.apply(cls, args) as unknown
|
||||||
}
|
}
|
||||||
Object.setPrototypeOf(cls, this.constructor.prototype)
|
Object.setPrototypeOf(cls, this.constructor.prototype)
|
||||||
|
|
||||||
|
@ -33,13 +38,16 @@ export const CallableInstance: CallableConstructor = function Callable (
|
||||||
return cls
|
return cls
|
||||||
} as any
|
} as any
|
||||||
CallableInstance.prototype = Object.create(Function.prototype)
|
CallableInstance.prototype = Object.create(Function.prototype)
|
||||||
|
/* eslint-enable @typescript-eslint/no-unsafe-assignment,
|
||||||
|
@typescript-eslint/no-unsafe-member-access,
|
||||||
|
@typescript-eslint/ban-types */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Escapes characters with special meaning in HTML with the corresponding
|
* Escapes characters with special meaning in HTML with the corresponding
|
||||||
* HTML entities.
|
* HTML entities.
|
||||||
*/
|
*/
|
||||||
export function escapeHTML (str: string): string {
|
export function escapeHTML (str: string): string {
|
||||||
return str.replace(/[&<>]/g, c => (htmlEntities as any)[c])
|
return str.replace(/[&<>]/g, c => htmlEntities[c])
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -204,6 +204,6 @@ export function extractMath (text: string): [string, MathExpression[]] {
|
||||||
*/
|
*/
|
||||||
export function restoreMath (text: string, math: string[]): string {
|
export function restoreMath (text: string, math: string[]): string {
|
||||||
return text
|
return text
|
||||||
.replace(/@@([1-9][0-9]*)@@/g, (_, n) => math[Number(n) - 1])
|
.replace(/@@([1-9][0-9]*)@@/g, (_, n) => math[Number(n) - 1] ?? '')
|
||||||
.replace(/@@0(\d+)@@/g, (_, n) => `@@${n}@@`)
|
.replace(/@@0(\d+)@@/g, (_, n) => `@@${n}@@`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,78 +1,79 @@
|
||||||
// These types are based on https://github.com/jupyter/nbformat/blob/b6b5a18e5a40d37f1cc0f71f65108288bdec9bb7/nbformat/v4/nbformat.v4.schema.json.
|
// These types are based on https://github.com/jupyter/nbformat/blob/b6b5a18e5a40d37f1cc0f71f65108288bdec9bb7/nbformat/v4/nbformat.v4.schema.json.
|
||||||
// This file was originally generated using json-schema-to-typescript 7.0.0 and
|
// This file was originally generated using json-schema-to-typescript 7.0.0 and
|
||||||
// then manually polished.
|
// then manually polished.
|
||||||
|
/* eslint-disable @typescript-eslint/member-ordering */
|
||||||
|
|
||||||
/** Jupyter Notebook v4.3. */
|
/** Jupyter Notebook v4.3. */
|
||||||
export interface Notebook {
|
export interface Notebook {
|
||||||
|
|
||||||
/** Notebook root-level metadata. */
|
/** Notebook root-level metadata. */
|
||||||
metadata: NotebookMetadata,
|
metadata: NotebookMetadata
|
||||||
|
|
||||||
/** Notebook format (minor number). Incremented for backward compatible changes to the notebook format. */
|
/** Notebook format (minor number). Incremented for backward compatible changes to the notebook format. */
|
||||||
nbformat_minor: number,
|
nbformat_minor: number
|
||||||
|
|
||||||
/** Notebook format (major number). Incremented between backwards incompatible changes to the notebook format. */
|
/** Notebook format (major number). Incremented between backwards incompatible changes to the notebook format. */
|
||||||
nbformat: 4,
|
nbformat: 4
|
||||||
|
|
||||||
/** Array of cells of the current notebook. */
|
/** Array of cells of the current notebook. */
|
||||||
cells: Cell[],
|
cells: Cell[]
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notebook root-level metadata. */
|
/** Notebook root-level metadata. */
|
||||||
export interface NotebookMetadata {
|
export interface NotebookMetadata {
|
||||||
|
|
||||||
/** Kernel information. */
|
/** Kernel information. */
|
||||||
kernelspec?: KernelSpec,
|
kernelspec?: KernelSpec
|
||||||
|
|
||||||
/** Kernel information. */
|
/** Kernel information. */
|
||||||
language_info?: LanguageInfo,
|
language_info?: LanguageInfo
|
||||||
|
|
||||||
/** Original notebook format (major number) before converting the notebook between versions. This should never be written to a file. */
|
/** Original notebook format (major number) before converting the notebook between versions. This should never be written to a file. */
|
||||||
orig_nbformat?: number,
|
orig_nbformat?: number
|
||||||
|
|
||||||
/** The title of the notebook document */
|
/** The title of the notebook document */
|
||||||
title?: string,
|
title?: string
|
||||||
|
|
||||||
/** The author(s) of the notebook document */
|
/** The author(s) of the notebook document */
|
||||||
authors?: any[],
|
authors?: any[]
|
||||||
|
|
||||||
/** Extra properties. */
|
/** Extra properties. */
|
||||||
[key: string]: any,
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Kernel information. */
|
/** Kernel information. */
|
||||||
export interface KernelSpec {
|
export interface KernelSpec {
|
||||||
|
|
||||||
/** Name of the kernel specification. */
|
/** Name of the kernel specification. */
|
||||||
name: string,
|
name: string
|
||||||
|
|
||||||
/** Name to display in UI. */
|
/** Name to display in UI. */
|
||||||
display_name: string,
|
display_name: string
|
||||||
|
|
||||||
/** Extra properties. */
|
/** Extra properties. */
|
||||||
[key: string]: any,
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Kernel information. */
|
/** Kernel information. */
|
||||||
export interface LanguageInfo {
|
export interface LanguageInfo {
|
||||||
|
|
||||||
/** The programming language which this kernel runs. */
|
/** The programming language which this kernel runs. */
|
||||||
name: string,
|
name: string
|
||||||
|
|
||||||
/** The codemirror mode to use for code in this language. */
|
/** The codemirror mode to use for code in this language. */
|
||||||
codemirror_mode?: string | { [k: string]: any },
|
codemirror_mode?: string | { [k: string]: any }
|
||||||
|
|
||||||
/** The file extension for files in this language. */
|
/** The file extension for files in this language. */
|
||||||
file_extension?: string,
|
file_extension?: string
|
||||||
|
|
||||||
/** The mimetype corresponding to files in this language. */
|
/** The mimetype corresponding to files in this language. */
|
||||||
mimetype?: string,
|
mimetype?: string
|
||||||
|
|
||||||
/** The pygments lexer to use for code in this language. */
|
/** The pygments lexer to use for code in this language. */
|
||||||
pygments_lexer?: string,
|
pygments_lexer?: string
|
||||||
|
|
||||||
/** Extra properties. */
|
/** Extra properties. */
|
||||||
[key: string]: any,
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,46 +90,46 @@ export enum CellType {
|
||||||
interface BaseCell {
|
interface BaseCell {
|
||||||
|
|
||||||
/** String identifying the type of cell. */
|
/** String identifying the type of cell. */
|
||||||
cell_type: CellType,
|
cell_type: CellType
|
||||||
|
|
||||||
/** Cell-level metadata. */
|
/** Cell-level metadata. */
|
||||||
metadata: CellMetadata,
|
metadata: CellMetadata
|
||||||
|
|
||||||
/** Contents of the cell, represented as an array of lines. */
|
/** Contents of the cell, represented as an array of lines. */
|
||||||
source: MultilineString,
|
source: MultilineString
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notebook raw nbconvert cell. */
|
/** Notebook raw nbconvert cell. */
|
||||||
export interface RawCell extends BaseCell {
|
export interface RawCell extends BaseCell {
|
||||||
|
|
||||||
/** String identifying the type of cell. */
|
/** String identifying the type of cell. */
|
||||||
cell_type: CellType.Raw,
|
cell_type: CellType.Raw
|
||||||
|
|
||||||
/** Cell-level metadata. */
|
/** Cell-level metadata. */
|
||||||
metadata: CellMetadata & {
|
metadata: CellMetadata & {
|
||||||
/** Raw cell metadata format for nbconvert. */
|
/** Raw cell metadata format for nbconvert. */
|
||||||
format?: string,
|
format?: string,
|
||||||
},
|
}
|
||||||
|
|
||||||
/** Media attachments (e.g. inline images), stored as mimebundle keyed by filename. */
|
/** Media attachments (e.g. inline images), stored as mimebundle keyed by filename. */
|
||||||
attachments?: MediaAttachments,
|
attachments?: MediaAttachments
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notebook markdown cell. */
|
/** Notebook markdown cell. */
|
||||||
export interface MarkdownCell extends BaseCell {
|
export interface MarkdownCell extends BaseCell {
|
||||||
|
|
||||||
/** String identifying the type of cell. */
|
/** String identifying the type of cell. */
|
||||||
cell_type: CellType.Markdown,
|
cell_type: CellType.Markdown
|
||||||
|
|
||||||
/** Media attachments (e.g. inline images), stored as mimebundle keyed by filename. */
|
/** Media attachments (e.g. inline images), stored as mimebundle keyed by filename. */
|
||||||
attachments?: MediaAttachments,
|
attachments?: MediaAttachments
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notebook code cell. */
|
/** Notebook code cell. */
|
||||||
export interface CodeCell extends BaseCell {
|
export interface CodeCell extends BaseCell {
|
||||||
|
|
||||||
/** String identifying the type of cell. */
|
/** String identifying the type of cell. */
|
||||||
cell_type: CellType.Code,
|
cell_type: CellType.Code
|
||||||
|
|
||||||
/** Cell-level metadata. */
|
/** Cell-level metadata. */
|
||||||
metadata: CellMetadata & {
|
metadata: CellMetadata & {
|
||||||
|
@ -138,38 +139,38 @@ export interface CodeCell extends BaseCell {
|
||||||
|
|
||||||
/** Whether the cell's output is scrolled, unscrolled, or autoscrolled. */
|
/** Whether the cell's output is scrolled, unscrolled, or autoscrolled. */
|
||||||
scrolled?: true | false | 'auto',
|
scrolled?: true | false | 'auto',
|
||||||
},
|
}
|
||||||
|
|
||||||
/** Execution, display, or stream outputs. */
|
/** Execution, display, or stream outputs. */
|
||||||
outputs: Output[],
|
outputs: Output[]
|
||||||
|
|
||||||
/** The code cell's prompt number. Will be null if the cell has not been run. */
|
/** The code cell's prompt number. Will be null if the cell has not been run. */
|
||||||
execution_count: number | null,
|
execution_count: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CellMetadata {
|
export interface CellMetadata {
|
||||||
|
|
||||||
/** Official Jupyter Metadata for Raw Cells */
|
/** Official Jupyter Metadata for Raw Cells */
|
||||||
jupyter?: { [k: string]: any },
|
jupyter?: { [k: string]: any }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The cell's name. If present, must be a non-empty string. Cell names are expected to be unique
|
* The cell's name. If present, must be a non-empty string. Cell names are expected to be unique
|
||||||
* across all the cells in a given notebook. This criterion cannot be checked by the json schema
|
* across all the cells in a given notebook. This criterion cannot be checked by the json schema
|
||||||
* and must be established by an additional check.
|
* and must be established by an additional check.
|
||||||
*/
|
*/
|
||||||
name?: string,
|
name?: string
|
||||||
|
|
||||||
/** The cell's tags. Tags must be unique, and must not contain commas. */
|
/** The cell's tags. Tags must be unique, and must not contain commas. */
|
||||||
tags?: string[],
|
tags?: string[]
|
||||||
|
|
||||||
/** Extra properties. */
|
/** Extra properties. */
|
||||||
[key: string]: any,
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MediaAttachments {
|
export interface MediaAttachments {
|
||||||
|
|
||||||
/** The attachment's data stored as a mimebundle. */
|
/** The attachment's data stored as a mimebundle. */
|
||||||
[filename: string]: MimeBundle,
|
[filename: string]: MimeBundle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -188,62 +189,62 @@ export enum OutputType {
|
||||||
export interface ExecuteResult {
|
export interface ExecuteResult {
|
||||||
|
|
||||||
/** Type of cell output. */
|
/** Type of cell output. */
|
||||||
output_type: OutputType.ExecuteResult,
|
output_type: OutputType.ExecuteResult
|
||||||
|
|
||||||
/** A result's prompt number. */
|
/** A result's prompt number. */
|
||||||
execution_count: number | null,
|
execution_count: number | null
|
||||||
|
|
||||||
/** A mime-type keyed dictionary of data */
|
/** A mime-type keyed dictionary of data */
|
||||||
data: MimeBundle,
|
data: MimeBundle
|
||||||
|
|
||||||
/** Cell output metadata. */
|
/** Cell output metadata. */
|
||||||
metadata: {
|
metadata: {
|
||||||
[k: string]: any,
|
[k: string]: any,
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Data displayed as a result of code cell execution. */
|
/** Data displayed as a result of code cell execution. */
|
||||||
export interface DisplayData {
|
export interface DisplayData {
|
||||||
|
|
||||||
/** Type of cell output. */
|
/** Type of cell output. */
|
||||||
output_type: OutputType.DisplayData,
|
output_type: OutputType.DisplayData
|
||||||
|
|
||||||
/** A mime-type keyed dictionary of data */
|
/** A mime-type keyed dictionary of data */
|
||||||
data: MimeBundle,
|
data: MimeBundle
|
||||||
|
|
||||||
/** Cell output metadata. */
|
/** Cell output metadata. */
|
||||||
metadata: {
|
metadata: {
|
||||||
[k: string]: any,
|
[k: string]: any,
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Stream output from a code cell. */
|
/** Stream output from a code cell. */
|
||||||
export interface StreamOutput {
|
export interface StreamOutput {
|
||||||
|
|
||||||
/** Type of cell output. */
|
/** Type of cell output. */
|
||||||
output_type: OutputType.Stream,
|
output_type: OutputType.Stream
|
||||||
|
|
||||||
/** The name of the stream (stdout, stderr). */
|
/** The name of the stream (stdout, stderr). */
|
||||||
name: string,
|
name: string
|
||||||
|
|
||||||
/** The stream's text output, represented as an array of strings. */
|
/** The stream's text output, represented as an array of strings. */
|
||||||
text: MultilineString,
|
text: MultilineString
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Output of an error that occurred during code cell execution. */
|
/** Output of an error that occurred during code cell execution. */
|
||||||
export interface ErrorOutput {
|
export interface ErrorOutput {
|
||||||
|
|
||||||
/** Type of cell output. */
|
/** Type of cell output. */
|
||||||
output_type: OutputType.Error,
|
output_type: OutputType.Error
|
||||||
|
|
||||||
/** The name of the error. */
|
/** The name of the error. */
|
||||||
ename: string,
|
ename: string
|
||||||
|
|
||||||
/** The value, or message, of the error. */
|
/** The value, or message, of the error. */
|
||||||
evalue: string,
|
evalue: string
|
||||||
|
|
||||||
/** The error's traceback, represented as an array of strings. */
|
/** The error's traceback, represented as an array of strings. */
|
||||||
traceback: string[],
|
traceback: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,7 +253,7 @@ export interface ErrorOutput {
|
||||||
export interface MimeBundle {
|
export interface MimeBundle {
|
||||||
|
|
||||||
/** mimetype output (e.g. text/plain), represented as either an array of strings or a string. */
|
/** mimetype output (e.g. text/plain), represented as either an array of strings or a string. */
|
||||||
[mediaType: string]: MultilineString,
|
[mediaType: string]: MultilineString
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MultilineString = string | string[]
|
export type MultilineString = string | string[]
|
||||||
|
|
|
@ -147,6 +147,7 @@ class NbRenderer <TElement> extends CallableInstance<NbRenderer<TElement>> {
|
||||||
__call__ (notebook: Notebook): TElement {
|
__call__ (notebook: Notebook): TElement {
|
||||||
return this.render(notebook)
|
return this.render(notebook)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the given Jupyter *notebook*.
|
* Renders the given Jupyter *notebook*.
|
||||||
*/
|
*/
|
||||||
|
@ -165,11 +166,11 @@ class NbRenderer <TElement> extends CallableInstance<NbRenderer<TElement>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderMarkdownCell (cell: MarkdownCell, _notebook: Notebook): TElement {
|
renderMarkdownCell (cell: MarkdownCell, _notebook: Notebook): TElement {
|
||||||
return this.el('div', ['cell', 'markdown-cell'], this.renderMarkdown(joinText(cell.source)))
|
return this.el('section', ['cell', 'markdown-cell'], this.renderMarkdown(joinText(cell.source)))
|
||||||
}
|
}
|
||||||
|
|
||||||
renderRawCell (cell: RawCell, _notebook: Notebook): TElement {
|
renderRawCell (cell: RawCell, _notebook: Notebook): TElement {
|
||||||
return this.el('div', ['cell', 'raw-cell'], joinText(cell.source))
|
return this.el('section', ['cell', 'raw-cell'], joinText(cell.source))
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCodeCell (cell: CodeCell, notebook: Notebook): TElement {
|
renderCodeCell (cell: CodeCell, notebook: Notebook): TElement {
|
||||||
|
@ -180,7 +181,7 @@ class NbRenderer <TElement> extends CallableInstance<NbRenderer<TElement>> {
|
||||||
const outputs = coalesceStreams(cell.outputs ?? [])
|
const outputs = coalesceStreams(cell.outputs ?? [])
|
||||||
.map(output => this.renderOutput(output, cell))
|
.map(output => this.renderOutput(output, cell))
|
||||||
|
|
||||||
return this.el('div', ['cell', 'code-cell'], [source, ...outputs])
|
return this.el('section', ['cell', 'code-cell'], [source, ...outputs])
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSource (cell: CodeCell, notebook: Notebook): TElement {
|
renderSource (cell: CodeCell, notebook: Notebook): TElement {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { $INLINE_JSON } from 'ts-transformer-inline-file'
|
import { $INLINE_JSON } from 'ts-transformer-inline-file'
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
const { version } = $INLINE_JSON('../package.json')
|
const { version } = $INLINE_JSON('../package.json')
|
||||||
|
|
||||||
export default version as string
|
export default version as string
|
||||||
|
|
|
@ -102,11 +102,11 @@ describe('built renderer', () => {
|
||||||
eachMultilineVariant(fixtures.MarkdownCell, 'source', (cell) => {
|
eachMultilineVariant(fixtures.MarkdownCell, 'source', (cell) => {
|
||||||
const source = join(cell.source)
|
const source = join(cell.source)
|
||||||
|
|
||||||
it('returns div.cell.markdown-cell with the $source converted using markdownRenderer() as content', () => {
|
it('returns section.cell.markdown-cell with the $source converted using markdownRenderer() as content', () => {
|
||||||
expect( renderer.renderMarkdownCell(cell, notebook) ).toHtmlEqual(
|
expect( renderer.renderMarkdownCell(cell, notebook) ).toHtmlEqual(
|
||||||
<div class="cell markdown-cell">
|
<section class="cell markdown-cell">
|
||||||
{{__html: mockLastResult(markdownRenderer) }}
|
{{__html: mockLastResult(markdownRenderer) }}
|
||||||
</div>
|
</section>
|
||||||
)
|
)
|
||||||
expect( markdownRenderer ).toBeCalledWith(source)
|
expect( markdownRenderer ).toBeCalledWith(source)
|
||||||
})
|
})
|
||||||
|
@ -117,11 +117,11 @@ describe('built renderer', () => {
|
||||||
describe('.renderRawCell', () => {
|
describe('.renderRawCell', () => {
|
||||||
eachMultilineVariant(fixtures.RawCell, 'source', (cell) => {
|
eachMultilineVariant(fixtures.RawCell, 'source', (cell) => {
|
||||||
|
|
||||||
it('returns div.cell.raw-cell with the $source as content', () => {
|
it('returns section.cell.raw-cell with the $source as content', () => {
|
||||||
expect( renderer.renderRawCell(cell, notebook) ).toHtmlEqual(
|
expect( renderer.renderRawCell(cell, notebook) ).toHtmlEqual(
|
||||||
<div class="cell raw-cell">
|
<section class="cell raw-cell">
|
||||||
{{__html: join(cell.source) }}
|
{{__html: join(cell.source) }}
|
||||||
</div>
|
</section>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -139,9 +139,9 @@ describe('built renderer', () => {
|
||||||
result = renderer.renderCodeCell(cell, notebook)
|
result = renderer.renderCodeCell(cell, notebook)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns div.cell.code-cell', () => {
|
it('returns section.cell.code-cell', () => {
|
||||||
expect( result ).toMatchElement(
|
expect( result ).toMatchElement(
|
||||||
<div class="cell code-cell"><Anything /></div>
|
<section class="cell code-cell"><Anything /></section>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ describe('built renderer', () => {
|
||||||
|
|
||||||
it('returns element with $source rendered using .renderSource() as children[0]', () => {
|
it('returns element with $source rendered using .renderSource() as children[0]', () => {
|
||||||
expect( renderer.renderSource ).toBeCalledWith(cell, notebook)
|
expect( renderer.renderSource ).toBeCalledWith(cell, notebook)
|
||||||
expect( result.children[0] ).toHtmlEqual(mockLastResult(renderer.renderSource))
|
expect( result.children[0] ).toHtmlEqual(mockLastResult(renderer.renderSource)!)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ describe('built renderer', () => {
|
||||||
|
|
||||||
it(`returns element with the output rendered using .${funcName}() as the only child`, () => {
|
it(`returns element with the output rendered using .${funcName}() as the only child`, () => {
|
||||||
expect( renderer[funcName] ).toBeCalledWith(output)
|
expect( renderer[funcName] ).toBeCalledWith(output)
|
||||||
expect( result.children ).toHtmlEqual([mockLastResult(renderer[funcName])])
|
expect( result.children ).toHtmlEqual([mockLastResult(renderer[funcName])!])
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('when the cell has non-null execution_count', () => {
|
describe('when the cell has non-null execution_count', () => {
|
||||||
|
@ -437,7 +437,7 @@ describe('built renderer', () => {
|
||||||
|
|
||||||
it('renders the data using the associated external renderer', () => {
|
it('renders the data using the associated external renderer', () => {
|
||||||
expect( renderer.renderDisplayData(output) ).toHtmlEqual(
|
expect( renderer.renderDisplayData(output) ).toHtmlEqual(
|
||||||
mockLastResult(dataRenderers['text/custom'])
|
mockLastResult(dataRenderers['text/custom'])!
|
||||||
)
|
)
|
||||||
expect( dataRenderers['text/custom'] ).toBeCalledWith(join(data))
|
expect( dataRenderers['text/custom'] ).toBeCalledWith(join(data))
|
||||||
})
|
})
|
||||||
|
@ -468,7 +468,7 @@ describe('built renderer', () => {
|
||||||
const output = displayDataWith(mimeBundle)
|
const output = displayDataWith(mimeBundle)
|
||||||
|
|
||||||
expect( renderer.renderDisplayData(output) ).toHtmlEqual(
|
expect( renderer.renderDisplayData(output) ).toHtmlEqual(
|
||||||
mockLastResult(dataRenderers['text/custom'])
|
mockLastResult(dataRenderers['text/custom'])!
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
// This file is needed only for VSCode, see https://github.com/palmerhq/tsdx/issues/84.
|
|
||||||
{
|
{
|
||||||
"extends": "../tsconfig.json",
|
"extends": "../../../tsconfig.test.json",
|
||||||
"include": ["."],
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
},
|
||||||
|
"references": [
|
||||||
|
{ "path": "../" },
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,6 @@
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"tsBuildInfoFile": "./.tsbuildinfo",
|
"tsBuildInfoFile": "./.tsbuildinfo",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
|
||||||
"*": ["../../types/*"],
|
|
||||||
"@/*": ["./src/*"],
|
|
||||||
"~/*": ["../../*"],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./src",
|
"./src",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ipynb2html",
|
"name": "ipynb2html",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"description": "Convert Jupyter Notebook to static HTML",
|
"description": "Convert Jupyter Notebook to static HTML",
|
||||||
"author": "Jakub Jirutka <jakub@jirutka.cz>",
|
"author": "Jakub Jirutka <jakub@jirutka.cz>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@ -31,8 +31,8 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "ttsc --build",
|
"build": "ttsc --build",
|
||||||
"bundle": "rollup -c",
|
"bundle": "rollup -c",
|
||||||
"clean": "rimraf coverage/ dist/ lib/ .tsbuildinfo",
|
"clean": "rimraf coverage/ dist/ lib/ .eslintcache .tsbuildinfo",
|
||||||
"lint": "eslint --ext .ts,.tsx,.js .",
|
"lint": "PKGDIR=$PWD; cd ../../ && eslint --cache --ext .ts,.tsx,.js $PKGDIR",
|
||||||
"minify-css": "csso styles/notebook.css -o dist/notebook.min.css -s dist/notebook.min.css.map",
|
"minify-css": "csso styles/notebook.css -o dist/notebook.min.css -s dist/notebook.min.css.map",
|
||||||
"prepublishOnly": "run-p bundle minify-css readme2md",
|
"prepublishOnly": "run-p bundle minify-css readme2md",
|
||||||
"test": "jest --detectOpenHandles --coverage --verbose",
|
"test": "jest --detectOpenHandles --coverage --verbose",
|
||||||
|
@ -44,10 +44,15 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"anser": "^1.4.9",
|
"anser": "^1.4.9",
|
||||||
"highlightjs": "^9.16.2",
|
"highlight.js": "^10.7.3",
|
||||||
"ipynb2html-core": "0.1.0",
|
"ipynb2html-core": "0.3.0",
|
||||||
"katex": "^0.11.1",
|
"katex": "^0.13.11",
|
||||||
"marked": "^0.8.0"
|
"marked": "^2.0.7"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/katex": "^0.11.0",
|
||||||
|
"@types/marked": "^2.0.3",
|
||||||
|
"ansi_up": "^5.0.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"nodom": "^2.3.0"
|
"nodom": "^2.3.0"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import addGitMsg from 'rollup-plugin-add-git-msg'
|
import addGitMsg from 'rollup-plugin-add-git-msg'
|
||||||
import babel from 'rollup-plugin-babel'
|
import babel from '@rollup/plugin-babel'
|
||||||
import commonjs from '@rollup/plugin-commonjs'
|
import commonjs from '@rollup/plugin-commonjs'
|
||||||
import license from 'rollup-plugin-node-license'
|
import license from 'rollup-plugin-node-license'
|
||||||
import resolve from '@rollup/plugin-node-resolve'
|
import resolve from '@rollup/plugin-node-resolve'
|
||||||
|
@ -13,10 +13,10 @@ import pkg from './package.json'
|
||||||
const extensions = ['.mjs', '.js', '.ts']
|
const extensions = ['.mjs', '.js', '.ts']
|
||||||
|
|
||||||
const globals = {
|
const globals = {
|
||||||
anser: 'anser',
|
'anser': 'anser',
|
||||||
highlightjs: 'hljs',
|
'highlight.js': 'hljs',
|
||||||
katex: 'katex',
|
'katex': 'katex',
|
||||||
marked: 'marked',
|
'marked': 'marked',
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugins = [
|
const plugins = [
|
||||||
|
@ -33,9 +33,6 @@ const plugins = [
|
||||||
incremental: true,
|
incremental: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// This is needed for node-license plugin. :(
|
|
||||||
// https://github.com/ezolenko/rollup-plugin-typescript2#plugins-using-asyncawait
|
|
||||||
objectHashIgnoreUnknownHack: true,
|
|
||||||
clean: true,
|
clean: true,
|
||||||
}),
|
}),
|
||||||
// Resolve node modules.
|
// Resolve node modules.
|
||||||
|
@ -48,6 +45,7 @@ const plugins = [
|
||||||
// Transpile all sources for older browsers and inject needed polyfills.
|
// Transpile all sources for older browsers and inject needed polyfills.
|
||||||
babel({
|
babel({
|
||||||
babelrc: false,
|
babelrc: false,
|
||||||
|
babelHelpers: 'bundled',
|
||||||
// To avoid Babel injecting core-js polyfills into core-js.
|
// To avoid Babel injecting core-js polyfills into core-js.
|
||||||
exclude: [/node_modules\/core-js\//],
|
exclude: [/node_modules\/core-js\//],
|
||||||
extensions,
|
extensions,
|
||||||
|
@ -72,22 +70,23 @@ const plugins = [
|
||||||
}),
|
}),
|
||||||
// Generate table of the bundled packages at top of the file.
|
// Generate table of the bundled packages at top of the file.
|
||||||
license({ format: 'table' }),
|
license({ format: 'table' }),
|
||||||
// Minify JS.
|
]
|
||||||
terser({
|
|
||||||
|
const output = (filename, extra = {}) => [false, true].map(minify => ({
|
||||||
|
name: pkg.name,
|
||||||
|
file: `${filename}${minify ? '.min.js' : '.js'}`,
|
||||||
|
format: 'umd',
|
||||||
|
sourcemap: true,
|
||||||
|
plugins: [
|
||||||
|
// Minify JS when building .min.js file.
|
||||||
|
minify && terser({
|
||||||
ecma: 5,
|
ecma: 5,
|
||||||
include: [/^.+\.min\.js$/],
|
|
||||||
output: {
|
output: {
|
||||||
// Preserve comment injected by addGitMsg and license.
|
// Preserve comment injected by addGitMsg and license.
|
||||||
comments: RegExp(`(?:\\$\\{${pkg.name}\\}|Bundled npm packages)`),
|
comments: RegExp(`(?:\\$\\{${pkg.name}\\}|Bundled npm packages)`),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]
|
].filter(Boolean),
|
||||||
|
|
||||||
const output = (filename, extra = {}) => ['.js', '.min.js'].map(ext => ({
|
|
||||||
name: pkg.name,
|
|
||||||
file: `${filename}${ext}`,
|
|
||||||
format: 'umd',
|
|
||||||
sourcemap: true,
|
|
||||||
...extra,
|
...extra,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ export function autoRender (opts: NbRendererOpts = {}): void {
|
||||||
|
|
||||||
document.querySelectorAll(selector).forEach(script => {
|
document.querySelectorAll(selector).forEach(script => {
|
||||||
if (script.textContent && script.parentElement) {
|
if (script.textContent && script.parentElement) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
const notebook = JSON.parse(unescapeHTML(script.textContent))
|
const notebook = JSON.parse(unescapeHTML(script.textContent))
|
||||||
const nbElement = render(notebook)
|
const nbElement = render(notebook)
|
||||||
script.parentElement.replaceChild(nbElement, script)
|
script.parentElement.replaceChild(nbElement, script)
|
||||||
|
|
1
packages/ipynb2html/src/global.d.ts
vendored
1
packages/ipynb2html/src/global.d.ts
vendored
|
@ -2,6 +2,5 @@
|
||||||
// via global variable. It's an alternative to Anser that doesn't provide
|
// via global variable. It's an alternative to Anser that doesn't provide
|
||||||
// bundle for browsers.
|
// bundle for browsers.
|
||||||
declare class AnsiUp {
|
declare class AnsiUp {
|
||||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
||||||
ansi_to_html (input: string): string
|
ansi_to_html (input: string): string
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import anser from 'anser'
|
import anser from 'anser'
|
||||||
import hljs from 'highlightjs'
|
import hljs from 'highlight.js'
|
||||||
import katex, { KatexOptions } from 'katex'
|
import katex, { KatexOptions } from 'katex'
|
||||||
import marked, { MarkedOptions } from 'marked'
|
import marked from 'marked'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createElementCreator,
|
createElementCreator,
|
||||||
|
@ -12,7 +12,7 @@ import {
|
||||||
Notebook,
|
Notebook,
|
||||||
} from 'ipynb2html-core'
|
} from 'ipynb2html-core'
|
||||||
|
|
||||||
import buildMarkdownRenderer from './markdownRenderer'
|
import buildMarkdownRenderer, { MarkedOptions } from './markdownRenderer'
|
||||||
|
|
||||||
|
|
||||||
export { default as version } from './version'
|
export { default as version } from './version'
|
||||||
|
@ -42,7 +42,7 @@ export type NbRendererOpts<TElement = HTMLElement> = BaseOptions<TElement> & {
|
||||||
* for this module's function.
|
* for this module's function.
|
||||||
*/
|
*/
|
||||||
type MinimalDocument<TElement extends MinimalElement> = {
|
type MinimalDocument<TElement extends MinimalElement> = {
|
||||||
createElement (tag: string): TElement,
|
createElement: (tag: string) => TElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultKatexOpts: KatexOptions = {
|
const defaultKatexOpts: KatexOptions = {
|
||||||
|
@ -50,9 +50,14 @@ const defaultKatexOpts: KatexOptions = {
|
||||||
throwOnError: false,
|
throwOnError: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultMarkedOpts: MarkedOptions = {
|
||||||
|
headerAnchors: true,
|
||||||
|
headerIdsStripAccents: true,
|
||||||
|
}
|
||||||
|
|
||||||
function hljsCodeHighlighter (code: string, lang: string): string {
|
function hljsCodeHighlighter (code: string, lang: string): string {
|
||||||
return hljs.getLanguage(lang)
|
return hljs.getLanguage(lang)
|
||||||
? hljs.highlight(lang, code).value
|
? hljs.highlight(code, { language: lang }).value
|
||||||
: code
|
: code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,11 +120,8 @@ export function createRenderer <TElement extends MinimalElement> (
|
||||||
codeHighlighter = hljsCodeHighlighter
|
codeHighlighter = hljsCodeHighlighter
|
||||||
}
|
}
|
||||||
if (!markdownRenderer && marked) {
|
if (!markdownRenderer && marked) {
|
||||||
if (katex) {
|
const markedOpts = { ...defaultMarkedOpts, ...opts.markedOpts }
|
||||||
markdownRenderer = buildMarkdownRenderer(opts.markedOpts, katexOpts)
|
markdownRenderer = buildMarkdownRenderer(markedOpts, katexOpts)
|
||||||
} else {
|
|
||||||
markdownRenderer = (text) => marked.parse(text, opts.markedOpts)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!dataRenderers['text/html'] && katex) {
|
if (!dataRenderers['text/html'] && katex) {
|
||||||
const mathRenderer = (tex: string) => katex.renderToString(tex, katexOpts)
|
const mathRenderer = (tex: string) => katex.renderToString(tex, katexOpts)
|
||||||
|
|
|
@ -1,32 +1,62 @@
|
||||||
import hljs from 'highlightjs'
|
import hljs from 'highlight.js'
|
||||||
import katex, { KatexOptions } from 'katex'
|
import katex, { KatexOptions } from 'katex'
|
||||||
import marked, { MarkedOptions } from 'marked'
|
import marked, { Slugger } from 'marked'
|
||||||
|
|
||||||
import { mathExtractor } from 'ipynb2html-core'
|
import { mathExtractor } from 'ipynb2html-core'
|
||||||
|
|
||||||
|
|
||||||
|
export type MarkdownRenderer = (markdown: string) => string
|
||||||
|
|
||||||
|
export interface MarkedOptions extends marked.MarkedOptions {
|
||||||
|
/** Generate heading anchors (this implies headingIds). */
|
||||||
|
headerAnchors?: boolean
|
||||||
|
headerIdsStripAccents?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes accents from the given string.
|
||||||
|
const stripAccents = (text: string) => text.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
|
||||||
|
|
||||||
|
// Removes math markers from the given string.
|
||||||
|
const stripMath = (text: string) => mathExtractor.restoreMath(text, []).trim()
|
||||||
|
|
||||||
|
class Renderer extends marked.Renderer {
|
||||||
|
|
||||||
|
heading (text: string, level: 1 | 2 | 3 | 4 | 5 | 6, raw: string, slugger: Slugger): string {
|
||||||
|
const opts = this.options as MarkedOptions
|
||||||
|
|
||||||
|
if (!opts.headerIds && !opts.headerAnchors) {
|
||||||
|
return super.heading(text, level, raw, slugger)
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = (opts.headerPrefix ?? '') + slugger.slug(stripMath(raw))
|
||||||
|
if (opts.headerIdsStripAccents) {
|
||||||
|
id = stripAccents(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.headerAnchors) {
|
||||||
|
text = `<a class="anchor" href="#${id}" aria-hidden="true"></a>${text}`
|
||||||
|
}
|
||||||
|
return `<h${level} id="${id}">${text}</h${level}>`
|
||||||
|
}
|
||||||
|
|
||||||
|
link (href: string | null, title: string | null, text: string): string {
|
||||||
|
return super.link(href && stripMath(href), title && stripMath(title), text)
|
||||||
|
}
|
||||||
|
|
||||||
|
image (href: string | null, title: string | null, text: string): string {
|
||||||
|
return super.image(href && stripMath(href), title && stripMath(title), stripMath(text))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function highlight (code: string, lang: string): string {
|
function highlight (code: string, lang: string): string {
|
||||||
return hljs.getLanguage(lang)
|
return hljs.getLanguage(lang)
|
||||||
? hljs.highlight(lang, code, true).value
|
? hljs.highlight(code, { language: lang, ignoreIllegals: true }).value
|
||||||
: code
|
: code
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
const renderer = (markedOpts: MarkedOptions) => (markdown: string) => marked.parse(markdown, markedOpts)
|
||||||
* Returns a pre-configured marked parser with math support (using KaTeX)
|
|
||||||
* and code highlighter (highlight.js).
|
|
||||||
*
|
|
||||||
* @param {MarkedOptions} markedOpts Options for the marked Markdown renderer.
|
|
||||||
* @param {KatexOptions} katexOpts Options for the KaTeX math renderer.
|
|
||||||
*/
|
|
||||||
export default (markedOpts: MarkedOptions = {}, katexOpts: KatexOptions = {}) => {
|
|
||||||
if (hljs) { // highlightjs may be an optional dependency (in browser bundle)
|
|
||||||
markedOpts = { highlight, ...markedOpts }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
const rendererWithMath = (markedOpts: MarkedOptions, katexOpts: KatexOptions) => (markdown: string) => {
|
||||||
* Converts the given *markdown* into HTML.
|
|
||||||
*/
|
|
||||||
return (markdown: string): string => {
|
|
||||||
const [text, math] = mathExtractor.extractMath(markdown)
|
const [text, math] = mathExtractor.extractMath(markdown)
|
||||||
const html = marked.parse(text, markedOpts)
|
const html = marked.parse(text, markedOpts)
|
||||||
|
|
||||||
|
@ -34,5 +64,23 @@ export default (markedOpts: MarkedOptions = {}, katexOpts: KatexOptions = {}) =>
|
||||||
return katex.renderToString(value, { ...katexOpts, displayMode })
|
return katex.renderToString(value, { ...katexOpts, displayMode })
|
||||||
})
|
})
|
||||||
return mathExtractor.restoreMath(html, mathHtml)
|
return mathExtractor.restoreMath(html, mathHtml)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pre-configured marked parser with (optional) math support (using
|
||||||
|
* KaTeX) and code highlighter (highlight.js).
|
||||||
|
*
|
||||||
|
* @param {MarkedOptions} markedOpts Options for the marked Markdown renderer.
|
||||||
|
* @param {KatexOptions} katexOpts Options for the KaTeX math renderer.
|
||||||
|
*/
|
||||||
|
export default (markedOpts: MarkedOptions = {}, katexOpts: KatexOptions = {}): MarkdownRenderer => {
|
||||||
|
|
||||||
|
markedOpts = { renderer: new Renderer(markedOpts), ...markedOpts }
|
||||||
|
if (hljs) { // highlight.js may be an optional dependency (in browser bundle)
|
||||||
|
markedOpts = { highlight, ...markedOpts }
|
||||||
|
}
|
||||||
|
|
||||||
|
return katex // katex may be an optional dependency (in browser bundle)
|
||||||
|
? rendererWithMath(markedOpts, katexOpts)
|
||||||
|
: renderer(markedOpts)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,14 @@ class EmptyRenderer extends marked.Renderer {}
|
||||||
|
|
||||||
// Override all the EmptyRenderer's methods inherited from marked.Renderer to
|
// Override all the EmptyRenderer's methods inherited from marked.Renderer to
|
||||||
// always return an empty string.
|
// always return an empty string.
|
||||||
const RendererProto: any = marked.Renderer.prototype
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
|
const RendererProto = marked.Renderer.prototype
|
||||||
for (const prop of Object.getOwnPropertyNames(RendererProto)) {
|
for (const prop of Object.getOwnPropertyNames(RendererProto)) {
|
||||||
if (prop !== 'constructor' && typeof RendererProto[prop] === 'function') {
|
if (prop !== 'constructor' && typeof (RendererProto as any)[prop] === 'function') {
|
||||||
;(EmptyRenderer.prototype as any)[prop] = () => ''
|
(EmptyRenderer.prototype as any)[prop] = () => ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
|
||||||
|
|
||||||
class MainTitleRenderer extends EmptyRenderer {
|
class MainTitleRenderer extends EmptyRenderer {
|
||||||
_titleFound = false
|
_titleFound = false
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { $INLINE_JSON } from 'ts-transformer-inline-file'
|
import { $INLINE_JSON } from 'ts-transformer-inline-file'
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
const { version } = $INLINE_JSON('../package.json')
|
const { version } = $INLINE_JSON('../package.json')
|
||||||
|
|
||||||
export default version as string
|
export default version as string
|
||||||
|
|
1
packages/ipynb2html/test/global.d.ts
vendored
Symbolic link
1
packages/ipynb2html/test/global.d.ts
vendored
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../src/global.d.ts
|
152
packages/ipynb2html/test/markdownRenderer.test.tsx
Normal file
152
packages/ipynb2html/test/markdownRenderer.test.tsx
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
import { KatexOptions } from 'katex'
|
||||||
|
import parseHtml from 'node-html-parser'
|
||||||
|
|
||||||
|
import markdownRenderer, { MarkedOptions } from '@/markdownRenderer'
|
||||||
|
|
||||||
|
import '~/test/setup' // setupFilesAfterEnv doesn't work here
|
||||||
|
import { Anything } from '~/test/support/matchers/toMatchElement'
|
||||||
|
|
||||||
|
|
||||||
|
let katexOpts: KatexOptions
|
||||||
|
let markedOpts: MarkedOptions
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
katexOpts = {
|
||||||
|
displayMode: true,
|
||||||
|
throwOnError: false,
|
||||||
|
}
|
||||||
|
markedOpts = {}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
describe('headings', () => {
|
||||||
|
|
||||||
|
it('renders h tag without anchor', () => {
|
||||||
|
expect( render('## Some Title') ).toHtmlEqual(
|
||||||
|
<h2 id="some-title">Some Title</h2>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders math in text, but strips it in id', () => {
|
||||||
|
expect( render('## Integers $\\mathbb{Z}$') ).toMatchElement(
|
||||||
|
<h2 id="integers">
|
||||||
|
Integers <span class="katex"><Anything /></span>
|
||||||
|
</h2>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when headerAnchors is true', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
markedOpts = { headerAnchors: true }
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders h tag with anchor', () => {
|
||||||
|
expect( render('## Some Title') ).toHtmlEqual(
|
||||||
|
<h2 id="some-title">
|
||||||
|
<a class="anchor" href="#some-title" aria-hidden="true"></a>Some Title
|
||||||
|
</h2>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders math in text, but strips it in href and id', () => {
|
||||||
|
expect( render('## Integers $\\mathbb{Z}$') ).toMatchElement(
|
||||||
|
<h2 id="integers">
|
||||||
|
<a class="anchor" href="#integers" aria-hidden="true"></a>
|
||||||
|
Integers <span class="katex"><Anything /></span>
|
||||||
|
</h2>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when headerIds is false', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
markedOpts = { headerIds: false }
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders h tag without id and anchor', () => {
|
||||||
|
expect( render('## Some Title') ).toHtmlEqual(
|
||||||
|
<h2>Some Title</h2>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when headerIdsStripAccents is true', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
markedOpts = { headerIdsStripAccents: true }
|
||||||
|
})
|
||||||
|
|
||||||
|
it('strips accents in generated id', () => {
|
||||||
|
expect( render('## Příliš žluťoučký kůň') ).toHtmlEqual(
|
||||||
|
<h2 id="prilis-zlutoucky-kun">
|
||||||
|
Příliš žluťoučký kůň
|
||||||
|
</h2>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
describe('link', () => {
|
||||||
|
|
||||||
|
it('strips math in title', () => {
|
||||||
|
expect( render('[link](https://example.org "This is $\\TeX$!")') ).toHtmlEqual(
|
||||||
|
<p><a href="https://example.org" title="This is !">link</a></p>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('strips math in href', () => {
|
||||||
|
expect( render('[link](https://example.org/$\\TeX$)') ).toHtmlEqual(
|
||||||
|
<p><a href="https://example.org/">link</a></p>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders math in text', () => {
|
||||||
|
expect( render('[This is $\\TeX$!](https://example.org/)') ).toMatchElement(
|
||||||
|
<p><a href="https://example.org/">This is <span class="katex"><Anything /></span>!</a></p>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
describe('image', () => {
|
||||||
|
|
||||||
|
it('strips math in title', () => {
|
||||||
|
expect( render('') ).toHtmlEqual(
|
||||||
|
<p><img src="https://example.org/img.png" alt="x" title="This is !" /></p>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('strips math in href', () => {
|
||||||
|
expect( render('') ).toHtmlEqual(
|
||||||
|
<p><img src="https://example.org/.png" alt="image" /></p>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('strips math in alt text', () => {
|
||||||
|
expect( render('') ).toHtmlEqual(
|
||||||
|
<p><img src="https://example.org/img.png" alt="This is !" /></p>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
describe('code', () => {
|
||||||
|
|
||||||
|
it('highlights fenced code block', () => {
|
||||||
|
// Note: We use `backticks` in this example to avoid problem that JSX
|
||||||
|
// implicitly decodes HTML entities, but node-html-parser does not.
|
||||||
|
expect( render('```js\nconsole.log(`Hello, world!`)\n```') ).toHtmlEqual(
|
||||||
|
<pre>
|
||||||
|
<code class="language-js">
|
||||||
|
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, world!`</span>)
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
function render (text: string) {
|
||||||
|
const html = markdownRenderer(markedOpts, katexOpts)(text).replace(/\n/, '')
|
||||||
|
return parseHtml(html, { pre: true }).childNodes[0]
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import readNotebookTitle from '@/readNotebookTitle'
|
|
||||||
|
|
||||||
import { Notebook, CellType, MarkdownCell } from 'ipynb2html-core'
|
import { Notebook, CellType, MarkdownCell } from 'ipynb2html-core'
|
||||||
|
|
||||||
|
import readNotebookTitle from '@/readNotebookTitle'
|
||||||
|
|
||||||
|
|
||||||
const markdownCell = (source: string | string[]): MarkdownCell => ({
|
const markdownCell = (source: string | string[]): MarkdownCell => ({
|
||||||
cell_type: CellType.Markdown,
|
cell_type: CellType.Markdown,
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
// This file is needed only for VSCode, see https://github.com/palmerhq/tsdx/issues/84.
|
|
||||||
{
|
{
|
||||||
"extends": "../tsconfig.json",
|
"extends": "../../../tsconfig.test.json",
|
||||||
"include": ["."],
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
},
|
||||||
|
"references": [
|
||||||
|
{ "path": "../" },
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,6 @@
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"tsBuildInfoFile": "./.tsbuildinfo",
|
"tsBuildInfoFile": "./.tsbuildinfo",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
|
||||||
"*": ["../../types/*"],
|
|
||||||
"@/*": ["./src/*"],
|
|
||||||
"~/*": ["../../*"],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./src",
|
"./src",
|
||||||
|
|
15
patches/yarn-version-bump+0.0.3.patch
Normal file
15
patches/yarn-version-bump+0.0.3.patch
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
TODO: Remove after https://github.com/chrisdarroch/yarn-bump/pull/1 is merged and released.
|
||||||
|
|
||||||
|
diff --git a/node_modules/yarn-version-bump/src/workspace.js b/node_modules/yarn-version-bump/src/workspace.js
|
||||||
|
index 28b1dd1..0cf2ecb 100644
|
||||||
|
--- a/node_modules/yarn-version-bump/src/workspace.js
|
||||||
|
+++ b/node_modules/yarn-version-bump/src/workspace.js
|
||||||
|
@@ -9,7 +9,7 @@ class Workspace {
|
||||||
|
|
||||||
|
get workspaceSnapshot() {
|
||||||
|
return runCommand('yarn',
|
||||||
|
- ['workspaces', 'info', '--silent'],
|
||||||
|
+ ['--silent', 'workspaces', 'info'],
|
||||||
|
{ cwd: this.root }
|
||||||
|
)
|
||||||
|
.then(data => JSON.parse(data))
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
( set -o pipefail 2>/dev/null ) && set -o pipefail
|
( set -o pipefail 2>/dev/null ) && set -o pipefail
|
||||||
|
|
||||||
asciidoctor -o - -b docbook "$@" | pandoc -f docbook -t markdown_github -o -
|
asciidoctor -o - -b docbook "$@" | pandoc -f docbook -t markdown_github --base-header-level 2 -o -
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
type Callable = (...args: any[]) => any
|
type Callable = (...args: any[]) => unknown
|
||||||
|
|
||||||
export type Mock<F extends Callable> = jest.Mock<ReturnType<F>, Parameters<F>>
|
export type Mock<F extends Callable> = jest.Mock<ReturnType<F>, Parameters<F>>
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@ export function asMock <F extends Callable> (fn: F): Mock<F> {
|
||||||
export function mockResults <F extends Callable> (fn: F): Array<ReturnType<F>> {
|
export function mockResults <F extends Callable> (fn: F): Array<ReturnType<F>> {
|
||||||
return asMock(fn).mock.results
|
return asMock(fn).mock.results
|
||||||
.filter(x => x.type === 'return')
|
.filter(x => x.type === 'return')
|
||||||
.map(x => x.value)
|
.map(x => x.value as ReturnType<F>)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mockLastResult <F extends Callable> (fn: F): ReturnType<F> {
|
export function mockLastResult <F extends Callable> (fn: F): ReturnType<F> | undefined {
|
||||||
return mockResults(fn).pop() as ReturnType<F>
|
return mockResults(fn).pop()
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,8 @@ export function createElement (
|
||||||
} else if (child instanceof NNode) {
|
} else if (child instanceof NNode) {
|
||||||
el.appendChild(child)
|
el.appendChild(child)
|
||||||
} else if (typeof child === 'object' && '__html' in child) {
|
} else if (typeof child === 'object' && '__html' in child) {
|
||||||
el.innerHTML = child.__html
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||||
|
el.innerHTML = child.__html as string
|
||||||
} else {
|
} else {
|
||||||
el.appendChild(document.createTextNode(String(child)))
|
el.appendChild(document.createTextNode(String(child)))
|
||||||
}
|
}
|
||||||
|
@ -68,6 +69,7 @@ export function createElement (
|
||||||
return el
|
return el
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||||
(global as any).JSX = {
|
(global as any).JSX = {
|
||||||
createElement,
|
createElement,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ declare global {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
namespace jest {
|
namespace jest {
|
||||||
interface Matchers<R, T> {
|
interface Matchers<R, T> {
|
||||||
toHtmlEqual (expected: HTMLElement | string | Array<HTMLElement | string>): R,
|
toHtmlEqual: (expected: HTMLElement | string | Array<HTMLElement | string>) => R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,32 +11,40 @@ declare global {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
namespace jest {
|
namespace jest {
|
||||||
interface Matchers<R, T> {
|
interface Matchers<R, T> {
|
||||||
toMatchElement (expected: HTMLElement, opts?: Options): R,
|
toMatchElement: (expected: HTMLElement, opts?: Options) => R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AnythingNode = new class extends Node {
|
export const AnythingNode = new class extends Node {
|
||||||
render () { return '<!--Anything-->' }
|
render () { return '<!--Anything-->' }
|
||||||
|
toString () { return this.render() }
|
||||||
}()
|
}()
|
||||||
|
|
||||||
export const Anything = () => AnythingNode
|
export const Anything = (): Node => AnythingNode
|
||||||
|
|
||||||
|
function isWritable (obj: any, prop: string): boolean {
|
||||||
|
const desc = Object.getOwnPropertyDescriptor(obj, prop)
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
return !!desc?.writable || !!desc?.set
|
||||||
|
}
|
||||||
|
|
||||||
function filterWildcardChildren (rec: Node, exp: Node): void {
|
function filterWildcardChildren (rec: Node, exp: Node): void {
|
||||||
if (exp.firstChild === AnythingNode
|
if (exp.firstChild === AnythingNode
|
||||||
&& exp.children.length === 1
|
&& exp.childNodes.length === 1
|
||||||
&& rec instanceof HTMLElement
|
&& (rec as HTMLElement).innerHTML
|
||||||
&& rec.innerHTML
|
|
||||||
) {
|
) {
|
||||||
rec.innerHTML = ''
|
if (isWritable(rec, 'innerHTML')) {
|
||||||
rec.children.splice(0, rec.children.length, AnythingNode)
|
(rec as HTMLElement).innerHTML = ''
|
||||||
|
}
|
||||||
|
rec.childNodes.splice(0, rec.childNodes.length, AnythingNode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for (let i = 0; i < exp.children.length && i < rec.children.length; i++) {
|
for (let i = 0; i < exp.childNodes.length && i < rec.childNodes.length; i++) {
|
||||||
if (exp.children[i] === AnythingNode) {
|
if (exp.childNodes[i] === AnythingNode) {
|
||||||
rec.children[i] = AnythingNode
|
rec.childNodes[i] = AnythingNode
|
||||||
} else {
|
} else {
|
||||||
filterWildcardChildren(exp.children[i], rec.children[i])
|
filterWildcardChildren(rec.childNodes[i], exp.childNodes[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,11 +54,13 @@ function clearAttributes (node: Node): void {
|
||||||
node.attributes = {}
|
node.attributes = {}
|
||||||
node.className = ''
|
node.className = ''
|
||||||
}
|
}
|
||||||
node.children.forEach(clearAttributes)
|
node.childNodes.forEach(clearAttributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toMatchElement (received: HTMLElement, expected: HTMLElement, opts?: Options): MatcherResult {
|
export function toMatchElement (received: HTMLElement, expected: HTMLElement, opts?: Options): MatcherResult {
|
||||||
|
if (received.cloneNode) {
|
||||||
received = received.cloneNode(true) as HTMLElement
|
received = received.cloneNode(true) as HTMLElement
|
||||||
|
}
|
||||||
|
|
||||||
if (opts?.ignoreAttrs) {
|
if (opts?.ignoreAttrs) {
|
||||||
clearAttributes(received)
|
clearAttributes(received)
|
||||||
|
|
6
test/tsconfig.json
Normal file
6
test/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.test.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
},
|
||||||
|
}
|
|
@ -42,7 +42,9 @@
|
||||||
/* Module Resolution Options */
|
/* Module Resolution Options */
|
||||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
"paths": { /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||||
|
"*": ["../../types/*"], /* This path is relative from baseUrl which is defined in tsconfig.json that includes this file inside each project. */
|
||||||
|
},
|
||||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||||
"typeRoots": [ /* List of folders to include type definitions from. */
|
"typeRoots": [ /* List of folders to include type definitions from. */
|
||||||
"./types",
|
"./types",
|
||||||
|
|
16
tsconfig.test.json
Normal file
16
tsconfig.test.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": false,
|
||||||
|
"declarationMap": false,
|
||||||
|
"sourceMap": false,
|
||||||
|
"composite": false,
|
||||||
|
"noEmit": true,
|
||||||
|
"paths": {
|
||||||
|
// These paths are relative from baseUrl which is defined in
|
||||||
|
// tsconfig.json that includes this file inside each project.
|
||||||
|
"@/*": ["../src/*"],
|
||||||
|
"~/*": ["../../../*"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue