npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@pretext-book/jsx

v1.0.1

Published

Use JSX to render a pretext file

Downloads

3

Readme

@pretext-book/jsx

A jsx implementation of PreTeXt

Development

To build this project, you need nodejs installed (>= v18 is recommended). Then run npm install in the root directory of the monorepo (i.e., not in the directory of this package).

Then, in the directory of this package, run

npm run build

This will build the package and put the built files in the dist/ directory. The package.json in this package directly references built files from dist/.

Live Rebuilding

Running npm run watch will start the build script with live reloading every time a file changes.

Tests

Run npm run test to execute the test suite. vitest is used as a test runner. Test are located in test/ and always end in a .test.ts. Because the tests are ouside of src/ your Typescript linter may complain about using references outside of the Typescript root.

If you want to run a specific test, you can press t in the vitest console and then type the name of the test you want to run. For example, to run tests related to the fragment ol-1.xml you could type "t ol-1".

Fragments

A temporary script has been created to render fragments until the CLI has the capability built in. It is called basic-compile.sh and relies on you running in a linux environment with the cli and nodejs installed. By default it renders to the ./tmp_fragment_compile/ folder. If you just want to see the results of a rendered fragment exported directly to the console, navigate to the packages/fragment directory and then, you may run a command like

NAME="ol-1"; ./basic-compile.sh tests/fragments/$NAME.xml && cat ./tmp_fragment_compile/$NAME.html

where NAME is set to the name of the fragment you wish to render.

To rerender and save all fragments, you can run

for i in tests/fragments/*xml; do A=`basename "$i"`; B=${A%.*}; NAME=$B; ./basic-compile.sh tests/fragments/$NAME.xml && cat ./tmp_fragment_compile/$NAME.html > tests/fragments/pretext-xsl-reference/$NAME.html; done
Fragment testing

A custom vitest/jest comparison function has been created to be used in tests. If a test file includes

import { jestToMatchFragment } from "@pretext-book/fragment";
expect.extend(jestToMatchFragment);

then you can use

expect(frag1).toMatchFragment(frag2);

to verify that two fragments match each other. Before comparison, these html fragments are normalized so that their attributes come in alphabetical order and their IDs are are replaced with id-0, id-1, etc...

How it Works

@pretext-book/jsx mimics the steps of the XSLT implementation of PreTeXt. Processing a document proceeds via:

  1. The XML input is parsed to a unifiedjs/xast

  2. The XML is normalized via rules derived from the schema. Normalizing expands all <CDATA... to actual text nodes, removes whitespace ocurring between nodes where whitespace is ignored, etc. The code for this is in src/stages/0-normalize

  3. An "assemble" stage where unique ids are added to all id-able elements, blank titles are inserted into elements that can have a title but don't, <docinfo /> tags and frontmatter is extracted from the document. The code for this is in src/stages/1-normalize.

  4. The conversion to HTML via unifiedjs plugins (code in src/target/html):

    i. Gather information about the document such as the information needed for creating the TOC and for allowing complex queries of the XML tree (e.g., collecting data about node parents, etc.)

    ii. Conversion to React. During this process, unifiedjs walks the syntax tree and asks for each node if there is a replacer available for that node. If so, the return value of the replacer is used. If not, the node is converted verbatim to React/html. To see exactly which elements are replaced, see src/target/html/index.ts and for the replacers themselves, see src/target/html/replacers/

  5. The resulting React object is converted to HTML via ReactDOM. It is then pretty-printed with Prettier.

Replacers

A replacer consists of two parts: a test function that determines whether a node should be replaced, and the React component that replaces the node.

Test Functions

A test function can be arbitrarily complicated, but there are ready-made test functions for the operation "if the node name matches X, it should be replaced". See replacerFactory and replacerFactoryWithId.

React Components

See src/target/html/components for examples of react components. (Components like p.tsx tend to be simpler, for your viewing pleasure.) At the start of each React component, you will see

const state = React.useContext(PretextStateContext);

This state object contains all information that was collected before the React processing started. It includes TOC information, information for references, etc. If you need any global information, or you need to look up a node's parents, you will be quierying the state object.

The rest of the component should look like standard React code, save for the special call

state.processContent(node.children);

which asks the replacer to run on all the current node's children. Calling this function (or not) gives you control over the recursive replacement process.

Contributing

Please contribute by adding replacers and tests! Add a file in src/target/html/components corresponding to the tag you wich in implement. Then add a line in src/target/html/index.ts to have your replacer called whenever your tag shows up in the source.

After you implement a tag/replacer, please add a test to the test/ folder to make sure your code doesn't break in the future!

Tips

If you run npm run watch, your code will automatically recompile when a file changes. Then, if you are running the pretext-playground in development mode (via npm run start), you will have hot-reloading upon file change, so you can immediately play around with your new tag.