noxcturnal 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +143 -0
- package/dist/noxcturnal.d.ts +6012 -0
- package/dist/noxcturnal.js +7513 -0
- package/dist/noxcturnal.js.map +1 -0
- package/dist/noxcturnal.mjs +7489 -0
- package/dist/noxcturnal.mjs.map +1 -0
- package/package.json +150 -0
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Noxcturnal
|
|
2
|
+
|
|
3
|
+
Noxcturnal is a native-backed JavaScript transformation library. It combines a typed,
|
|
4
|
+
Babel-like visitor API in TypeScript with parsing, semantic analysis, traversal, edit validation,
|
|
5
|
+
rendering, and source-map generation in Rust.
|
|
6
|
+
|
|
7
|
+
Noxcturnal is an independent transform runtime. It is not a Metro transformer and does not collect
|
|
8
|
+
dependencies, rewrite modules, or wrap output for a particular framework.
|
|
9
|
+
|
|
10
|
+
> [!NOTE]
|
|
11
|
+
> Noxcturnal is under active development. Its public API may change before the first stable release.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
pnpm add noxcturnal
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Noxcturnal requires Node.js 18 or later. The package selects a prebuilt native binary for supported
|
|
20
|
+
macOS, Linux, and Windows targets.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
Plugins declare exactly which nodes and fields they need. Noxcturnal compiles those declarations
|
|
25
|
+
into native routes, sends only the requested data to JavaScript, and commits the resulting edits as
|
|
26
|
+
one transaction.
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { defineNativePipeline, defineNativePlugin, defineVisitor, transform } from 'noxcturnal';
|
|
30
|
+
|
|
31
|
+
const replaceBuildId = defineNativePlugin({
|
|
32
|
+
name: 'replace-build-id',
|
|
33
|
+
contract: { metadata: { writes: ['replacedBuildId'] } },
|
|
34
|
+
visitors: [
|
|
35
|
+
defineVisitor(
|
|
36
|
+
'Identifier',
|
|
37
|
+
{
|
|
38
|
+
fields: ['name', 'global'],
|
|
39
|
+
where: { name: { equals: '__BUILD_ID__' } },
|
|
40
|
+
},
|
|
41
|
+
path => {
|
|
42
|
+
if (path.node.global) {
|
|
43
|
+
path.replaceWith(path.context.code.stringLiteral('development'));
|
|
44
|
+
path.context.metadata.set('replacedBuildId', true);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
),
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const pipeline = defineNativePipeline({
|
|
52
|
+
phases: [{ name: 'application', plugins: [replaceBuildId] }],
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const result = transform('console.log(__BUILD_ID__);', 'app.js', pipeline);
|
|
56
|
+
|
|
57
|
+
if (result.status === 'complete') {
|
|
58
|
+
console.log(result.code);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Every plugin in a phase observes the same immutable input. Its edits become visible together at the
|
|
63
|
+
phase boundary, after validation and an optional reparse. Split dependent transforms into separate
|
|
64
|
+
phases when a later transform must observe an earlier transform's output.
|
|
65
|
+
|
|
66
|
+
### Configuration and per-file data
|
|
67
|
+
|
|
68
|
+
Pipeline definitions describe reusable program configuration:
|
|
69
|
+
|
|
70
|
+
- `plugin.withOptions(options)` creates a definition with different declared behavior.
|
|
71
|
+
- `plugin.withParameters(values)` binds values used by native predicates.
|
|
72
|
+
- `pluginData` passes current-file data to state factories, hooks, and visitors.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
const result = transform(source, filename, pipeline, {
|
|
76
|
+
pluginData: { platform: 'ios' },
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Do not close over per-file data in a reusable plugin definition. Read it from `pluginData` instead.
|
|
81
|
+
If that data affects output, include it in the consumer's transform-result cache key;
|
|
82
|
+
`pipelineCacheKey` intentionally covers only Noxcturnal-owned configuration.
|
|
83
|
+
|
|
84
|
+
### Native transforms
|
|
85
|
+
|
|
86
|
+
A phase can run declarative native transforms without a JavaScript visitor:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const pipeline = defineNativePipeline({
|
|
90
|
+
phases: [
|
|
91
|
+
{
|
|
92
|
+
name: 'syntax',
|
|
93
|
+
native: {
|
|
94
|
+
typescript: 'strip',
|
|
95
|
+
transforms: {
|
|
96
|
+
optionalChaining: { loose: false },
|
|
97
|
+
nullishCoalescingOperator: { loose: false },
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The native surface includes TypeScript and Flow erasure, JSX modes, React Compiler and React
|
|
106
|
+
Refresh integration, common ES syntax lowering, constant folding, and dead-code elimination.
|
|
107
|
+
|
|
108
|
+
### Transform outcomes
|
|
109
|
+
|
|
110
|
+
`transform` has three outcomes:
|
|
111
|
+
|
|
112
|
+
- A successful transform returns a `NativeTransformResult`.
|
|
113
|
+
- An intentional compatibility boundary returns a `NativeBailoutResult` with the pristine input in
|
|
114
|
+
`source`.
|
|
115
|
+
- Invalid input or configuration and internal failures throw.
|
|
116
|
+
|
|
117
|
+
Run a compatibility transformer only for a returned bailout. Thrown failures should propagate.
|
|
118
|
+
Syntax failures use `TransformSyntaxError`; fatal native failures use `NativeTransformError` with
|
|
119
|
+
the stable code `NOXCTURNAL_TRANSFORM_ERROR`.
|
|
120
|
+
|
|
121
|
+
## Development
|
|
122
|
+
|
|
123
|
+
The reproducible development environment includes Node.js, pnpm, Rust, CMake, Ninja, Python, and
|
|
124
|
+
the C++ tools needed to build the optional Hermes-backed Flow parser.
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
nix develop
|
|
128
|
+
pnpm install
|
|
129
|
+
pnpm build
|
|
130
|
+
pnpm check
|
|
131
|
+
pnpm benchmark
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Use `pnpm format` to format the TypeScript and Rust sources. User-visible changes should include a
|
|
135
|
+
changeset because the main package and its native platform packages are released as one fixed
|
|
136
|
+
version group.
|
|
137
|
+
|
|
138
|
+
The test suite is organized by ownership and purpose; see [test/README.md](test/README.md) before
|
|
139
|
+
adding, moving, or deleting coverage.
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
MIT
|