Created
March 4, 2023 22:29
-
-
Save webstrand/de518199f8ff118e61e3c6dfa6f29beb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const tsconfig = { | |
| include: ["lib/**/*.ts", "lib/packages/**/*.ts", "lib/index.ts"], | |
| exclude: ["src"], | |
| files: ["lib/index.ts"], | |
| typeAcquisition: { | |
| enable: true, | |
| disableFilenameBasedTypeAcquisition: true, | |
| }, | |
| compilerOptions: { | |
| allowUnreachableCode: true, | |
| allowUnusedLabels: true, | |
| exactOptionalPropertyTypes: true, | |
| noImplicitAny: true, | |
| noImplicitOverride: true, | |
| noImplicitThis: false, | |
| noPropertyAccessFromIndexSignature: false, | |
| noUncheckedIndexedAccess: false, | |
| noUnusedLocals: true, | |
| noUnusedParameters: true, | |
| strict: true, | |
| allowUmdGlobalAccess: false, | |
| baseUrl: "./lib", | |
| module: "ESNext", | |
| moduleResolution: "node", | |
| paths: { | |
| "@utils/*": ["utils/*"], | |
| "@test-helpers/*": ["packages/__test__/*"], | |
| }, | |
| resolveJsonModule: true, | |
| types: ["node", "jest"], | |
| typeRoots: ["lib/packages/__test__/jest-ext.d.ts", "node_modules/@types"], | |
| declaration: false, | |
| outDir: "dist/tsc", | |
| preserveConstEnums: true, | |
| stripInternal: true, | |
| checkJs: true, | |
| plugins: [ | |
| { | |
| name: "typescript-eslint-language-service", | |
| }, | |
| { | |
| transform: "typescript-transform-paths", | |
| }, | |
| { | |
| transform: "typescript-transform-paths", | |
| afterDeclarations: true, | |
| }, | |
| ], | |
| allowSyntheticDefaultImports: false, | |
| esModuleInterop: false, | |
| forceConsistentCasingInFileNames: true, | |
| preserveSymlinks: true, | |
| lib: ["esnext", "dom"], | |
| target: "esnext", | |
| explainFiles: false, | |
| extendedDiagnostics: true, | |
| listEmittedFiles: true, | |
| listFiles: true, | |
| traceResolution: false, | |
| composite: false, | |
| incremental: false, | |
| }, | |
| }; | |
| const sortorder = ` | |
| Top Level: compilerOptions, files, extends, include, exclude, references, watchOptions, typeAcquisition | |
| Type Checking: allowUnreachableCode, allowUnusedLabels, alwaysStrict, exactOptionalPropertyTypes, noFallthroughCasesInSwitch, noImplicitAny, noImplicitOverride, noImplicitReturns, noImplicitThis, noPropertyAccessFromIndexSignature, noUncheckedIndexedAccess, noUnusedLocals, noUnusedParameters, strict, strictBindCallApply, strictFunctionTypes, strictNullChecks, strictPropertyInitialization, useUnknownInCatchVariables | |
| Modules: allowUmdGlobalAccess, baseUrl, module, moduleResolution, moduleSuffixes, noResolve, paths, resolveJsonModule, rootDir, rootDirs, typeRoots, types | |
| Emit: declaration, declarationDir, declarationMap, downlevelIteration, emitBOM, emitDeclarationOnly, importHelpers, importsNotUsedAsValues, inlineSourceMap, inlineSources, mapRoot, newLine, noEmit, noEmitHelpers, noEmitOnError, outDir, outFile, preserveConstEnums, preserveValueImports, removeComments, sourceMap, sourceRoot, stripInternal | |
| JavaScript Support: allowJs, checkJs, maxNodeModuleJsDepth | |
| Editor Support: disableSizeLimit, plugins | |
| Interop Constraints: allowSyntheticDefaultImports, esModuleInterop, forceConsistentCasingInFileNames, isolatedModules, preserveSymlinks | |
| Backwards Compatibility: charset, keyofStringsOnly, noImplicitUseStrict, noStrictGenericChecks, out, suppressExcessPropertyErrors, suppressImplicitAnyIndexErrors | |
| Language, Environment: emitDecoratorMetadata, experimentalDecorators, jsx, jsxFactory, jsxFragmentFactory, jsxImportSource, lib, moduleDetection, noLib, reactNamespace, target, useDefineForClassFields | |
| Compiler Diagnostics: diagnostics, explainFiles, extendedDiagnostics, generateCpuProfile, listEmittedFiles, listFiles, traceResolution | |
| Projects: composite, disableReferencedProjectLoad, disableSolutionSearching, disableSourceOfProjectReferenceRedirect, incremental, tsBuildInfoFile | |
| Output Formatting: noErrorTruncation, preserveWatchOutput, pretty | |
| Completeness: skipDefaultLibCheck, skipLibCheck | |
| Watch Options: assumeChangesOnlyAffectDirectDependencies | |
| watchOptions: watchFile, watchDirectory, fallbackPolling, synchronousWatchDirectory, excludeDirectories, excludeFiles | |
| typeAcquisition: enable, include, exclude, disableFilenameBasedTypeAcquisition | |
| ` | |
| .split(/\s*\n\s*/) | |
| .filter((x) => x) | |
| .map((group) => | |
| (([label, opts]) => ({ | |
| group: label, | |
| sort: opts.split(/[,\s]+/).filter((opt) => opt), | |
| }))(group.split(/\s*:\s*/) as [string, string]) | |
| ); | |
| console.log(sortorder); | |
| const defaults = { | |
| // Top Level | |
| compilerOptions: { | |
| // | |
| resolvePackageJsonExports: false, | |
| resolvePackageJsonImports: false, | |
| // Type Checking | |
| exactOptionalPropertyTypes: false, | |
| noFallthroughCasesInSwitch: false, | |
| noImplicitOverride: false, | |
| noImplicitReturns: false, | |
| noUnusedLocals: false, | |
| noUnusedParameters: false, | |
| strict: false, | |
| strictBindCallApply: false, | |
| strictFunctionTypes: false, | |
| strictNullChecks: false, | |
| strictPropertyInitialization: false, | |
| useUnknownInCatchVariables: false, | |
| // Modules | |
| allowUmdGlobalAccess: false, | |
| moduleResolution: "classic", | |
| noResolve: false, | |
| resolveJsonModule: false, | |
| // Emit | |
| declaration: false, | |
| declarationMap: false, | |
| downlevelIteration: false, | |
| emitBOM: false, | |
| emitDeclarationOnly: false, | |
| importHelpers: false, | |
| importsNotUsedAsValues: "remove", | |
| inlineSourceMap: false, | |
| inlineSources: false, | |
| noEmit: false, | |
| noEmitHelpers: false, | |
| noEmitOnError: false, | |
| preserveConstEnums: false, | |
| preserveValueImports: false, | |
| removeComments: false, | |
| sourceMap: false, | |
| // JavaScript Support | |
| allowJs: false, | |
| checkJs: false, | |
| maxNodeModuleJsDepth: 0, | |
| // Editor Support | |
| disableSizeLimit: false, | |
| // Interop Constraints | |
| esModuleInterop: false, | |
| forceConsistentCasingInFileNames: false, | |
| isolatedModules: false, | |
| preserveSymlinks: false, | |
| // Backwards Compatibility | |
| keyofStringsOnly: false, | |
| noImplicitUseStrict: false, | |
| noStrictGenericChecks: false, | |
| suppressExcessPropertyErrors: false, | |
| suppressImplicitAnyIndexErrors: false, | |
| // Language, Environment | |
| jsxFactory: "React.createElement", | |
| jsxFragmentFactory: "React.Fragment", | |
| jsxImportSource: "react", | |
| noLib: false, | |
| reactNamespace: "React", | |
| target: "ES3", | |
| useDefineForClassFields: false, | |
| // Compiler Diagnostics | |
| extendedDiagnostics: false, | |
| generateCpuProfile: "profile.cpuprofile", | |
| listEmittedFiles: false, | |
| listFiles: false, | |
| traceResolution: false, | |
| // Projects | |
| composite: true, | |
| tsBuildInfoFile: ".tsbuildinfo", | |
| // Output Formatting | |
| noErrorTruncation: false, | |
| pretty: true, | |
| // Completeness | |
| skipDefaultLibCheck: false, | |
| skipLibCheck: false, | |
| // watchOptions | |
| watchFile: "useFsEvents", | |
| watchDirectory: "useFsEvents", | |
| }, | |
| }; | |
| type Json = string | number | boolean | null | { [key: string]: Json } | Json[]; | |
| type SortableJson = | |
| | string | |
| | number | |
| | boolean | |
| | null | |
| | { entries: readonly (readonly [string, SortableJson])[] } | |
| | readonly SortableJson[]; | |
| type GroupedSortableJson = | |
| | string | |
| | number | |
| | boolean | |
| | null | |
| | { | |
| entries: readonly (readonly (readonly [ | |
| string, | |
| GroupedSortableJson, | |
| number, | |
| number | |
| ])[])[]; | |
| } | |
| | readonly GroupedSortableJson[]; | |
| function makeSortable(u: Json): SortableJson { | |
| if (typeof u === "string") return u; | |
| else if (typeof u === "number") return u; | |
| else if (typeof u === "boolean") return u; | |
| else if (typeof u === "object") { | |
| if (u === null) return null; | |
| if (u instanceof Array) return u.map((v) => makeSortable(v)); | |
| return { | |
| entries: Array.from(Object.entries(u), ([key, v]) => [ | |
| key, | |
| makeSortable(v), | |
| ]), | |
| }; | |
| } | |
| throw new Error(`unknown json ${u} ${typeof u}`); | |
| } | |
| function writeSortable(u: GroupedSortableJson, i = ""): string { | |
| if (typeof u === "string") return JSON.stringify(u); | |
| else if (typeof u === "number") return JSON.stringify(u); | |
| else if (typeof u === "boolean") return JSON.stringify(u); | |
| else if (typeof u === "object") { | |
| if (u === null) return "null"; | |
| else if (u instanceof Array) | |
| return `[\n${u | |
| .map((v) => `${i}\t${writeSortable(v, i + "\t")}`) | |
| .join(",\n")}\n${i}]`; | |
| return `{\n${u.entries | |
| .map( | |
| (group) => | |
| `${i}\t// ${sortorder[group[0]?.[2] ?? 1e309]?.group ?? ""}\n` + | |
| group | |
| .map( | |
| ([k, v, g, s]) => | |
| `${i}\t${JSON.stringify(k)}: ${writeSortable(v, i + "\t")}` | |
| ) | |
| .join(",\n") | |
| ) | |
| .join(",\n\n")}\n${i}}`; | |
| } | |
| throw new Error(`unknown sortable-json ${u} ${typeof u}`); | |
| } | |
| function sortSortableJson( | |
| u: SortableJson, | |
| groups: readonly { group: string; sort: string[] }[] | |
| ): GroupedSortableJson { | |
| if (typeof u === "string") return u; | |
| else if (typeof u === "number") return u; | |
| else if (typeof u === "boolean") return u; | |
| else if (typeof u === "object") { | |
| if (u === null) return "null"; | |
| else if (u instanceof Array) | |
| return u.map((v) => sortSortableJson(v, groups)); | |
| // group the keys into the groups specified by the sortorder | |
| const grouped = groupByPredicate( | |
| u.entries.map(([k, v]) => { | |
| let sortIndex = -1; | |
| const groupIndex = groups.findIndex( | |
| (group) => (sortIndex = group.sort.indexOf(k)) !== -1 | |
| ); | |
| return [k, v, groupIndex, sortIndex] as const; | |
| }), | |
| ([, , group]) => group | |
| ).sort(([[, , a]], [[, , b]]) => a - b); | |
| // sort the keys in each group by the specified sortorder | |
| const sorted = grouped.map((group) => | |
| group | |
| .sort(([ka, , , a], [kb, , , b]) => a - b || ka.localeCompare(kb)) | |
| .map(([k, v, g, s]) => [k, sortSortableJson(v, groups), g, s] as const) | |
| ); | |
| return { entries: sorted }; | |
| } | |
| throw new Error(`unknown sortable-json ${u} ${typeof u}`); | |
| } | |
| /** | |
| * Split the array into an arbitrary number of non-empty groups. The group | |
| * ordering is arbitrary. | |
| */ | |
| function groupByPredicate<T, G>( | |
| values: readonly T[], | |
| predicate: (v: T) => G | |
| ): ([T, ...T[]])[] { | |
| const map = new Map<G, T[]>(); | |
| for (const v of values) { | |
| const group = predicate(v); | |
| let table = map.get(group); | |
| if (!table) map.set(group, (table = [])); | |
| table.push(v); | |
| } | |
| return [...map.values()] as never; | |
| } | |
| console.log(writeSortable(sortSortableJson(makeSortable(tsconfig), sortorder))); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment