@react-native-windows/codegen 0.0.0-canary.4 → 0.0.0-canary.41

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +359 -4
  2. package/bin.js +0 -0
  3. package/lib-commonjs/Cli.d.ts +7 -0
  4. package/lib-commonjs/Cli.js +60 -0
  5. package/lib-commonjs/Cli.js.map +1 -0
  6. package/lib-commonjs/generators/AliasGen.d.ts +11 -0
  7. package/lib-commonjs/generators/AliasGen.js +72 -0
  8. package/lib-commonjs/generators/AliasGen.js.map +1 -0
  9. package/lib-commonjs/generators/AliasManaging.d.ts +15 -0
  10. package/lib-commonjs/generators/AliasManaging.js +49 -0
  11. package/lib-commonjs/generators/AliasManaging.js.map +1 -0
  12. package/lib-commonjs/generators/GenerateNM2.d.ts +12 -0
  13. package/lib-commonjs/generators/GenerateNM2.js +94 -0
  14. package/lib-commonjs/generators/GenerateNM2.js.map +1 -0
  15. package/lib-commonjs/generators/GenerateTypeScript.d.ts +11 -0
  16. package/lib-commonjs/generators/GenerateTypeScript.js +166 -0
  17. package/lib-commonjs/generators/GenerateTypeScript.js.map +1 -0
  18. package/lib-commonjs/generators/ObjectTypes.d.ts +8 -0
  19. package/lib-commonjs/generators/ObjectTypes.js +53 -0
  20. package/lib-commonjs/generators/ObjectTypes.js.map +1 -0
  21. package/lib-commonjs/generators/ParamTypes.d.ts +11 -0
  22. package/lib-commonjs/generators/ParamTypes.js +114 -0
  23. package/lib-commonjs/generators/ParamTypes.js.map +1 -0
  24. package/lib-commonjs/generators/ReturnTypes.d.ts +9 -0
  25. package/lib-commonjs/generators/ReturnTypes.js +63 -0
  26. package/lib-commonjs/generators/ReturnTypes.js.map +1 -0
  27. package/lib-commonjs/generators/ValidateConstants.d.ts +8 -0
  28. package/lib-commonjs/generators/ValidateConstants.js +38 -0
  29. package/lib-commonjs/generators/ValidateConstants.js.map +1 -0
  30. package/lib-commonjs/generators/ValidateMethods.d.ts +8 -0
  31. package/lib-commonjs/generators/ValidateMethods.js +70 -0
  32. package/lib-commonjs/generators/ValidateMethods.js.map +1 -0
  33. package/lib-commonjs/index.d.ts +35 -0
  34. package/lib-commonjs/index.js +190 -0
  35. package/lib-commonjs/index.js.map +1 -0
  36. package/package.json +32 -18
  37. package/src/Cli.ts +26 -152
  38. package/src/generators/AliasGen.ts +105 -0
  39. package/src/generators/AliasManaging.ts +75 -0
  40. package/src/generators/GenerateNM2.ts +69 -297
  41. package/src/generators/GenerateTypeScript.ts +247 -0
  42. package/src/generators/ObjectTypes.ts +73 -0
  43. package/src/generators/ParamTypes.ts +220 -0
  44. package/src/generators/ReturnTypes.ts +92 -0
  45. package/src/generators/ValidateConstants.ts +50 -0
  46. package/src/generators/ValidateMethods.ts +135 -0
  47. package/src/index.ts +321 -0
  48. package/.eslintrc.js +0 -4
  49. package/.vscode/launch.json +0 -23
  50. package/CHANGELOG.json +0 -462
  51. package/jest.config.js +0 -1
  52. package/tsconfig.json +0 -5
package/src/index.ts ADDED
@@ -0,0 +1,321 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation.
3
+ * Licensed under the MIT License.
4
+ *
5
+ * @format
6
+ */
7
+
8
+ import path from 'path';
9
+ import fs from '@react-native-windows/fs';
10
+ import globby from 'globby';
11
+ import {createNM2Generator} from './generators/GenerateNM2';
12
+ import {
13
+ generateTypeScript,
14
+ setOptionalTurboModule,
15
+ } from './generators/GenerateTypeScript';
16
+ import type {SchemaType} from 'react-native-tscodegen';
17
+
18
+ // Load react-native-codegen from react-native
19
+ const rnPath = path.dirname(require.resolve('react-native/package.json'));
20
+ const rncodegenPath = path.dirname(
21
+ require.resolve('react-native-codegen/package.json', {paths: [rnPath]}),
22
+ );
23
+ const FlowParser = require(path.resolve(rncodegenPath, 'lib/parsers/flow'));
24
+ const TypeScriptParser = require(path.resolve(
25
+ rncodegenPath,
26
+ 'lib/parsers/typescript',
27
+ ));
28
+
29
+ const schemaValidator = require(path.resolve(
30
+ rncodegenPath,
31
+ 'lib/schemaValidator',
32
+ ));
33
+
34
+ interface Options {
35
+ libraryName: string;
36
+ schema: SchemaType;
37
+ outputDirectory: string;
38
+ moduleSpecName: string;
39
+ namespace: string;
40
+ methodonly: boolean;
41
+ ts: boolean;
42
+ }
43
+
44
+ interface Config {
45
+ generators: any[] /*Generators[]*/;
46
+ test?: boolean;
47
+ }
48
+
49
+ function normalizeFileMap(
50
+ map: Map<string, string>,
51
+ outputDir: string,
52
+ outMap: Map<string, string>,
53
+ ): void {
54
+ for (const [fileName, contents] of map) {
55
+ const location = path.join(outputDir, fileName);
56
+ outMap.set(path.normalize(location), contents);
57
+ }
58
+ }
59
+
60
+ function checkFilesForChanges(
61
+ map: Map<string, string>,
62
+ outputDir: string,
63
+ ): boolean {
64
+ let hasChanges = false;
65
+
66
+ const allExistingFiles = globby
67
+ .sync(`${outputDir}/**`)
68
+ .map(_ => path.normalize(_))
69
+ .sort();
70
+ const allGeneratedFiles = [...map.keys()].map(_ => path.normalize(_)).sort();
71
+
72
+ if (
73
+ allExistingFiles.length !== allGeneratedFiles.length ||
74
+ !allExistingFiles.every((val, index) => val === allGeneratedFiles[index])
75
+ )
76
+ return true;
77
+
78
+ for (const [fileName, contents] of map) {
79
+ if (!fs.existsSync(fileName)) {
80
+ hasChanges = true;
81
+ continue;
82
+ }
83
+
84
+ const currentContents = fs.readFileSync(fileName, 'utf8');
85
+ if (currentContents !== contents) {
86
+ console.log(`- ${fileName} has changed`);
87
+ hasChanges = true;
88
+ continue;
89
+ }
90
+ }
91
+
92
+ return hasChanges;
93
+ }
94
+
95
+ function writeMapToFiles(map: Map<string, string>, outputDir: string) {
96
+ let success = true;
97
+
98
+ // This ensures that we delete any generated files from modules that have been deleted
99
+ const allExistingFiles = globby.sync(`${outputDir}/**`);
100
+ allExistingFiles.forEach(existingFile => {
101
+ if (!map.has(path.normalize(existingFile))) {
102
+ fs.unlinkSync(existingFile);
103
+ }
104
+ });
105
+
106
+ for (const [fileName, contents] of map) {
107
+ try {
108
+ fs.mkdirSync(path.dirname(fileName), {recursive: true});
109
+
110
+ if (fs.existsSync(fileName)) {
111
+ const currentContents = fs.readFileSync(fileName, 'utf8');
112
+ // Don't update the files if there are no changes as this breaks incremental builds
113
+ if (currentContents === contents) {
114
+ continue;
115
+ }
116
+ }
117
+
118
+ fs.writeFileSync(fileName, contents);
119
+ } catch (error) {
120
+ success = false;
121
+ console.error(`Failed to write ${fileName} to ${fileName}`, error);
122
+ }
123
+ }
124
+
125
+ return success;
126
+ }
127
+
128
+ export function parseFile(filename: string): SchemaType {
129
+ try {
130
+ const isTypeScript =
131
+ path.extname(filename) === '.ts' || path.extname(filename) === '.tsx';
132
+
133
+ const schema = isTypeScript
134
+ ? TypeScriptParser.parseFile(filename)
135
+ : FlowParser.parseFile(filename);
136
+ // there will be at most one turbo module per file
137
+ const moduleName = Object.keys(schema.modules)[0];
138
+ if (moduleName) {
139
+ const spec = schema.modules[moduleName];
140
+ if (spec.type === 'NativeModule') {
141
+ const contents = fs.readFileSync(filename, 'utf8');
142
+ if (contents) {
143
+ // This is a temporary implementation until such information is added to the schema in facebook/react-native
144
+ if (contents.includes('TurboModuleRegistry.get<')) {
145
+ setOptionalTurboModule(spec, true);
146
+ } else if (contents.includes('TurboModuleRegistry.getEnforcing<')) {
147
+ setOptionalTurboModule(spec, false);
148
+ }
149
+ }
150
+ }
151
+ }
152
+ return schema;
153
+ } catch (e) {
154
+ if (e instanceof Error) {
155
+ e.message = `(${filename}): ${e.message}`;
156
+ }
157
+ throw e;
158
+ }
159
+ }
160
+
161
+ export function combineSchemas(files: string[]): SchemaType {
162
+ return files.reduce(
163
+ (merged, filename) => {
164
+ const contents = fs.readFileSync(filename, 'utf8');
165
+ if (
166
+ contents &&
167
+ (/export\s+default\s+\(?codegenNativeComponent</.test(contents) ||
168
+ contents.includes('extends TurboModule'))
169
+ ) {
170
+ const schema = parseFile(filename);
171
+ merged.modules = {...merged.modules, ...schema.modules};
172
+ }
173
+ return merged;
174
+ },
175
+ {modules: {}},
176
+ );
177
+ }
178
+
179
+ export function generate(
180
+ {
181
+ libraryName,
182
+ schema,
183
+ outputDirectory,
184
+ moduleSpecName,
185
+ namespace,
186
+ methodonly,
187
+ ts,
188
+ }: Options,
189
+ {/*generators,*/ test}: Config,
190
+ ): boolean {
191
+ schemaValidator.validate(schema);
192
+
193
+ const componentOutputdir = path.join(
194
+ outputDirectory,
195
+ 'react/components',
196
+ libraryName,
197
+ );
198
+
199
+ const generatedFiles = new Map<string, string>();
200
+
201
+ generatedFiles.set(
202
+ path.join(outputDirectory, '.clang-format'),
203
+ 'DisableFormat: true\nSortIncludes: false',
204
+ );
205
+
206
+ const generateNM2 = createNM2Generator({
207
+ namespace,
208
+ methodonly,
209
+ });
210
+
211
+ const generatorPropsH = require(path.resolve(
212
+ rncodegenPath,
213
+ 'lib/generators/components/GeneratePropsH',
214
+ )).generate;
215
+ const generatorPropsCPP = require(path.resolve(
216
+ rncodegenPath,
217
+ 'lib/generators/components/GeneratePropsCPP',
218
+ )).generate;
219
+ const generatorShadowNodeH = require(path.resolve(
220
+ rncodegenPath,
221
+ 'lib/generators/components/GenerateShadowNodeH',
222
+ )).generate;
223
+ const generatorShadowNodeCPP = require(path.resolve(
224
+ rncodegenPath,
225
+ 'lib/generators/components/GenerateShadowNodeCPP',
226
+ )).generate;
227
+ const generatorComponentDescriptorH = require(path.resolve(
228
+ rncodegenPath,
229
+ 'lib/generators/components/GenerateComponentDescriptorH',
230
+ )).generate;
231
+ const generatorEventEmitterH = require(path.resolve(
232
+ rncodegenPath,
233
+ 'lib/generators/components/GenerateEventEmitterH',
234
+ )).generate;
235
+ const generatorEventEmitterCPP = require(path.resolve(
236
+ rncodegenPath,
237
+ 'lib/generators/components/GenerateEventEmitterCpp',
238
+ )).generate;
239
+
240
+ normalizeFileMap(
241
+ generateNM2(libraryName, schema, moduleSpecName),
242
+ outputDirectory,
243
+ generatedFiles,
244
+ );
245
+
246
+ if (ts) {
247
+ normalizeFileMap(
248
+ generateTypeScript(libraryName, schema, moduleSpecName),
249
+ outputDirectory,
250
+ generatedFiles,
251
+ );
252
+ }
253
+
254
+ if (
255
+ Object.keys(schema.modules).some(
256
+ moduleName => schema.modules[moduleName].type === 'Component',
257
+ )
258
+ ) {
259
+ const componentGenerators = [
260
+ generatorPropsH,
261
+ generatorPropsCPP,
262
+ generatorShadowNodeH,
263
+ generatorShadowNodeCPP,
264
+ generatorComponentDescriptorH,
265
+ generatorEventEmitterH,
266
+ generatorEventEmitterCPP,
267
+ ];
268
+
269
+ componentGenerators.forEach(generator => {
270
+ const generated: Map<string, string> = generator(
271
+ libraryName,
272
+ schema,
273
+ moduleSpecName,
274
+ );
275
+ normalizeFileMap(generated, componentOutputdir, generatedFiles);
276
+ });
277
+ }
278
+
279
+ if (test === true) {
280
+ return checkFilesForChanges(generatedFiles, outputDirectory);
281
+ }
282
+
283
+ return writeMapToFiles(generatedFiles, outputDirectory);
284
+ }
285
+
286
+ export type CodeGenOptions = {
287
+ file?: string;
288
+ files?: string[];
289
+ libraryName: string;
290
+ outdir: string;
291
+ namespace: string;
292
+ methodonly: boolean;
293
+ ts: boolean;
294
+ test: boolean;
295
+ };
296
+
297
+ export function runCodeGen(options: CodeGenOptions): boolean {
298
+ if (!options.file && !options.files)
299
+ throw new Error('Must specify file or files option');
300
+
301
+ const schema = options.file
302
+ ? parseFile(options.file)
303
+ : combineSchemas(globby.sync(options.files!));
304
+
305
+ const libraryName = options.libraryName;
306
+ const moduleSpecName = 'moduleSpecName';
307
+ const outputDirectory = options.outdir;
308
+ const {namespace, methodonly, ts} = options;
309
+ return generate(
310
+ {
311
+ libraryName,
312
+ schema,
313
+ outputDirectory,
314
+ moduleSpecName,
315
+ namespace,
316
+ methodonly,
317
+ ts,
318
+ },
319
+ {generators: [], test: options.test},
320
+ );
321
+ }
package/.eslintrc.js DELETED
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- extends: ['@rnw-scripts'],
3
- parserOptions: {tsconfigRootDir : __dirname},
4
- };
@@ -1,23 +0,0 @@
1
- {
2
- // Use IntelliSense to learn about possible attributes.
3
- // Hover to view descriptions of existing attributes.
4
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
- "version": "0.2.0",
6
- "configurations": [
7
- {
8
- "name": "vscode-jest-tests",
9
- "type": "node",
10
- "request": "launch",
11
- "runtimeArgs": [
12
- "--inspect-brk",
13
- "../../node_modules/jest/bin/jest.js",
14
- "--runInBand",
15
- "--config",
16
- "../@rnw-scripts/jest-debug-config/jest.debug.config.js",
17
- ],
18
- "console": "integratedTerminal",
19
- "internalConsoleOptions": "neverOpen",
20
- "port": 9229,
21
- },
22
- ]
23
- }