expo-modules-macros 0.0.1 → 0.14.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/.github/resources/expo-modules-macros.svg +23 -0
- package/.github/workflows/publish.yml +122 -0
- package/.github/workflows/swift.yml +68 -0
- package/AGENTS.md +59 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +21 -0
- package/README.md +119 -0
- package/apple/ExpoModulesMacros +0 -0
- package/apple/Package.resolved +15 -0
- package/apple/Package.swift +61 -0
- package/apple/PodTests/StubTest.swift +5 -0
- package/apple/Sources/ExpoModulesMacros/DecorateModuleBuilder.swift +444 -0
- package/apple/Sources/ExpoModulesMacros/EventMacro.swift +330 -0
- package/apple/Sources/ExpoModulesMacros/ExpoModuleMacro.swift +263 -0
- package/apple/Sources/ExpoModulesMacros/ExpoModulesOptimizedMacro.swift +117 -0
- package/apple/Sources/ExpoModulesMacros/ExpoViewMacro.swift +259 -0
- package/apple/Sources/ExpoModulesMacros/FreeFormTypes.swift +214 -0
- package/apple/Sources/ExpoModulesMacros/JSConstructor.swift +55 -0
- package/apple/Sources/ExpoModulesMacros/JSMacro.swift +294 -0
- package/apple/Sources/ExpoModulesMacros/MacroHelpers.swift +433 -0
- package/apple/Sources/ExpoModulesMacros/OptimizedFunctionHelpers.swift +55 -0
- package/apple/Sources/ExpoModulesMacros/Plugin.swift +34 -0
- package/apple/Sources/ExpoModulesMacros/Receiver.swift +79 -0
- package/apple/Sources/ExpoModulesMacros/RecordMacro.swift +590 -0
- package/apple/Sources/ExpoModulesMacros/SharedObjectMacro.swift +162 -0
- package/apple/Sources/ExpoModulesMacros/TypeConformanceAssertion.swift +190 -0
- package/apple/Sources/ExpoModulesMacros/UnionMacro.swift +365 -0
- package/apple/Sources/ExpoModulesMacros/ViewPropsMacro.swift +477 -0
- package/apple/Sources/ExpoModulesOptimized/ExpoModulesOptimized.swift +19 -0
- package/apple/Sources/ExpoModulesScanner/CLI.swift +114 -0
- package/apple/Sources/ExpoModulesScanner/Core/Detection.swift +79 -0
- package/apple/Sources/ExpoModulesScanner/Core/DetectionVisitor.swift +181 -0
- package/apple/Sources/ExpoModulesScanner/Core/ScanBuildConfiguration.swift +115 -0
- package/apple/Sources/ExpoModulesScanner/Core/SourceScan.swift +193 -0
- package/apple/Sources/ExpoModulesScanner/Exports/ExportedSurface.swift +319 -0
- package/apple/Sources/ExpoModulesScanner/Exports/ResolveRefs.swift +199 -0
- package/apple/Sources/ExpoModulesScanner/Exports/ScanExports.swift +66 -0
- package/apple/Sources/ExpoModulesScanner/Exports/SurfaceVisitor.swift +616 -0
- package/apple/Sources/ExpoModulesScanner/Exports/TypeNode.swift +284 -0
- package/apple/Sources/ExpoModulesScanner/Modules/ScanModules.swift +161 -0
- package/apple/build.js +138 -0
- package/build/index.d.ts +51 -0
- package/build/index.js +153 -0
- package/build/types.d.ts +264 -0
- package/build/types.js +15 -0
- package/package.json +22 -5
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<svg width="303" height="48" viewBox="0 0 303 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<g clip-path="url(#clip0_748_204)">
|
|
3
|
+
<rect width="48" height="48" rx="10" fill="#63607A"/>
|
|
4
|
+
<g opacity="0.4">
|
|
5
|
+
<rect x="-28" y="-28" width="64" height="64" rx="10" fill="url(#paint0_radial_748_204)"/>
|
|
6
|
+
</g>
|
|
7
|
+
<path opacity="0.55" d="M21.4 24H24.5M24.5 17V31M24.5 17H28.8M24.5 24H28.8M24.5 31H28.8" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
8
|
+
<circle cx="18" cy="24" r="3.4" stroke="white" stroke-width="2"/>
|
|
9
|
+
<circle cx="31" cy="17" r="2.2" stroke="white" stroke-width="2"/>
|
|
10
|
+
<circle cx="31" cy="24" r="2.2" stroke="white" stroke-width="2"/>
|
|
11
|
+
<circle cx="31" cy="31" r="2.2" stroke="white" stroke-width="2"/>
|
|
12
|
+
</g>
|
|
13
|
+
<path d="M69.5781 32.5H80.0469V30.0703H72.4766V25.7031H79.4453V23.2734H72.4766V18.9297H79.9844V16.5H69.5781ZM85.1328 20.5H82.1328L85.6953 26.5L82.0391 32.5H85.0391L87.5547 28.1797L90.0938 32.5H93.0703L89.3906 26.5L93.0078 20.5H90.0156L87.5547 24.9297ZM95.1953 37.0H98.0234V30.6094H98.1406C98.5859 31.4844 99.5156 32.7109 101.5781 32.7109C104.4062 32.7109 106.5234 30.4688 106.5234 26.5156C106.5234 22.5156 104.3438 20.3438 101.5703 20.3438C99.4531 20.3438 98.5703 21.6172 98.1406 22.4844H97.9766V20.5H95.1953ZM97.9688 26.5C97.9688 24.1719 98.9688 22.6641 100.7891 22.6641C102.6719 22.6641 103.6406 24.2656 103.6406 26.5C103.6406 28.75 102.6562 30.3906 100.7891 30.3906C98.9844 30.3906 97.9688 28.8281 97.9688 26.5ZM114.1719 32.7344C117.6875 32.7344 119.9219 30.2578 119.9219 26.5469C119.9219 22.8281 117.6875 20.3438 114.1719 20.3438C110.6562 20.3438 108.4219 22.8281 108.4219 26.5469C108.4219 30.2578 110.6562 32.7344 114.1719 32.7344ZM114.1875 30.4688C112.2422 30.4688 111.2891 28.7344 111.2891 26.5391C111.2891 24.3438 112.2422 22.5859 114.1875 22.5859C116.1016 22.5859 117.0547 24.3438 117.0547 26.5391C117.0547 28.7344 116.1016 30.4688 114.1875 30.4688ZM127.8984 16.5V32.5H130.6797V21.4844H130.8281L135.25 32.4531H137.3281L141.75 21.5078H141.8984V32.5H144.6797V16.5H141.1328L136.3828 28.0938H136.1953L131.4453 16.5ZM152.9453 32.7344C156.4609 32.7344 158.6953 30.2578 158.6953 26.5469C158.6953 22.8281 156.4609 20.3438 152.9453 20.3438C149.4297 20.3438 147.1953 22.8281 147.1953 26.5469C147.1953 30.2578 149.4297 32.7344 152.9453 32.7344ZM152.9609 30.4688C151.0156 30.4688 150.0625 28.7344 150.0625 26.5391C150.0625 24.3438 151.0156 22.5859 152.9609 22.5859C154.875 22.5859 155.8281 24.3438 155.8281 26.5391C155.8281 28.7344 154.875 30.4688 152.9609 30.4688ZM165.5391 32.7109C167.6016 32.7109 168.5312 31.4844 168.9766 30.6094H169.1484V32.5H171.9297V16.5H169.0938V22.4844H168.9766C168.5469 21.6172 167.6641 20.3438 165.5469 20.3438C162.7734 20.3438 160.5938 22.5156 160.5938 26.5156C160.5938 30.4688 162.7109 32.7109 165.5391 32.7109ZM166.3281 30.3906C164.4609 30.3906 163.4766 28.75 163.4766 26.5C163.4766 24.2656 164.4453 22.6641 166.3281 22.6641C168.1484 22.6641 169.1484 24.1719 169.1484 26.5C169.1484 28.8281 168.1328 30.3906 166.3281 30.3906ZM182.6016 27.4531C182.6016 29.2812 181.2969 30.1875 180.0469 30.1875C178.6875 30.1875 177.7812 29.2266 177.7812 27.7031V20.5H174.9531V28.1406C174.9531 31.0234 176.5938 32.6562 178.9531 32.6562C180.75 32.6562 182.0156 31.7109 182.5625 30.3672H182.6875V32.5H185.4297V20.5H182.6016ZM191.1641 16.5H188.3359V32.5H191.1641ZM199.3828 32.7344C202.1797 32.7344 204.1016 31.3672 204.6016 29.2812L201.9609 28.9844C201.5781 30.0 200.6406 30.5312 199.4219 30.5312C197.5938 30.5312 196.3828 29.3281 196.3594 27.2734H204.7188V26.4062C204.7188 22.1953 202.1875 20.3438 199.2344 20.3438C195.7969 20.3438 193.5547 22.8672 193.5547 26.5703C193.5547 30.3359 195.7656 32.7344 199.3828 32.7344ZM196.3672 25.3672C196.4531 23.8359 197.5859 22.5469 199.2734 22.5469C200.8984 22.5469 201.9922 23.7344 202.0078 25.3672ZM216.5938 23.6719C216.2031 21.6406 214.5781 20.3438 211.7656 20.3438C208.875 20.3438 206.9062 21.7656 206.9141 23.9844C206.9062 25.7344 207.9844 26.8906 210.2891 27.3672L212.3359 27.7969C213.4375 28.0391 213.9531 28.4844 213.9531 29.1641C213.9531 29.9844 213.0625 30.6016 211.7188 30.6016C210.4219 30.6016 209.5781 30.0391 209.3359 28.9609L206.5781 29.2266C206.9297 31.4297 208.7812 32.7344 211.7266 32.7344C214.7266 32.7344 216.8438 31.1797 216.8516 28.9062C216.8438 27.1953 215.7422 26.1484 213.4766 25.6562L211.4297 25.2188C210.2109 24.9453 209.7266 24.5234 209.7344 23.8281C209.7266 23.0156 210.625 22.4531 211.8047 22.4531C213.1094 22.4531 213.7969 23.1641 214.0156 23.9531ZM224.7734 16.5V32.5H227.5547V21.4844H227.7031L232.125 32.4531H234.2031L238.625 21.5078H238.7734V32.5H241.5547V16.5H238.0078L233.2578 28.0938H233.0703L228.3203 16.5ZM248.0391 32.7422C249.9219 32.7422 251.0469 31.8594 251.5625 30.8516H251.6562V32.5H254.375V24.4688C254.375 21.2969 251.7891 20.3438 249.5 20.3438C246.9766 20.3438 245.0391 21.4688 244.4141 23.6562L247.0547 24.0312C247.3359 23.2109 248.1328 22.5078 249.5156 22.5078C250.8281 22.5078 251.5469 23.1797 251.5469 24.3594V24.4062C251.5469 25.2188 250.6953 25.2578 248.5781 25.4844C246.25 25.7344 244.0234 26.4297 244.0234 29.1328C244.0234 31.4922 245.75 32.7422 248.0391 32.7422ZM248.7734 30.6641C247.5938 30.6641 246.75 30.125 246.75 29.0859C246.75 28.0 247.6953 27.5469 248.9609 27.3672C249.7031 27.2656 251.1875 27.0781 251.5547 26.7812V28.1953C251.5547 29.5312 250.4766 30.6641 248.7734 30.6641ZM262.4609 32.7344C265.4766 32.7344 267.3984 30.9453 267.6016 28.3984H264.8984C264.6562 29.6875 263.7266 30.4297 262.4844 30.4297C260.7188 30.4297 259.5781 28.9531 259.5781 26.5C259.5781 24.0781 260.7422 22.625 262.4844 22.625C263.8438 22.625 264.6797 23.5 264.8984 24.6562H267.6016C267.4062 22.0547 265.375 20.3438 262.4453 20.3438C258.9297 20.3438 256.7109 22.8828 256.7109 26.5469C256.7109 30.1797 258.875 32.7344 262.4609 32.7344ZM269.9297 32.5H272.7578V25.4453C272.7578 23.9219 273.9062 22.8438 275.4609 22.8438C275.9375 22.8438 276.5312 22.9297 276.7734 23.0078V20.4062C276.5156 20.3594 276.0703 20.3281 275.7578 20.3281C274.3828 20.3281 273.2344 21.1094 272.7969 22.5H272.6719V20.5H269.9297ZM283.8906 32.7344C287.4062 32.7344 289.6406 30.2578 289.6406 26.5469C289.6406 22.8281 287.4062 20.3438 283.8906 20.3438C280.375 20.3438 278.1406 22.8281 278.1406 26.5469C278.1406 30.2578 280.375 32.7344 283.8906 32.7344ZM283.9062 30.4688C281.9609 30.4688 281.0078 28.7344 281.0078 26.5391C281.0078 24.3438 281.9609 22.5859 283.9062 22.5859C285.8203 22.5859 286.7734 24.3438 286.7734 26.5391C286.7734 28.7344 285.8203 30.4688 283.9062 30.4688ZM301.5156 23.6719C301.125 21.6406 299.5 20.3438 296.6875 20.3438C293.7969 20.3438 291.8281 21.7656 291.8359 23.9844C291.8281 25.7344 292.9062 26.8906 295.2109 27.3672L297.2578 27.7969C298.3594 28.0391 298.875 28.4844 298.875 29.1641C298.875 29.9844 297.9844 30.6016 296.6406 30.6016C295.3438 30.6016 294.5 30.0391 294.2578 28.9609L291.5 29.2266C291.8516 31.4297 293.7031 32.7344 296.6484 32.7344C299.6484 32.7344 301.7656 31.1797 301.7734 28.9062C301.7656 27.1953 300.6641 26.1484 298.3984 25.6562L296.3516 25.2188C295.1328 24.9453 294.6484 24.5234 294.6562 23.8281C294.6484 23.0156 295.5469 22.4531 296.7266 22.4531C298.0312 22.4531 298.7188 23.1641 298.9375 23.9531Z" fill="#63607A"/>
|
|
14
|
+
<defs>
|
|
15
|
+
<radialGradient id="paint0_radial_748_204" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(4 4) rotate(90) scale(32)">
|
|
16
|
+
<stop stop-color="white"/>
|
|
17
|
+
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
|
18
|
+
</radialGradient>
|
|
19
|
+
<clipPath id="clip0_748_204">
|
|
20
|
+
<rect width="48" height="48" rx="10" fill="white"/>
|
|
21
|
+
</clipPath>
|
|
22
|
+
</defs>
|
|
23
|
+
</svg>
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
release_type:
|
|
7
|
+
description: Release type
|
|
8
|
+
type: choice
|
|
9
|
+
required: true
|
|
10
|
+
default: patch
|
|
11
|
+
options:
|
|
12
|
+
- patch
|
|
13
|
+
- minor
|
|
14
|
+
- major
|
|
15
|
+
- prepatch
|
|
16
|
+
- preminor
|
|
17
|
+
- premajor
|
|
18
|
+
- prerelease
|
|
19
|
+
|
|
20
|
+
concurrency:
|
|
21
|
+
group: publish-${{ github.workflow }}
|
|
22
|
+
cancel-in-progress: false
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
publish:
|
|
26
|
+
name: Build and publish to npm
|
|
27
|
+
# Builds the native macOS tool binary, so it must run on macOS.
|
|
28
|
+
# The package declares swift-tools-version 6.2, which requires Xcode 26+.
|
|
29
|
+
runs-on: macos-26
|
|
30
|
+
permissions:
|
|
31
|
+
# Required for npm trusted publishing (OIDC) and provenance.
|
|
32
|
+
id-token: write
|
|
33
|
+
# Required to push the version bump commit/tag and create the release.
|
|
34
|
+
contents: write
|
|
35
|
+
steps:
|
|
36
|
+
- name: Checkout
|
|
37
|
+
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
|
38
|
+
with:
|
|
39
|
+
# The default token lets gh create the release and push the bump
|
|
40
|
+
# commit/tag. Note: commits pushed with GITHUB_TOKEN do NOT trigger
|
|
41
|
+
# other workflows (e.g. the Swift CI), by GitHub's design.
|
|
42
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
43
|
+
|
|
44
|
+
- name: Setup Node
|
|
45
|
+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
|
46
|
+
with:
|
|
47
|
+
node-version: 22
|
|
48
|
+
registry-url: https://registry.npmjs.org
|
|
49
|
+
|
|
50
|
+
- name: Update npm
|
|
51
|
+
# Trusted publishing requires npm >= 11.5.1.
|
|
52
|
+
run: npm install -g npm@latest
|
|
53
|
+
|
|
54
|
+
- name: Configure git
|
|
55
|
+
run: |
|
|
56
|
+
git config user.name "expo-bot"
|
|
57
|
+
git config user.email "expo-bot@users.noreply.github.com"
|
|
58
|
+
|
|
59
|
+
- name: Bump version
|
|
60
|
+
id: bump
|
|
61
|
+
# Only edit package.json here; the commit, tag and release are created
|
|
62
|
+
# at the end so a failed build/publish leaves the branch untouched.
|
|
63
|
+
run: |
|
|
64
|
+
version=$(npm version "${{ inputs.release_type }}" --no-git-tag-version)
|
|
65
|
+
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
66
|
+
echo "Bumping to $version"
|
|
67
|
+
|
|
68
|
+
- name: Select Xcode
|
|
69
|
+
# Pin to an Xcode that ships Swift 6.2 (required by Package.swift).
|
|
70
|
+
run: sudo xcode-select -switch /Applications/Xcode_26.4.1.app
|
|
71
|
+
|
|
72
|
+
- name: Cache SwiftPM build
|
|
73
|
+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
|
74
|
+
with:
|
|
75
|
+
path: apple/.build
|
|
76
|
+
key: spm-${{ github.repository }}-${{ runner.os }}-${{ hashFiles('apple/Package.resolved') }}
|
|
77
|
+
restore-keys: |
|
|
78
|
+
spm-${{ github.repository }}-${{ runner.os }}-
|
|
79
|
+
|
|
80
|
+
- name: Resolve dependencies
|
|
81
|
+
run: swift package resolve
|
|
82
|
+
working-directory: apple
|
|
83
|
+
|
|
84
|
+
- name: Install dependencies
|
|
85
|
+
# The wrapper's `prepublishOnly` build needs `tsc`; the tool binary needs none.
|
|
86
|
+
run: npm install
|
|
87
|
+
|
|
88
|
+
- name: Build release tool
|
|
89
|
+
# Runs apple/build.js: builds the release plugin binary,
|
|
90
|
+
# copies it to apple/ExpoModulesMacros, and strips it.
|
|
91
|
+
run: npm run build
|
|
92
|
+
|
|
93
|
+
- name: Publish
|
|
94
|
+
# Authentication is handled via OIDC trusted publishing — no token needed.
|
|
95
|
+
# npm generates provenance automatically when publishing via OIDC.
|
|
96
|
+
run: npm publish --access public
|
|
97
|
+
|
|
98
|
+
# Everything below only runs once the publish above has succeeded.
|
|
99
|
+
|
|
100
|
+
- name: Commit, tag and push
|
|
101
|
+
run: |
|
|
102
|
+
version="${{ steps.bump.outputs.version }}"
|
|
103
|
+
git commit -am "Release $version"
|
|
104
|
+
# Use an annotated tag so `git push --follow-tags` actually pushes it
|
|
105
|
+
# (--follow-tags ignores lightweight tags).
|
|
106
|
+
git tag -a "$version" -m "Release $version"
|
|
107
|
+
git push --follow-tags origin HEAD
|
|
108
|
+
|
|
109
|
+
- name: Create GitHub release
|
|
110
|
+
env:
|
|
111
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
112
|
+
# Tag prerelease versions (those containing a hyphen) as prereleases.
|
|
113
|
+
run: |
|
|
114
|
+
version="${{ steps.bump.outputs.version }}"
|
|
115
|
+
prerelease=""
|
|
116
|
+
case "$version" in
|
|
117
|
+
*-*) prerelease="--prerelease" ;;
|
|
118
|
+
esac
|
|
119
|
+
gh release create "$version" \
|
|
120
|
+
--title "$version" \
|
|
121
|
+
--generate-notes \
|
|
122
|
+
$prerelease
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: Swift
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
workflow_dispatch: {}
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
defaults:
|
|
15
|
+
run:
|
|
16
|
+
working-directory: apple
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
build-and-test:
|
|
20
|
+
name: Build & test
|
|
21
|
+
# The package declares swift-tools-version 6.2, which requires Xcode 26+.
|
|
22
|
+
runs-on: macos-26
|
|
23
|
+
steps:
|
|
24
|
+
- name: Checkout
|
|
25
|
+
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
|
26
|
+
|
|
27
|
+
- name: Select Xcode
|
|
28
|
+
# Pin to an Xcode that ships Swift 6.2 (required by Package.swift).
|
|
29
|
+
run: sudo xcode-select -switch /Applications/Xcode_26.4.1.app
|
|
30
|
+
|
|
31
|
+
- name: Cache SwiftPM build
|
|
32
|
+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
|
33
|
+
with:
|
|
34
|
+
path: apple/.build
|
|
35
|
+
key: spm-${{ github.repository }}-${{ runner.os }}-${{ hashFiles('apple/Package.resolved') }}
|
|
36
|
+
restore-keys: |
|
|
37
|
+
spm-${{ github.repository }}-${{ runner.os }}-
|
|
38
|
+
|
|
39
|
+
- name: Resolve dependencies
|
|
40
|
+
run: swift package resolve
|
|
41
|
+
|
|
42
|
+
- name: Build release tool
|
|
43
|
+
# Runs `npm run build` (apple/build.js): builds the universal
|
|
44
|
+
# (arm64 + x86_64) release plugin binary, copies it to
|
|
45
|
+
# apple/ExpoModulesMacros, and strips it.
|
|
46
|
+
working-directory: ${{ github.workspace }}
|
|
47
|
+
run: npm run build
|
|
48
|
+
|
|
49
|
+
- name: Verify universal binary
|
|
50
|
+
run: |
|
|
51
|
+
archs="$(lipo -archs ExpoModulesMacros)"
|
|
52
|
+
echo "Architectures: $archs"
|
|
53
|
+
case "$archs" in *arm64*) ;; *) echo "Missing arm64 slice"; exit 1;; esac
|
|
54
|
+
case "$archs" in *x86_64*) ;; *) echo "Missing x86_64 slice"; exit 1;; esac
|
|
55
|
+
arch -arm64 ./ExpoModulesMacros < /dev/null
|
|
56
|
+
arch -x86_64 ./ExpoModulesMacros < /dev/null
|
|
57
|
+
# With arguments the same binary runs the scanner CLI instead of the plugin server.
|
|
58
|
+
arch -arm64 ./ExpoModulesMacros --help > /dev/null
|
|
59
|
+
arch -x86_64 ./ExpoModulesMacros --help > /dev/null
|
|
60
|
+
|
|
61
|
+
- name: Test
|
|
62
|
+
run: swift test -v
|
|
63
|
+
|
|
64
|
+
- name: Typecheck the TypeScript wrapper
|
|
65
|
+
working-directory: ${{ github.workspace }}
|
|
66
|
+
run: |
|
|
67
|
+
npm install
|
|
68
|
+
npm run typecheck
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
`expo-modules-macros` is the Swift compiler plugin that implements the macros declared by `expo-modules-core`, plus a source scanner CLI built into the same executable. Read `README.md` first for what each macro does and how the plugin reaches the compiler.
|
|
4
|
+
|
|
5
|
+
## Layout
|
|
6
|
+
|
|
7
|
+
- `apple/Package.swift`: the SwiftPM package. The test targets are declared only when `apple/Tests` exists, because the published npm package leaves it out.
|
|
8
|
+
- `apple/Sources/ExpoModulesMacros`: the macro implementations. `Plugin.swift` registers every macro in `providingMacros` and holds the entry point that sends any invocation with arguments to the scanner CLI.
|
|
9
|
+
- `apple/Sources/ExpoModulesScanner`: the scanner library. `Modules/` implements `scan-modules` (autolinking), `Exports/` implements `scan-exports` (type generation), `Core/` holds the shared parsing and `#if` evaluation, and `CLI.swift` is the command-line front end.
|
|
10
|
+
- `apple/Sources/ExpoModulesOptimized`: declarations for the `@OptimizedFunction` macro.
|
|
11
|
+
- `apple/Tests`: `ExpoModulesMacrosTests` (expansion tests) and `ExpoModulesScannerTests`.
|
|
12
|
+
- `apple/PodTests`: a stub test so that `expo/expo` native tests can install this package as a pod. Do not add real tests here.
|
|
13
|
+
- `src/`: the TypeScript wrapper around the scanner CLI. `types.ts` mirrors the Swift `Codable` output types by hand.
|
|
14
|
+
- `apple/build.js`: builds the universal release binary that is committed under `apple/`.
|
|
15
|
+
|
|
16
|
+
## Commands
|
|
17
|
+
|
|
18
|
+
Swift 6.2 is required (Xcode 26 or newer).
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
cd apple && swift build # debug build
|
|
22
|
+
cd apple && swift test # all Swift tests
|
|
23
|
+
npm run typecheck # TypeScript wrapper
|
|
24
|
+
npm run build # universal release binary (slow; uses Rosetta for x86_64)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
CI (`.github/workflows/swift.yml`) runs the release build, checks both binary slices, then runs `swift test` and `npm run typecheck`.
|
|
28
|
+
|
|
29
|
+
## Conventions
|
|
30
|
+
|
|
31
|
+
- Swift uses 2-space indentation. Write new doc comments as `///` line comments, not `/** */` blocks.
|
|
32
|
+
- Tests use Swift Testing (`import Testing`, `@Test`) with backtick-quoted descriptive names, for example ``func `Prunes .build, Pods, .git, and node_modules directories`()``.
|
|
33
|
+
- Macro tests compare full expansions with `assertMacroExpansion` from `SwiftSyntaxMacrosGenericTestSupport`, using `indentationWidth: .spaces(2)`. Each test file wraps it in a local `assertExpansion` helper.
|
|
34
|
+
- Scanner tests reach internal API with `@testable import ExpoModulesScanner`. Do not make scanner types `public` only for tests.
|
|
35
|
+
- `@JS` applies to functions, properties and initializers. Do not write code or comments that assume it marks only functions.
|
|
36
|
+
- Code comments describe the code as it is. Do not refer to open PRs, branches or planned work.
|
|
37
|
+
|
|
38
|
+
## Changing macros
|
|
39
|
+
|
|
40
|
+
- The scanner re-implements the macros' naming and member rules on the syntax tree; it does not call the macro code. When a macro changes which members it binds or how it names them (the `@JS` name override, the `on` prefix `@Event` strips, which properties `@Record` treats as fields), change `scan-exports` to match, or generated TypeScript types drift from the runtime.
|
|
41
|
+
- The scanner only parses files that match the pre-filter built by `macroAttributeRegex` in `Core/SourceScan.swift`. A new attribute or conformance the scanner must detect has to be added there, or files that use it are skipped without an error.
|
|
42
|
+
- A new macro needs: the implementation in `apple/Sources/ExpoModulesMacros`, an entry in `providingMacros` in `Plugin.swift`, an expansion test file, the `#externalMacro` declaration in `expo-modules-core`, and an entry in the macro list in `README.md`.
|
|
43
|
+
|
|
44
|
+
## Contracts with other packages
|
|
45
|
+
|
|
46
|
+
- **Macro declarations live in `expo-modules-core`** (`ios/Core/ExpoModulesMacros.swift` in `expo/expo`), as `#externalMacro(module: "ExpoModulesMacros", type: ...)`. Adding a macro, renaming a macro type or changing a macro's signature needs a matching edit there, and the type must be listed in `providingMacros` in `Plugin.swift`.
|
|
47
|
+
- **Generated code calls `expo-modules-core` API.** An expansion that uses a new core symbol only works with a core version that has it.
|
|
48
|
+
- **Scanner output is versioned.** `scanModulesSchemaVersion` (`Modules/ScanModules.swift`) and `scanExportsSchemaVersion` (`Exports/ExportedSurface.swift`) change independently. When the output shape of a command changes, bump its version and update the matching `SUPPORTED_SCAN_*_SCHEMA_VERSION` constant and mirror types in `src/types.ts`. `expo-modules-autolinking` also checks the `scan-modules` version.
|
|
49
|
+
- **The binary path is part of the contract.** `expo-modules-autolinking` resolves this package from `expo-modules-core` and passes `-load-plugin-executable <package>/apple/<binary>#ExpoModulesMacros` to the compiler. The scanner wrapper in autolinking uses the same path. Renaming or moving the binary needs a matching change in `expo/expo`.
|
|
50
|
+
|
|
51
|
+
## Releases
|
|
52
|
+
|
|
53
|
+
- Do not rebuild or commit the binary under `apple/` in a feature change. Only the **Publish** workflow (`.github/workflows/publish.yml`, manual) rebuilds it, and it commits the result as `Release vX.Y.Z` after the npm publish succeeds.
|
|
54
|
+
- Do not edit the `version` in `package.json` by hand. The Publish workflow bumps it.
|
|
55
|
+
- Commit and PR titles are short and imperative, with code identifiers in backticks, for example ``Report `@Union` types in `scan-exports` ``.
|
|
56
|
+
|
|
57
|
+
## Installed copies
|
|
58
|
+
|
|
59
|
+
In `node_modules`, the compiler runs the prebuilt binary `apple/ExpoModulesMacros`; editing the Swift sources there has no effect. Macro and scanner fixes belong in this repository and ship in a new release. The TypeScript wrapper ships compiled in `build/`, since `src/` is not published.
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
|
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,119 @@
|
|
|
1
|
+
<p>
|
|
2
|
+
<a href="https://docs.expo.dev/modules/">
|
|
3
|
+
<img
|
|
4
|
+
src=".github/resources/expo-modules-macros.svg"
|
|
5
|
+
alt="expo-modules-macros"
|
|
6
|
+
height="64" />
|
|
7
|
+
</a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
`expo-modules-macros` is the Swift compiler plugin behind the Expo Modules API. It implements the macros that [`expo-modules-core`](https://github.com/expo/expo/tree/main/packages/expo-modules-core) declares, so a module author writes plain Swift declarations and the plugin synthesizes the code that binds them to JavaScript.
|
|
11
|
+
|
|
12
|
+
The same executable doubles as a source scanner CLI.
|
|
13
|
+
|
|
14
|
+
# Installation
|
|
15
|
+
|
|
16
|
+
This package is not meant to be installed directly. It is a dependency of `expo-modules-core`, so every Expo project already has it. The published package contains a prebuilt universal (arm64 + x86_64) macOS binary at `apple/ExpoModulesMacros`, so consumers never build the plugin themselves.
|
|
17
|
+
|
|
18
|
+
# Macros
|
|
19
|
+
|
|
20
|
+
- **`@ExpoModule(_ name: String? = nil, classes: [Any.Type] = [])`** on a class. Turns the class into a module: binds its `@JS` members into the module's JavaScript object and resolves the module name from the argument, falling back to the class name. It also synthesizes everything inheriting from `Module` used to provide, so a module class can carry any superclass, or none.
|
|
21
|
+
- **`@JS(_ jsName: String? = nil, _ options: JSOptions...)`** on a member of a module or shared object. Marks a function, property or initializer for export. `@ExpoModule` and `@SharedObject` bind each marked member straight into the JavaScript object, with the argument decoding, the call and the result encoding inlined, so there is no dynamic per-call path. The JS name defaults to the Swift name; pass a string to override it. The macro also checks that every type crossing the boundary is convertible in the direction it travels, so a bad type is reported on the author's own declaration rather than on the enclosing type. The `.concurrent` option moves an `async` body off the JavaScript thread while still decoding and encoding on it.
|
|
22
|
+
- **`@Event(_ name: String? = nil, sync: Bool = false)`** on a function-typed `var`. Expands the property into a closure that emits the event, so calling the property sends it to JavaScript with the closure's parameter as the payload. The JS name defaults to the property name with a leading `on` stripped. `sync: true` dispatches inline instead of asynchronously.
|
|
23
|
+
- **`@SharedObject(_ name: String? = nil)`** on a `SharedObject` subclass. Collects the class's `@JS` members into a class definition that a module exposes through `@ExpoModule(classes:)`.
|
|
24
|
+
- **`@Record()`** on a record type. Treats every non-static, non-private, non-computed stored property as a field, with no per-field wrapper, and synthesizes the memberwise initializer, the conversions in both directions, and the `Record` conformance. Requiredness is inferred: a default value makes a field optional, an optional type makes it nullable and optional.
|
|
25
|
+
- **`@Union()`** on an enum whose cases each carry one associated value. Models a TypeScript union. Synthesizes the conversions in both directions, a typed accessor per payload type, and the `JavaScriptDecodable` and `JavaScriptEncodable` conformances. Decoding is ordered: the first case whose payload decodes wins, so the more specific case goes first.
|
|
26
|
+
|
|
27
|
+
How that looks in a module:
|
|
28
|
+
|
|
29
|
+
```swift
|
|
30
|
+
import ExpoModulesCore
|
|
31
|
+
|
|
32
|
+
@ExpoModule(classes: [Cache.self])
|
|
33
|
+
public final class MyModule {
|
|
34
|
+
@JS
|
|
35
|
+
func greet(name: String) -> String {
|
|
36
|
+
"Hi, \(name)"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@JS("doWork")
|
|
40
|
+
func performWork() async throws { ... }
|
|
41
|
+
|
|
42
|
+
@Event
|
|
43
|
+
var onProgress: (ProgressEvent) -> Void
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@SharedObject
|
|
47
|
+
final class Cache: SharedObject {
|
|
48
|
+
@JS
|
|
49
|
+
init(name: String) { ... }
|
|
50
|
+
|
|
51
|
+
@JS
|
|
52
|
+
func get(_ key: String) -> String? { ... }
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The author-facing documentation for each macro lives next to its declaration in `expo-modules-core`, in `ios/Core/ExpoModulesMacros.swift`. This repository holds the implementations.
|
|
57
|
+
|
|
58
|
+
# Scanner
|
|
59
|
+
|
|
60
|
+
The Swift compiler launches a plugin executable with no arguments and speaks the plugin protocol over stdin, so the binary treats any argument as a scanner invocation instead:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
ExpoModulesMacros <subcommand> [options] <path> [<path> ...]
|
|
64
|
+
|
|
65
|
+
subcommands:
|
|
66
|
+
scan-modules fast scan for top-level @ExpoModule types (autolinking)
|
|
67
|
+
scan-exports deep scan of the full JS-exported surface (type generation)
|
|
68
|
+
|
|
69
|
+
options (scan-modules only):
|
|
70
|
+
--platform <os> evaluate '#if os(...)' against this platform
|
|
71
|
+
--define <flag> treat a conditional compilation flag as set; repeatable
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Each path is a `.swift` file or a directory, scanned recursively for `.swift` files. Both subcommands print a JSON report to stdout, each carrying its own `schemaVersion` so a consumer can check it understands the shape before trusting it. The two versions are independent: the commands serve different consumers and change for different reasons.
|
|
75
|
+
|
|
76
|
+
# TypeScript wrapper
|
|
77
|
+
|
|
78
|
+
Node consumers can call the scanner through this package instead of locating the binary and shelling out themselves:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { scanModules, scanExports } from 'expo-modules-macros';
|
|
82
|
+
|
|
83
|
+
const { modules, warnings } = await scanModules(['ios/'], { defines: ['DEBUG'] });
|
|
84
|
+
const { exports } = await scanExports(['ios/']);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The binary is a compiled executable, so each call still spawns a process. What the wrapper owns is the part consumers would otherwise duplicate: resolving the shipped binary, building the arguments, parsing the JSON, checking `schemaVersion`, and turning a non-zero exit into a `ScannerError`. The result types are hand-written mirrors of the Swift `Codable` types, which is what the version check guards against drifting.
|
|
88
|
+
|
|
89
|
+
# How the plugin reaches the compiler
|
|
90
|
+
|
|
91
|
+
`expo-modules-core` declares the macro signatures with `#externalMacro(module: "ExpoModulesMacros", type: …)`. During `pod install`, `expo-modules-autolinking` resolves this package from the core package and appends
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
-Xfrontend -load-plugin-executable -Xfrontend <plugin>/apple/ExpoModulesMacros#ExpoModulesMacros
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
to `OTHER_SWIFT_FLAGS` for `ExpoModulesCore`, every pod that depends on it, and their test specs. Expo's SPM prebuilds pass the same flag when they generate `Package.swift`, so both build systems load the same binary.
|
|
98
|
+
|
|
99
|
+
The module and type names in `#externalMacro` must stay in sync with `apple/Sources/ExpoModulesMacros/Plugin.swift`.
|
|
100
|
+
|
|
101
|
+
# Development
|
|
102
|
+
|
|
103
|
+
Requires macOS 13 or newer and a toolchain with Swift 6.2, which means Xcode 26 or newer.
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
cd apple
|
|
107
|
+
swift build
|
|
108
|
+
swift test
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`npm run build` runs `apple/build.js`, which builds the release binary for arm64 and x86_64, merges the slices into `apple/ExpoModulesMacros` with `lipo`, strips it, and verifies both slices are present. SwiftPM only builds macro tools for the host architecture, so the x86_64 slice is produced by running the toolchain under Rosetta; the script installs Rosetta if it is missing. The resulting binary is committed to the repository.
|
|
112
|
+
|
|
113
|
+
# Releasing
|
|
114
|
+
|
|
115
|
+
The **Publish** workflow is manual (`workflow_dispatch`) and takes a release type. It bumps the version, builds the universal binary, and publishes to npm through OIDC trusted publishing. The commit, tag and GitHub release are created only after the publish succeeds, so a failed build leaves the branch untouched.
|
|
116
|
+
|
|
117
|
+
# Contributing
|
|
118
|
+
|
|
119
|
+
Contributions are very welcome! Please refer to the guidelines described in the [contributing guide](https://github.com/expo/expo#contributing).
|
|
Binary file
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"originHash" : "4832fa479257148c1acb46952c02540c156db6e744797638db69be31154d5ad2",
|
|
3
|
+
"pins" : [
|
|
4
|
+
{
|
|
5
|
+
"identity" : "swift-syntax",
|
|
6
|
+
"kind" : "remoteSourceControl",
|
|
7
|
+
"location" : "https://github.com/swiftlang/swift-syntax.git",
|
|
8
|
+
"state" : {
|
|
9
|
+
"revision" : "4799286537280063c85a32f09884cfbca301b1a1",
|
|
10
|
+
"version" : "602.0.0"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"version" : 3
|
|
15
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// swift-tools-version: 6.2
|
|
2
|
+
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
|
3
|
+
|
|
4
|
+
import CompilerPluginSupport
|
|
5
|
+
import Foundation
|
|
6
|
+
import PackageDescription
|
|
7
|
+
|
|
8
|
+
let package = Package(
|
|
9
|
+
name: "ExpoModulesMacros",
|
|
10
|
+
platforms: [.macOS(.v13)],
|
|
11
|
+
dependencies: [
|
|
12
|
+
.package(url: "https://github.com/swiftlang/swift-syntax.git", from: "602.0.0-latest")
|
|
13
|
+
],
|
|
14
|
+
targets: [
|
|
15
|
+
// The plugin executable doubles as the scanner CLI: the compiler launches it without arguments
|
|
16
|
+
// and speaks the plugin protocol over stdin, while an invocation with arguments dispatches into
|
|
17
|
+
// `ScannerCLI` (see the entry point in Plugin.swift). Sharing the binary keeps the package to a
|
|
18
|
+
// single shipped executable; the scanner adds little on top of the SwiftSyntax the macros
|
|
19
|
+
// already link.
|
|
20
|
+
.macro(
|
|
21
|
+
name: "ExpoModulesMacros",
|
|
22
|
+
dependencies: [
|
|
23
|
+
"ExpoModulesScanner",
|
|
24
|
+
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
|
|
25
|
+
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
|
|
26
|
+
]
|
|
27
|
+
),
|
|
28
|
+
.target(
|
|
29
|
+
name: "ExpoModulesScanner",
|
|
30
|
+
dependencies: [
|
|
31
|
+
.product(name: "SwiftSyntax", package: "swift-syntax"),
|
|
32
|
+
.product(name: "SwiftParser", package: "swift-syntax"),
|
|
33
|
+
.product(name: "SwiftIfConfig", package: "swift-syntax"),
|
|
34
|
+
]
|
|
35
|
+
),
|
|
36
|
+
]
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
// The Tests directory is excluded from the published npm package,
|
|
40
|
+
// so only declare the test target when building from the repository.
|
|
41
|
+
if FileManager.default.fileExists(atPath: Context.packageDirectory + "/Tests") {
|
|
42
|
+
package.targets.append(
|
|
43
|
+
.testTarget(
|
|
44
|
+
name: "ExpoModulesMacrosTests",
|
|
45
|
+
dependencies: [
|
|
46
|
+
"ExpoModulesMacros",
|
|
47
|
+
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
|
|
48
|
+
.product(name: "SwiftSyntaxMacrosGenericTestSupport", package: "swift-syntax"),
|
|
49
|
+
]
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
package.targets.append(
|
|
53
|
+
.testTarget(
|
|
54
|
+
name: "ExpoModulesScannerTests",
|
|
55
|
+
dependencies: [
|
|
56
|
+
"ExpoModulesScanner",
|
|
57
|
+
.product(name: "SwiftParser", package: "swift-syntax"),
|
|
58
|
+
]
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
}
|