Skip to content

Conversation

@mientjan
Copy link
Owner

@mientjan mientjan commented Feb 9, 2026

No description provided.

- Add TypeScript, ESLint, Jest, Babel, and react-native-builder-bob configs
- Update package.json with modern deps (markdown-it ^14, React 18+, RN 0.73+)
- Remove prop-types, react-native-fit-image, chokidar, fs-extra
- Replace .npmignore with files field in package.json
- Add CJS + ESM + TypeScript build targets via builder-bob
- Convert all 13 utility files from JS to TS/TSX
- Create shared types.ts with ASTNode, RenderFunction, RenderRules, MarkdownStyles
- Add 11 test suites with 47 unit tests covering all utilities
- All tests pass, TypeScript compiles cleanly
- Convert styles, AstRenderer, parser, renderRules, plugins to TypeScript
- Remove react-native-fit-image dependency, use RN Image instead
- Remove broken PropTypes import from react in AstRenderer
- Add 4 test suites (AstRenderer, parser, renderRules, PluginContainer)
- Total: 15 test suites, 69 tests all passing
- Replace class component with functional component using useMemo hooks
- Remove deprecated componentWillMount and componentWillReceiveProps
- Remove PropTypes, use TypeScript MarkdownProps interface instead
- Delete hand-written index.d.ts (auto-generated by builder-bob now)
- Export types: ASTNode, RenderFunction, RenderRules, MarkdownStyles, MarkdownProps
- Set allowJs: false in tsconfig (all source is now TypeScript)
- Add 25 Markdown component tests
- Total: 16 test suites, 94 tests all passing
- Fix all ESLint errors across source and test files
- Add test file overrides in ESLint config (lenient on any in tests)
- Disable react/prop-types rule (TypeScript handles this)
- Fix unused React import and prefer-spread in index.tsx
- Add integration test with 3 snapshot tests
- Fix types path in package.json for builder-bob output
- Bob build now produces clean CJS + ESM + TypeScript output
- Total: 17 test suites, 99 tests all passing
Remove old example app, bin/ build scripts, export.json debug artifact,
and legacy README.v1.3.6.md. Add CHANGELOG.md documenting all v4 breaking
changes. Rewrite README.md with TypeScript examples, migration guide, and
updated compatibility table.
Expo TypeScript app with markdown showcase covering headings, bold,
italic, strikethrough, links, code blocks, blockquotes, tables, lists,
and horizontal rules. Configured Metro to resolve the local library.
Run with: cd example && npm start
Add default lineHeight fallback in Platform.select for web platform.
Fix Metro config to use extraNodeModules instead of file:.. symlink
to resolve the library, avoiding main field resolution errors.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Modernizes the library for a v4 release by migrating the implementation from JavaScript to TypeScript, updating the React/React Native + markdown-it baselines, and switching the package build pipeline to react-native-builder-bob with a refreshed Expo-based example app and a new Jest test suite.

Changes:

  • Convert core renderer/parser/utilities from JS (+ hand-written d.ts) to TypeScript with generated type declarations.
  • Update packaging/build/test tooling (bob outputs, tsconfigs, Jest, ESLint/Prettier) and adjust package entry points.
  • Refresh default render rules (remove react-native-fit-image) and replace the legacy RN example with an Expo example.

Reviewed changes

Copilot reviewed 133 out of 150 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tsconfig.json Base TS config for strict checking and JSX runtime.
tsconfig.build.json Build-time TS overrides for emitting declarations/output.
src/types.ts Introduces shared public types (ASTNode, render rule types, styles).
src/lib/util/tokensToAST.ts TS port of token→AST conversion with typed token input.
src/lib/util/tokensToAST.js Removes legacy JS implementation.
src/lib/util/stringToTokens.ts TS port of string→markdown-it token parsing.
src/lib/util/stringToTokens.js Removes legacy JS implementation.
src/lib/util/splitTextNonTextNodes.ts TS port of React element splitting helper.
src/lib/util/splitTextNonTextNodes.js Removes legacy JS implementation.
src/lib/util/openUrl.ts Adds TS typing for URL opener utility.
src/lib/util/hasParents.ts TS port of parent-check helper.
src/lib/util/hasParents.js Removes legacy JS implementation.
src/lib/util/groupTextTokens.ts TS port of text-group token wrapper.
src/lib/util/groupTextTokens.js Removes legacy JS implementation.
src/lib/util/getUniqueID.ts TS port of unique ID generator.
src/lib/util/getUniqueID.js Removes legacy JS implementation.
src/lib/util/getTokenTypeByToken.ts TS port of markdown-it token type normalization.
src/lib/util/getTokenTypeByToken.js Removes legacy JS implementation.
src/lib/util/flattenInlineTokens.ts TS port of inline token flattener.
src/lib/util/flattenInlineTokens.js Removes legacy JS implementation.
src/lib/util/cleanupTokens.ts TS port of token cleanup + link→blocklink conversion.
src/lib/util/cleanupTokens.js Removes legacy JS implementation.
src/lib/util/applyStyle.tsx TS port of style application helper for rendered children.
src/lib/util/applyStyle.js Removes legacy JS implementation.
src/lib/util/Token.ts TS port of Token class used by grouping utilities.
src/lib/util/Token.js Removes legacy JS implementation.
src/lib/styles.ts Updates default styles (list alignment + Platform.select defaults).
src/lib/renderRules.tsx TS render rules; removes FitImage usage in favor of RN Image.
src/lib/renderRules.js Removes legacy JS render rules.
src/lib/plugin/blockPlugin.ts TS port of block container plugin.
src/lib/plugin/blockPlugin.js Removes legacy JS plugin.
src/lib/plugin/PluginContainer.ts TS port of plugin container helper.
src/lib/plugin/PluginContainer.js Removes legacy JS helper.
src/lib/parser.ts TS parser pipeline wiring (tokens→cleanup→group→AST→renderer).
src/lib/parser.js Removes legacy JS parser.
src/lib/data/PlatformEnum.ts TS platform enum with literal types.
src/lib/data/PlatformEnum.js Removes legacy JS enum.
src/lib/AstRenderer.tsx TS renderer class + typed render pipeline.
src/lib/AstRenderer.js Removes legacy JS renderer.
src/index.tsx Replaces class component with hook-based functional Markdown component; re-exports/types.
src/index.js Removes legacy entrypoint.
src/index.d.ts Removes hand-written types (replaced by generated declarations).
src/tests/util/tokensToAST.test.ts Adds unit coverage for token→AST conversion.
src/tests/util/stringToTokens.test.ts Adds unit coverage for markdown-it parsing wrapper.
src/tests/util/splitTextNonTextNodes.test.ts Adds unit coverage for node splitting helper.
src/tests/util/hasParents.test.ts Adds unit coverage for parent type checks.
src/tests/util/groupTextTokens.test.ts Adds unit coverage for token grouping behavior.
src/tests/util/getUniqueID.test.ts Adds unit coverage for unique ID generator.
src/tests/util/getTokenTypeByToken.test.ts Adds unit coverage for token type normalization.
src/tests/util/flattenInlineTokens.test.ts Adds unit coverage for inline flattening.
src/tests/util/cleanupTokens.test.ts Adds unit coverage for token cleanup/blocklink conversion.
src/tests/util/applyStyle.test.tsx Adds unit coverage for applyStyle behavior.
src/tests/util/Token.test.ts Adds unit coverage for Token class.
src/tests/renderRules.test.tsx Adds renderRules tests with react-test-renderer.
src/tests/plugin/PluginContainer.test.ts Adds PluginContainer tests.
src/tests/parser.test.ts Adds parser pipeline tests.
src/tests/integration.test.tsx Adds snapshot-style integration coverage.
src/tests/Markdown.test.tsx Adds component-level tests for new hook-based Markdown.
src/tests/AstRenderer.test.tsx Adds AstRenderer tests.
package.json Updates to v4 alpha, new entry points, bob build config, deps/devDeps, scripts.
jest.config.js Adds Jest configuration for TS/TSX tests and coverage.
example/tsconfig.json Adds TS config for the Expo example.
example/src/pluginRules.js Removes legacy example rule file.
example/src/customMarkdownStyle.js Removes legacy example style file.
example/src/copyAllCheckboxPlugin.js Removes legacy example copy source.
example/src/copyAll.js Removes legacy example copy source.
example/src/copy/linkedimg.js Removes legacy example copy source.
example/src/copy/all.js Removes legacy example copy source.
example/src/code.js Removes legacy example copy source.
example/react-native-markdown-renderer/lib/util/stringToTokens.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/util/splitTextNonTextNodes.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/util/openUrl.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/util/hasParents.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/util/getUniqueID.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/util/getTokenTypeByToken.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/util/flattenInlineTokens.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/util/applyStyle.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/util/Token.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/styles.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/renderRules.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/plugin/blockPlugin.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/plugin/PluginContainer.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/parser.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/data/PlatformEnum.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/lib/AstRenderer.js Removes vendored legacy library copy inside example.
example/react-native-markdown-renderer/index.js Removes vendored legacy library entry inside example.
example/react-native-markdown-renderer/index.d.ts Removes vendored legacy library types inside example.
example/package.json Converts example app to Expo-managed setup with updated dependencies.
example/metro.config.js Adds Expo Metro config for local library development.
example/ios/exampleTests/exampleTests.m Removes legacy native iOS test harness.
example/ios/exampleTests/Info.plist Removes legacy native iOS test plist.
example/ios/example/main.m Removes legacy native iOS entrypoint.
example/ios/example/Info.plist Removes legacy native iOS app plist.
example/ios/example/Images.xcassets/Contents.json Removes legacy iOS assets metadata.
example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json Removes legacy iOS icon set metadata.
example/ios/example/Base.lproj/LaunchScreen.xib Removes legacy iOS launch screen.
example/ios/example/AppDelegate.m Removes legacy iOS AppDelegate implementation.
example/ios/example/AppDelegate.h Removes legacy iOS AppDelegate header.
example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme Removes legacy Xcode scheme.
example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme Removes legacy tvOS scheme.
example/ios/example-tvOSTests/Info.plist Removes legacy tvOS test plist.
example/ios/example-tvOS/Info.plist Removes legacy tvOS app plist.
example/index.ts Adds Expo entrypoint registering root component.
example/index.js Removes legacy RN CLI entrypoint.
example/app.json Converts to Expo app config.
example/android/settings.gradle Removes legacy Android project settings.
example/android/keystores/debug.keystore.properties Removes legacy debug keystore props.
example/android/keystores/BUCK Removes legacy Buck config.
example/android/gradlew.bat Removes legacy Gradle wrapper script.
example/android/gradlew Removes legacy Gradle wrapper script.
example/android/gradle/wrapper/gradle-wrapper.properties Removes legacy wrapper properties.
example/android/gradle/wrapper/gradle-wrapper.jar Removes legacy wrapper jar.
example/android/gradle.properties Removes legacy Gradle properties.
example/android/build.gradle Removes legacy top-level Gradle build.
example/android/app/src/main/res/values/styles.xml Removes legacy Android resources.
example/android/app/src/main/res/values/strings.xml Removes legacy Android resources.
example/android/app/src/main/java/com/example/MainApplication.java Removes legacy Android application class.
example/android/app/src/main/java/com/example/MainActivity.java Removes legacy Android activity.
example/android/app/src/main/AndroidManifest.xml Removes legacy Android manifest.
example/android/app/proguard-rules.pro Removes legacy Proguard rules.
example/android/app/build.gradle Removes legacy Android app Gradle build.
example/android/app/BUCK Removes legacy Buck config.
example/App.tsx Adds new Expo example UI demonstrating markdown rendering.
example/App.js Removes legacy example app implementation.
example/.watchmanconfig Removes legacy Watchman config.
example/.gitignore Updates ignore rules for Expo + generated native folders.
example/.gitattributes Removes legacy gitattributes.
example/.flowconfig Removes legacy Flow config.
example/.buckconfig Removes legacy Buck config.
example/.babelrc Removes legacy Babel config.
bin/watch.js Removes legacy dev watch/copy script.
bin/test.js Removes legacy debug script.
bin/example.js Removes legacy embedded example markdown.
bin/data.json Removes legacy debug output artifact.
bin/copy-to-run.js Removes legacy copy script.
babel.config.js Adds root Babel config for Jest/React Native preset.
README.v1.3.6.md Removes legacy archived README.
README.md Rewrites docs for v4 (TS, new props/types, migration section).
CHANGELOG.md Adds v4 alpha changelog entry.
.npmignore Removes .npmignore in favor of package.json files.
.gitignore Updates ignores for build output and TS artifacts.
.eslintrc.js Adds ESLint configuration for TS/React/React Hooks.
Comments suppressed due to low confidence (1)

src/lib/util/cleanupTokens.ts:44

  • Similar to flattenInlineTokens, this loop drains stack via shift(), which is O(n) per element and can become quadratic. Prefer a simple while-pop pattern (LIFO) or iterate over stack by index, depending on the intended ordering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3 to +30
export interface BlockPluginOptions {
marker?: string;
marker_end?: string;
validate?: (params: string) => boolean;
render?: (tokens: any[], idx: number, options: any, env: any, self: any) => any;
}

export default function blockPlugin(md: any, name: string, options?: BlockPluginOptions): void {
function validateDefault(params: string): boolean {
return params.trim().split(' ', 2)[0] === name;
}

function renderDefault(tokens: any[], idx: number, _options: any, env: any, self: any): any {
return self.renderToken(tokens, idx, _options, env, self);
}

const opts = options || {};

const min_markers = 1;
const marker_str = opts.marker || `[${name}]`;
const marker_end_str = opts.marker_end || `[/${name}]`;
const marker_char = marker_str.charCodeAt(0);
const marker_len = marker_str.length;
const marker_end_len = marker_end_str.length;

const validate = opts.validate || validateDefault;
const render = opts.render || renderDefault;

Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BlockPluginOptions.validate is defined and a validate function is selected, but the container rule never calls it, so options.validate has no effect. Either invoke validate(params) before accepting the opening marker (and return false when it fails), or remove the option to avoid a misleading API.

Copilot uses AI. Check for mistakes.
Comment on lines +136 to +138
md.block.ruler.before('fence', 'container_checklist', container, {
alt: ['paragraph', 'reference', 'blockquote', 'list'],
});
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The block rule is registered under the fixed name 'container_checklist', which will collide/override if blockPlugin is used more than once for different container names. Use a rule key that includes name (e.g., container_${name}) so multiple containers can coexist.

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +13
if (curr.type === 'inline' && curr.children && curr.children.length > 0) {
const children = flattenTokens(curr.children as T[]);
while (children.length) {
acc.push(children.shift()!);
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation repeatedly uses children.shift() inside a loop. shift() is O(n), so this becomes quadratic for large inline token lists. Prefer iterating with an index / for..of and pushing directly, or acc.push(...flattenTokens(curr.children)) to keep it linear.

Copilot uses AI. Check for mistakes.
const marker_len = marker_str.length;
const marker_end_len = marker_end_str.length;

const validate = opts.validate || validateDefault;
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable validate.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant