@octanejs/octane-is 0.0.1
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/LICENSE +21 -0
- package/LICENSE.upstream +21 -0
- package/README.md +42 -0
- package/UPSTREAM.md +57 -0
- package/package.json +50 -0
- package/src/ReactIs.ts +97 -0
- package/src/index.ts +28 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dominic Gannaway
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/LICENSE.upstream
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @octanejs/octane-is
|
|
2
|
+
|
|
3
|
+
The `react-is` 19.2.7 predicates for Octane elements. Replace `react-is` imports
|
|
4
|
+
with `@octanejs/octane-is` when porting source to Octane.
|
|
5
|
+
|
|
6
|
+
This binding requires the coordinated Octane core release containing the
|
|
7
|
+
behavioral-audit fixes, planned for **Octane 0.2.3**. Its predicates depend on that
|
|
8
|
+
release's `StrictMode` export and owner-bound component-kind metadata. Release
|
|
9
|
+
and install the binding together with that core version or a later compatible
|
|
10
|
+
release. The repository's shared beta peer range is broader than this capability
|
|
11
|
+
requirement; it does not establish compatibility with older core releases.
|
|
12
|
+
|
|
13
|
+
Install it alongside the required Octane release:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install @octanejs/octane-is octane@^0.2.3
|
|
17
|
+
pnpm add @octanejs/octane-is octane@^0.2.3
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { createElement, Fragment, memo } from 'octane';
|
|
22
|
+
import { isFragment, isMemo, typeOf } from '@octanejs/octane-is';
|
|
23
|
+
|
|
24
|
+
isFragment(createElement(Fragment, null)); // true
|
|
25
|
+
isMemo(createElement(memo(() => null), null)); // true
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
All 26 upstream exports are available. Kind labels use Octane symbols; React
|
|
29
|
+
elements are not Octane elements. Component functions themselves are valid
|
|
30
|
+
element types, while `isMemo` and `isLazy` inspect element descriptors, as in
|
|
31
|
+
`react-is`. Inspection never renders components or starts lazy loaders.
|
|
32
|
+
|
|
33
|
+
Octane has no Context.Consumer, forwardRef, Profiler, or SuspenseList. Their
|
|
34
|
+
predicates return false and their exported kind labels are not valid element
|
|
35
|
+
types. Refs are ordinary props; read context with `use` or `useContext`.
|
|
36
|
+
StrictMode is the Octane pass-through wrapper and does not double invoke.
|
|
37
|
+
`StrictMode` and `Suspense` exported here are classifier labels. Construct
|
|
38
|
+
elements with the corresponding functions from `octane`; the labels themselves
|
|
39
|
+
are not valid element types. The shared `Fragment` symbol is also Octane's
|
|
40
|
+
fragment element type.
|
|
41
|
+
|
|
42
|
+
See [UPSTREAM.md](./UPSTREAM.md) for the immutable source pin and test crosswalk.
|
package/UPSTREAM.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Upstream boundary
|
|
2
|
+
|
|
3
|
+
- Package: `react-is@19.2.7`.
|
|
4
|
+
- Source: https://github.com/facebook/react/tree/6117d7cca4906492c51fe6a03381e35adfd86e7d/packages/react-is
|
|
5
|
+
- Immutable commit: `6117d7cca4906492c51fe6a03381e35adfd86e7d`.
|
|
6
|
+
- License: MIT. `LICENSE.upstream` retains the exact Meta notice and permission.
|
|
7
|
+
- npm integrity: `sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==`.
|
|
8
|
+
|
|
9
|
+
`audit/upstream.lock.json` pins every pristine source and test blob. `src/ReactIs.ts`
|
|
10
|
+
adapts `src/ReactIs.js`; `src/index.ts` mirrors `index.stable.js`. Runtime ownership
|
|
11
|
+
is Octane's `$$kind`, callable context, memo marker and lazy marker. No React
|
|
12
|
+
runtime dependency or React element branding ships.
|
|
13
|
+
|
|
14
|
+
## Octane release requirement
|
|
15
|
+
|
|
16
|
+
Publish this binding with the coordinated Octane core release containing the
|
|
17
|
+
behavioral-audit fixes, planned for **0.2.3**. Earlier releases do not supply the
|
|
18
|
+
required `StrictMode` export and owner-bound component-kind metadata. Validation
|
|
19
|
+
uses the current workspace core containing those changes. The shared beta peer
|
|
20
|
+
range is mandated by repository source and tarball validation; it is not a claim
|
|
21
|
+
that earlier core releases implement these capabilities. Shipping this binding
|
|
22
|
+
before the coordinated core release would expose an unresolved runtime dependency.
|
|
23
|
+
|
|
24
|
+
## Source boundary
|
|
25
|
+
|
|
26
|
+
The two authored TypeScript source modules adapt only the pinned `react-is`
|
|
27
|
+
package's `src/ReactIs.js` and `index.stable.js`. The pinned npm artifact supplies
|
|
28
|
+
the pristine runtime oracle. The copied upstream source, tests and npm artifact
|
|
29
|
+
stay outside published files; their exact licenses and hashes are retained.
|
|
30
|
+
|
|
31
|
+
The complete published surface is accounted for: `typeOf`, `isValidElementType`,
|
|
32
|
+
`ContextConsumer`, `ContextProvider`, `Element`, `ForwardRef`, `Fragment`, `Lazy`,
|
|
33
|
+
`Memo`, `Portal`, `Profiler`, `StrictMode`, `Suspense`, `SuspenseList`,
|
|
34
|
+
`isContextConsumer`, `isContextProvider`, `isElement`, `isForwardRef`, `isFragment`,
|
|
35
|
+
`isLazy`, `isMemo`, `isPortal`, `isProfiler`, `isStrictMode`, `isSuspense`, and
|
|
36
|
+
`isSuspenseList`.
|
|
37
|
+
|
|
38
|
+
Consumer, ForwardRef, Profiler and SuspenseList labels/predicates remain exported,
|
|
39
|
+
but cannot identify a supported Octane kind: those predicates return false and
|
|
40
|
+
their labels are not valid element types. Octane function refs need no forwarding
|
|
41
|
+
wrapper. StrictMode identifies the pass-through wrapper without promising double
|
|
42
|
+
invocation. React Server Component references and arbitrary `getModuleId` objects
|
|
43
|
+
are not valid Octane types. These are deliberate differences, covered by tests.
|
|
44
|
+
The exported StrictMode and Suspense symbols label the corresponding Octane
|
|
45
|
+
wrapper functions; use those functions from `octane` to construct elements.
|
|
46
|
+
Classifier symbols do not grant rendering support. Fragment is the shared
|
|
47
|
+
exception: its symbol is also Octane's fragment element type.
|
|
48
|
+
|
|
49
|
+
The pinned package ships no TypeScript declaration files or type tests. Strict
|
|
50
|
+
authored/public/packed-source type consumers validate this binding's declarations.
|
|
51
|
+
The pinned Flow implementation informs the authored signature crosswalk; no
|
|
52
|
+
separate upstream TypeScript suite is invented. The full public type consumer
|
|
53
|
+
asserts all 26 exports and rejects invalid calls and return assignments.
|
|
54
|
+
The upstream runtime inventory has 14 cases; its experimental SuspenseList case
|
|
55
|
+
is inapplicable to the pinned stable package. Supported cases run against the
|
|
56
|
+
pinned original and the adapted Octane suite; unsupported kinds retain explicit
|
|
57
|
+
negative controls. See the machine crosswalk in `audit/`.
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@octanejs/octane-is",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Element-kind predicates for Octane, matching react-is 19.2.7's public surface.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=22.22.2"
|
|
10
|
+
},
|
|
11
|
+
"author": {
|
|
12
|
+
"name": "Dominic Gannaway",
|
|
13
|
+
"email": "dg@domgan.com"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/octanejs/octane.git",
|
|
21
|
+
"directory": "packages/octane-is"
|
|
22
|
+
},
|
|
23
|
+
"main": "src/index.ts",
|
|
24
|
+
"module": "src/index.ts",
|
|
25
|
+
"types": "src/index.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": "./src/index.ts"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"src",
|
|
31
|
+
"README.md",
|
|
32
|
+
"UPSTREAM.md",
|
|
33
|
+
"LICENSE",
|
|
34
|
+
"LICENSE.upstream"
|
|
35
|
+
],
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"octane": "^0.1.51 || ^0.2.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"react": "19.2.7",
|
|
41
|
+
"react-dom": "19.2.7",
|
|
42
|
+
"vitest": "^4.1.10",
|
|
43
|
+
"octane": "0.2.3"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"test": "vitest run --root ../.. --project octane-is --project octane-is-pristine --project octane-is-differential --maxWorkers=2",
|
|
47
|
+
"upstream:verify": "node ../../scripts/react-parity/verify-provenance.mjs",
|
|
48
|
+
"upstream:test": "node ../../scripts/react-parity/run-pristine.mjs octane-is"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/ReactIs.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
* Adapted for Octane from react-is 19.2.7 under the MIT license.
|
|
4
|
+
* See LICENSE.upstream and UPSTREAM.md.
|
|
5
|
+
*/
|
|
6
|
+
import { Activity, StrictMode as OctaneStrictMode } from 'octane';
|
|
7
|
+
import type { ElementDescriptor } from 'octane';
|
|
8
|
+
|
|
9
|
+
export const ContextConsumer: symbol = Symbol.for('octane.consumer');
|
|
10
|
+
export const ContextProvider: symbol = Symbol.for('octane.context');
|
|
11
|
+
export const Element: symbol = Symbol.for('octane.element');
|
|
12
|
+
export const ForwardRef: symbol = Symbol.for('octane.forward_ref');
|
|
13
|
+
export const Fragment: symbol = Symbol.for('octane.Fragment');
|
|
14
|
+
export const Lazy: symbol = Symbol.for('octane.lazy');
|
|
15
|
+
export const Memo: symbol = Symbol.for('octane.memo');
|
|
16
|
+
export const Portal: symbol = Symbol.for('octane.portal');
|
|
17
|
+
export const Profiler: symbol = Symbol.for('octane.profiler');
|
|
18
|
+
export const StrictMode: symbol = Symbol.for('octane.strict_mode');
|
|
19
|
+
export const Suspense: symbol = Symbol.for('octane.suspense');
|
|
20
|
+
export const SuspenseList: symbol = Symbol.for('octane.suspense_list');
|
|
21
|
+
|
|
22
|
+
interface BrandedValue {
|
|
23
|
+
$$kind?: unknown;
|
|
24
|
+
type?: unknown;
|
|
25
|
+
}
|
|
26
|
+
interface ComponentMetadata extends Function {
|
|
27
|
+
$$kind?: unknown;
|
|
28
|
+
Provider?: unknown;
|
|
29
|
+
__memo?: unknown;
|
|
30
|
+
[key: symbol]: unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Return an Octane kind label without executing a component or lazy loader. */
|
|
34
|
+
export function typeOf(value: unknown): symbol | undefined {
|
|
35
|
+
if (typeof value !== 'object' || value === null) return undefined;
|
|
36
|
+
const descriptor = value as BrandedValue;
|
|
37
|
+
if (descriptor.$$kind === Portal) return Portal;
|
|
38
|
+
if (descriptor.$$kind !== Element) return undefined;
|
|
39
|
+
const type = descriptor.type;
|
|
40
|
+
if (type === Fragment) return Fragment;
|
|
41
|
+
if (type === OctaneStrictMode) return StrictMode;
|
|
42
|
+
if (typeof type === 'function') {
|
|
43
|
+
const component = type as ComponentMetadata;
|
|
44
|
+
if (component[Suspense] === true) return Suspense;
|
|
45
|
+
if (component.$$kind === ContextProvider && component.Provider === component)
|
|
46
|
+
return ContextProvider;
|
|
47
|
+
// Lazy may acquire memo bailout metadata after resolving a memo wrapper.
|
|
48
|
+
// Its public kind remains Lazy, and inspecting it never starts the load.
|
|
49
|
+
if (component[Lazy] === true) return Lazy;
|
|
50
|
+
if (component.__memo === true) return Memo;
|
|
51
|
+
}
|
|
52
|
+
return Element;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function isValidElementType(type: unknown): boolean {
|
|
56
|
+
return (
|
|
57
|
+
typeof type === 'string' || typeof type === 'function' || type === Fragment || type === Activity
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
// OCTANE DIVERGENCE[unsupported-renderer-kinds][runtime:50faf032d93f99c2]
|
|
61
|
+
// Unsupported renderer kinds remain negative feature probes.
|
|
62
|
+
export function isContextConsumer(_value: unknown): boolean {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
export function isContextProvider(value: unknown): boolean {
|
|
66
|
+
return typeOf(value) === ContextProvider;
|
|
67
|
+
}
|
|
68
|
+
export function isElement(value: unknown): value is ElementDescriptor<unknown> {
|
|
69
|
+
return typeof value === 'object' && value !== null && (value as BrandedValue).$$kind === Element;
|
|
70
|
+
}
|
|
71
|
+
export function isForwardRef(_value: unknown): boolean {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
export function isFragment(value: unknown): boolean {
|
|
75
|
+
return typeOf(value) === Fragment;
|
|
76
|
+
}
|
|
77
|
+
export function isLazy(value: unknown): boolean {
|
|
78
|
+
return typeOf(value) === Lazy;
|
|
79
|
+
}
|
|
80
|
+
export function isMemo(value: unknown): boolean {
|
|
81
|
+
return typeOf(value) === Memo;
|
|
82
|
+
}
|
|
83
|
+
export function isPortal(value: unknown): boolean {
|
|
84
|
+
return typeOf(value) === Portal;
|
|
85
|
+
}
|
|
86
|
+
export function isProfiler(_value: unknown): boolean {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
export function isStrictMode(value: unknown): boolean {
|
|
90
|
+
return typeOf(value) === StrictMode;
|
|
91
|
+
}
|
|
92
|
+
export function isSuspense(value: unknown): boolean {
|
|
93
|
+
return typeOf(value) === Suspense;
|
|
94
|
+
}
|
|
95
|
+
export function isSuspenseList(_value: unknown): boolean {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export {
|
|
2
|
+
isValidElementType,
|
|
3
|
+
typeOf,
|
|
4
|
+
ContextConsumer,
|
|
5
|
+
ContextProvider,
|
|
6
|
+
Element,
|
|
7
|
+
ForwardRef,
|
|
8
|
+
Fragment,
|
|
9
|
+
Lazy,
|
|
10
|
+
Memo,
|
|
11
|
+
Portal,
|
|
12
|
+
Profiler,
|
|
13
|
+
StrictMode,
|
|
14
|
+
Suspense,
|
|
15
|
+
SuspenseList,
|
|
16
|
+
isContextConsumer,
|
|
17
|
+
isContextProvider,
|
|
18
|
+
isElement,
|
|
19
|
+
isForwardRef,
|
|
20
|
+
isFragment,
|
|
21
|
+
isLazy,
|
|
22
|
+
isMemo,
|
|
23
|
+
isPortal,
|
|
24
|
+
isProfiler,
|
|
25
|
+
isStrictMode,
|
|
26
|
+
isSuspense,
|
|
27
|
+
isSuspenseList,
|
|
28
|
+
} from './ReactIs.ts';
|