@tinglinzh/react-native-markdownview 0.4.0 → 0.5.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/app.plugin.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('./plugin/index.js');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinglinzh/react-native-markdownview",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "React Native wrapper for MarkdownView — native iOS/macOS markdown rendering with GFM, syntax highlighting, LaTeX math, and unified diff support",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -14,10 +14,13 @@
14
14
  "types": "./lib/typescript/src/index.d.ts"
15
15
  }
16
16
  },
17
+ "plugin": "app.plugin.js",
17
18
  "files": [
18
19
  "src",
19
20
  "lib",
20
21
  "ios",
22
+ "plugin",
23
+ "app.plugin.js",
21
24
  "react-native-markdownview.podspec",
22
25
  "Package.swift"
23
26
  ],
@@ -37,9 +40,15 @@
37
40
  "author": "",
38
41
  "license": "MIT",
39
42
  "peerDependencies": {
43
+ "@expo/config-plugins": ">=7.0.0",
40
44
  "react": "*",
41
45
  "react-native": "*"
42
46
  },
47
+ "peerDependenciesMeta": {
48
+ "@expo/config-plugins": {
49
+ "optional": true
50
+ }
51
+ },
43
52
  "devDependencies": {
44
53
  "@types/react": "^18.3.28",
45
54
  "react": "18.3.1",
@@ -0,0 +1,139 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Expo Config Plugin — adds MarkdownView as an SPM dependency to the
5
+ * host app's Xcode project during `expo prebuild`.
6
+ *
7
+ * Without this step the pod can't compile `import MarkdownView` because
8
+ * CocoaPods has no way to pull in Swift Package Manager-only packages.
9
+ *
10
+ * Usage in app.config.ts / app.json:
11
+ * plugins: ['@tinglinzh/react-native-markdownview']
12
+ */
13
+
14
+ const { withXcodeProject } = require('@expo/config-plugins');
15
+ const crypto = require('crypto');
16
+
17
+ const MARKDOWNVIEW_REPO = 'https://github.com/HumanInterfaceDesign/MarkdownView';
18
+ const MARKDOWNVIEW_BRANCH = 'main';
19
+ const PRODUCT_NAME = 'MarkdownView';
20
+
21
+ /**
22
+ * Deterministic 24-char uppercase hex UUID derived from a seed string.
23
+ * Using a fixed seed means `prebuild` is idempotent — re-running it won't
24
+ * add duplicate entries to the pbxproj file.
25
+ */
26
+ function uuid(seed) {
27
+ return crypto.createHash('sha256').update(seed).digest('hex').toUpperCase().slice(0, 24);
28
+ }
29
+
30
+ const PKG_REF_UUID = uuid('RNMarkdownView-XCRemoteSwiftPackageReference');
31
+ const PROD_DEP_UUID = uuid('RNMarkdownView-XCSwiftPackageProductDependency');
32
+ const BUILD_FILE_UUID = uuid('RNMarkdownView-PBXBuildFile');
33
+
34
+ /**
35
+ * @param {import('@expo/config-plugins').ExpoConfig} config
36
+ */
37
+ const withMarkdownViewSPM = (config) => {
38
+ return withXcodeProject(config, (modConfig) => {
39
+ const project = modConfig.modResults;
40
+ const pbx = project.hash.project.objects;
41
+
42
+ // ── Guard: already added? ──────────────────────────────────────────────
43
+ const existingRefs = pbx['XCRemoteSwiftPackageReference'] || {};
44
+ const alreadyAdded = Object.values(existingRefs).some(
45
+ (ref) =>
46
+ ref &&
47
+ typeof ref === 'object' &&
48
+ typeof ref.repositoryURL === 'string' &&
49
+ ref.repositoryURL.includes('MarkdownView'),
50
+ );
51
+ if (alreadyAdded) return modConfig;
52
+
53
+ // ── 1. XCRemoteSwiftPackageReference ──────────────────────────────────
54
+ pbx['XCRemoteSwiftPackageReference'] = pbx['XCRemoteSwiftPackageReference'] || {};
55
+ pbx['XCRemoteSwiftPackageReference'][PKG_REF_UUID] = {
56
+ isa: 'XCRemoteSwiftPackageReference',
57
+ repositoryURL: `"${MARKDOWNVIEW_REPO}"`,
58
+ requirement: { branch: MARKDOWNVIEW_BRANCH, kind: 'branch' },
59
+ };
60
+ pbx['XCRemoteSwiftPackageReference'][`${PKG_REF_UUID}_comment`] =
61
+ `XCRemoteSwiftPackageReference "${PRODUCT_NAME}"`;
62
+
63
+ // ── 2. XCSwiftPackageProductDependency ────────────────────────────────
64
+ pbx['XCSwiftPackageProductDependency'] = pbx['XCSwiftPackageProductDependency'] || {};
65
+ pbx['XCSwiftPackageProductDependency'][PROD_DEP_UUID] = {
66
+ isa: 'XCSwiftPackageProductDependency',
67
+ package: PKG_REF_UUID,
68
+ productName: PRODUCT_NAME,
69
+ };
70
+ pbx['XCSwiftPackageProductDependency'][`${PROD_DEP_UUID}_comment`] = PRODUCT_NAME;
71
+
72
+ // ── 3. PBXBuildFile ───────────────────────────────────────────────────
73
+ pbx['PBXBuildFile'] = pbx['PBXBuildFile'] || {};
74
+ pbx['PBXBuildFile'][BUILD_FILE_UUID] = {
75
+ isa: 'PBXBuildFile',
76
+ productRef: PROD_DEP_UUID,
77
+ };
78
+ pbx['PBXBuildFile'][`${BUILD_FILE_UUID}_comment`] = `${PRODUCT_NAME} in Frameworks`;
79
+
80
+ // ── 4. PBXProject.packageReferences ──────────────────────────────────
81
+ const projectSection = pbx['PBXProject'] || {};
82
+ const projectObj = Object.values(projectSection).find(
83
+ (v) => v && typeof v === 'object' && v.isa === 'PBXProject',
84
+ );
85
+ if (projectObj) {
86
+ projectObj.packageReferences = projectObj.packageReferences || [];
87
+ if (!projectObj.packageReferences.some((r) => r.value === PKG_REF_UUID)) {
88
+ projectObj.packageReferences.push({
89
+ value: PKG_REF_UUID,
90
+ comment: `XCRemoteSwiftPackageReference "${PRODUCT_NAME}"`,
91
+ });
92
+ }
93
+ }
94
+
95
+ // ── 5. Add to the main app target ─────────────────────────────────────
96
+ const targetName = modConfig.modRequest.projectName;
97
+ const nativeTargets = pbx['PBXNativeTarget'] || {};
98
+
99
+ for (const [, target] of Object.entries(nativeTargets)) {
100
+ if (!target || typeof target !== 'object') continue;
101
+
102
+ // pbxproj stores names with surrounding quotes; handle both forms.
103
+ const name = typeof target.name === 'string'
104
+ ? target.name.replace(/^"|"$/g, '')
105
+ : '';
106
+ if (name !== targetName) continue;
107
+
108
+ // packageProductDependencies
109
+ target.packageProductDependencies = target.packageProductDependencies || [];
110
+ if (!target.packageProductDependencies.some((d) => d.value === PROD_DEP_UUID)) {
111
+ target.packageProductDependencies.push({
112
+ value: PROD_DEP_UUID,
113
+ comment: PRODUCT_NAME,
114
+ });
115
+ }
116
+
117
+ // Add build file to PBXFrameworksBuildPhase
118
+ for (const phaseRef of target.buildPhases || []) {
119
+ const frameworksSection = pbx['PBXFrameworksBuildPhase'] || {};
120
+ const phase = frameworksSection[phaseRef.value];
121
+ if (!phase) continue;
122
+
123
+ phase.files = phase.files || [];
124
+ if (!phase.files.some((f) => f.value === BUILD_FILE_UUID)) {
125
+ phase.files.push({
126
+ value: BUILD_FILE_UUID,
127
+ comment: `${PRODUCT_NAME} in Frameworks`,
128
+ });
129
+ }
130
+ break;
131
+ }
132
+ break;
133
+ }
134
+
135
+ return modConfig;
136
+ });
137
+ };
138
+
139
+ module.exports = withMarkdownViewSPM;