? -> string)
639 | function Strings.pretty(value, serializeOptions)
640 | local function serializeValue(value, options)
641 | if type(value) == "table" then
642 | local className = ""
643 | if value.Class then
644 | className = value.Class.name .. " "
645 | end
646 | return className .. Tables.serialize(value, options)
647 | else
648 | return Tables.defaultSerializer(value, options)
649 | end
650 | end
651 |
652 | local MAX_LINE = 80
653 |
654 | return Tables.serialize(
655 | value,
656 | Tables.assign(
657 | {
658 | serializeValue = serializeValue,
659 | serializeKey = function(key, options)
660 | if type(key) == "string" then
661 | return key
662 | else
663 | return "[" .. serializeValue(key, options) .. "]"
664 | end
665 | end,
666 | serializeElement = function(key, value)
667 | local shortString = key .. " = " .. value
668 | if #shortString < MAX_LINE or shortString:match("\n") then
669 | return shortString
670 | end
671 | return key .. " =\n\t" .. value
672 | end or nil,
673 | serializeTable = function(contents, ref, options)
674 | local shortString = ref .. "{" .. table.concat(contents, ", ") .. "}"
675 | if #shortString < MAX_LINE then
676 | return shortString
677 | end
678 | return ref ..
679 | "{\n" ..
680 | table.concat(
681 | Tables.map(
682 | contents,
683 | function(element)
684 | return "\t" .. element:gsub("\n", "\n\t")
685 | end
686 | ),
687 | ",\n"
688 | ) ..
689 | "\n}"
690 | end or nil,
691 | keyDelimiter = " = ",
692 | valueDelimiter = ", ",
693 | omitKeys = {"Class"}
694 | },
695 | serializeOptions or {}
696 | )
697 | )
698 | end
699 |
700 | return Strings
701 |
--------------------------------------------------------------------------------
/src/init.lua:
--------------------------------------------------------------------------------
1 | local Async = require(script.Async)
2 | local Classes = require(script.Classes)
3 | local Functions = require(script.Functions)
4 | local Strings = require(script.Strings)
5 | local Arrays = require(script.Arrays)
6 | local Tables = require(script.Tables)
7 |
8 | local dash = Tables.assign({}, Async, Classes, Functions, Strings, Arrays, Tables)
9 | return dash
10 |
--------------------------------------------------------------------------------
/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -o nounset
4 | set -o errexit
5 | set -o pipefail
6 |
7 | export PATH="$PWD/lua_install/bin:$PATH"
8 |
9 | if [ -n "${DEBUG:-}" ]
10 | then
11 | echo "Testing with debug mode..."
12 | fi
13 |
14 | set -o xtrace
15 | busted --helper tools/testInit.lua -Xhelper "${DEBUG:+debug}" -m 'modules/?/lib/t.lua' -m 'modules/?/lib/init.lua' -m './lib/?.lua' -m './src/?.lua' -p "%.spec" spec ${COVERAGE:-} "$@"
16 |
17 | if [ -n "${COVERAGE:-}" ]
18 | then
19 | echo "Generating coverage..."
20 | ./lua_install/bin/luacov-cobertura -o cobertura-coverage.xml
21 | sed -i.bak -E "s%%$(pwd)%p" cobertura-coverage.xml
22 | rm cobertura-coverage.xml.bak
23 | fi
--------------------------------------------------------------------------------
/tools/buildDocs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -o nounset
4 | set -o errexit
5 | set -o pipefail
6 |
7 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
8 | cd "$SCRIPT_DIR"
9 | cd ..
10 |
11 | mkdir -p docs/api
12 | node node_modules/ts-node/dist/bin.js tools/docublox --output docs --libName "dash" --rootUrl "/rodash/" src docs_source
13 | mkdocs build --clean
14 |
--------------------------------------------------------------------------------
/tools/checkFormat.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -o nounset
4 | set -o errexit
5 | set -o pipefail
6 |
7 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
8 | cd "$SCRIPT_DIR"
9 |
10 | if [ -n "$(git status --porcelain)" ]; then
11 | echo "There are uncommitted changes in the work directory - this would prevent the code style check from working"
12 | exit 1
13 | fi
14 |
15 | ./format.sh
16 |
17 | if [ -n "$(git status --porcelain)" ]; then
18 | echo "The code style is invalid in the following files (run format.sh before committing):"
19 | git status
20 | exit 1
21 | fi
--------------------------------------------------------------------------------
/tools/docublox/LuaTypes.ts:
--------------------------------------------------------------------------------
1 | import { stringify } from 'querystring';
2 |
3 | export enum TypeKind {
4 | DEFINITION = 'definition',
5 | TABLE = 'table',
6 | ARRAY = 'array',
7 | DICTIONARY = 'dictionary',
8 | TUPLE = 'tuple',
9 | ALIAS = 'alias',
10 | FAIL = 'fail',
11 | FUNCTION = 'function',
12 | ANY = 'any',
13 | CHAR = 'char',
14 | STRING = 'string',
15 | NUMBER = 'number',
16 | INT = 'int',
17 | UINT = 'uint',
18 | FLOAT = 'float',
19 | BOOL = 'bool',
20 | NIL = 'nil',
21 | NEVER = 'never',
22 | VOID = 'void',
23 | UNION = 'union',
24 | OPTIONAL = 'optional',
25 | INTERSECTION = 'intersection',
26 | GENERIC = 'generic',
27 | }
28 | export interface Type {
29 | typeKind: TypeKind;
30 | isRestParameter?: boolean;
31 | genericParameters?: Type[];
32 | tag?: string;
33 | isMutable?: boolean;
34 | }
35 | export interface GenericType {
36 | typeKind: TypeKind.GENERIC;
37 | tag: string;
38 | extendingType: Type;
39 | }
40 | export interface TupleType extends Type {
41 | typeKind: TypeKind.TUPLE;
42 | elementTypes: Type[];
43 | genericTypes?: GenericType[];
44 | }
45 | export interface FunctionType extends Type {
46 | typeKind: TypeKind.FUNCTION;
47 | parameterTypes: Type[];
48 | returnType: ReturnType;
49 | genericTypes?: GenericType[];
50 | }
51 | export interface UnionType extends Type {
52 | typeKind: TypeKind.UNION;
53 | allowedTypes: Type[];
54 | }
55 | export interface IntersectionType extends Type {
56 | typeKind: TypeKind.INTERSECTION;
57 | requiredTypes: Type[];
58 | }
59 | export interface OptionalType extends Type {
60 | typeKind: TypeKind.OPTIONAL;
61 | optionalType: Type;
62 | }
63 | export interface ReturnType extends Type {
64 | isYielding?: boolean;
65 | }
66 | export interface ArrayType extends Type {
67 | typeKind: TypeKind.ARRAY;
68 | valueType: Type;
69 | }
70 | export interface DictionaryType extends Type {
71 | typeKind: TypeKind.DICTIONARY;
72 | keyType: Type;
73 | valueType: Type;
74 | }
75 | export interface AliasType extends Type {
76 | typeKind: TypeKind.ALIAS;
77 | aliasName: string;
78 | }
79 | export interface TableType extends Type {
80 | typeKind: TypeKind.TABLE;
81 | dimensions: { isArray: boolean }[];
82 | elementType: Type;
83 | }
84 |
85 | export function stringifyType(type: Type) {
86 | let typeString;
87 | switch (type.typeKind) {
88 | case TypeKind.ALIAS:
89 | typeString = (type as AliasType).aliasName;
90 | break;
91 | case TypeKind.OPTIONAL:
92 | typeString = stringifyType((type as OptionalType).optionalType) + '?';
93 | break;
94 | case TypeKind.TABLE:
95 | const tableType = type as TableType;
96 | typeString =
97 | stringifyType(tableType.elementType) +
98 | tableType.dimensions.map(dim => (dim.isArray ? '[]' : '{}')).join('');
99 | break;
100 | case TypeKind.FUNCTION:
101 | const functionType = type as FunctionType;
102 | typeString =
103 | '(' +
104 | functionType.parameterTypes.map(type => stringifyType(type)).join(', ') +
105 | ') -> ' +
106 | stringifyType(functionType.returnType);
107 | break;
108 | case TypeKind.ARRAY:
109 | const arrayType = type as ArrayType;
110 | typeString = '{' + (arrayType.valueType ? stringifyType(arrayType.valueType) : '') + '}';
111 | break;
112 | case TypeKind.TUPLE:
113 | const tupleType = type as TupleType;
114 | typeString = tupleType.elementTypes.map(type => stringifyType(type)).join(', ');
115 | break;
116 | case TypeKind.UNION:
117 | const unionType = type as UnionType;
118 | typeString = unionType.allowedTypes.map(type => stringifyType(type)).join(' | ');
119 | break;
120 | case TypeKind.INTERSECTION:
121 | const intersectionType = type as IntersectionType;
122 | typeString = intersectionType.requiredTypes.map(type => stringifyType(type)).join(' & ');
123 | break;
124 | case TypeKind.DICTIONARY:
125 | const dictionaryType = type as DictionaryType;
126 | typeString =
127 | '{[' +
128 | stringifyType(dictionaryType.keyType) +
129 | ']: ' +
130 | stringifyType(dictionaryType.valueType) +
131 | '}';
132 | break;
133 | default:
134 | typeString = type.typeKind;
135 | break;
136 | }
137 | return (
138 | (type.tag ? type.tag + ': ' : '') +
139 | (type.isMutable ? 'mut ' : '') +
140 | (type.isRestParameter ? '...' : '') +
141 | typeString +
142 | (type.genericParameters
143 | ? '<' + type.genericParameters.map(param => stringifyType(param)).join(', ') + '>'
144 | : '')
145 | );
146 | }
147 |
148 | export enum PLURALITY {
149 | SINGULAR,
150 | PLURAL,
151 | }
152 |
153 | export interface MetaDescription {
154 | rootUrl: string;
155 | generics: { [genericKey: string]: string };
156 | }
157 |
158 | function pluralizeName(name: string, plurality?: PLURALITY) {
159 | const useAn = name.match(/(^[aeiou].)|(^[aefhilmnorsx][0-9]*$)/i);
160 | switch (plurality) {
161 | case PLURALITY.SINGULAR:
162 | return (useAn ? 'an ' : 'a ') + name;
163 | case PLURALITY.PLURAL:
164 | const commonPluralizations = {
165 | dictionary: 'dictionaries',
166 | strategy: 'strategies',
167 | };
168 | return commonPluralizations[name] ? commonPluralizations[name] : name + 's';
169 | default:
170 | return name;
171 | }
172 | }
173 | function joinList(values: string[]) {
174 | const output = [];
175 | if (values.length === 0) {
176 | return 'nothing';
177 | }
178 | for (let i = 0; i < values.length - 2; i++) {
179 | output.push(values[i] + ', ');
180 | }
181 | for (let i = Math.max(values.length - 2, 0); i < values.length - 1; i++) {
182 | output.push(values[i] + ' and ');
183 | }
184 | output.push(values[values.length - 1]);
185 | return output.join('');
186 | }
187 |
188 | export function getCommonNameForTypeVariable(name: string) {
189 | const commonNames = {
190 | A: 'the primary arguments',
191 | A2: 'the secondary arguments',
192 | K: 'the primary key type',
193 | K2: 'the secondary key type',
194 | R: 'the result type',
195 | S: 'the subject type',
196 | T: 'the primary type',
197 | T2: 'the secondary type',
198 | V: 'the primary value type',
199 | V2: 'the secondary value type',
200 | };
201 | return commonNames[name];
202 | }
203 |
204 | export function describeGeneric(type: GenericType, meta?: MetaDescription) {
205 | const commonName = getCommonNameForTypeVariable(type.tag);
206 | const name = commonName ? commonName : type.tag;
207 | if (meta) {
208 | return name + ' (extends ' + describeType(type.extendingType, meta, PLURALITY.SINGULAR) + ')';
209 | } else {
210 | return name;
211 | }
212 | }
213 |
214 | export function describeType(type: Type, meta: MetaDescription, plurality?: PLURALITY): string {
215 | let typeString: string;
216 | if (type.isRestParameter) {
217 | plurality = PLURALITY.PLURAL;
218 | }
219 | switch (type.typeKind) {
220 | case TypeKind.ALIAS:
221 | const name = (type as AliasType).aliasName;
222 | if (meta.generics[name]) {
223 | typeString = meta.generics[name];
224 | } else {
225 | typeString = `[${pluralizeName(name, plurality)}](${
226 | meta.rootUrl
227 | }types/#${name.toLowerCase()})`;
228 | }
229 | break;
230 | case TypeKind.OPTIONAL:
231 | const optionalType = describeType((type as OptionalType).optionalType, meta, plurality);
232 | typeString = optionalType + ' (optional)';
233 | break;
234 | case TypeKind.TABLE:
235 | const tableType = type as TableType;
236 | const elementType = describeType(tableType.elementType, meta, PLURALITY.PLURAL);
237 | if (tableType.dimensions.length === 1) {
238 | const dim = tableType.dimensions[0];
239 | const name = pluralizeName(dim.isArray ? 'array' : 'dictionary', plurality);
240 | typeString = name + ' (of ' + elementType + ')';
241 | } else {
242 | const dimensionString = pluralizeName(tableType.dimensions.length + 'd', plurality);
243 | const namePlurality = plurality === PLURALITY.SINGULAR ? undefined : plurality;
244 | const name = pluralizeName(
245 | tableType.dimensions[0].isArray ? 'array' : 'dictionary',
246 | namePlurality,
247 | );
248 | typeString = dimensionString + ' ' + name + ' (of ' + elementType + ')';
249 | }
250 | break;
251 | case TypeKind.FUNCTION:
252 | const functionType = type as FunctionType;
253 | typeString =
254 | pluralizeName('function', plurality) +
255 | ' (taking ' +
256 | joinList(
257 | functionType.parameterTypes.map(type => describeType(type, meta, PLURALITY.SINGULAR)),
258 | ) +
259 | ', and returning ' +
260 | describeType(functionType.returnType, meta, PLURALITY.SINGULAR) +
261 | ')';
262 | break;
263 | case TypeKind.ARRAY:
264 | const arrayType = type as ArrayType;
265 | if (arrayType.valueType) {
266 | typeString =
267 | pluralizeName('array', plurality) +
268 | ' (of ' +
269 | describeType(arrayType.valueType, meta, PLURALITY.PLURAL) +
270 | ')';
271 | } else {
272 | typeString = pluralizeName('table', plurality);
273 | }
274 | break;
275 | case TypeKind.TUPLE:
276 | const tupleType = type as TupleType;
277 | typeString =
278 | pluralizeName('tuple', plurality) +
279 | ' (' +
280 | joinList(tupleType.elementTypes.map(type => describeType(type, meta, PLURALITY.SINGULAR))) +
281 | ')';
282 | break;
283 | case TypeKind.UNION:
284 | const unionType = type as UnionType;
285 | typeString = unionType.allowedTypes
286 | .map(type => describeType(type, meta, plurality))
287 | .join(' or ');
288 | break;
289 | case TypeKind.INTERSECTION:
290 | const intersectionType = type as IntersectionType;
291 | typeString =
292 | pluralizeName('intersection', plurality) +
293 | ' (of ' +
294 | joinList(
295 | intersectionType.requiredTypes.map(type => describeType(type, meta, PLURALITY.SINGULAR)),
296 | ) +
297 | ')';
298 | break;
299 | case TypeKind.DICTIONARY:
300 | const dictionaryType = type as DictionaryType;
301 | typeString =
302 | 'a dictionary mapping ' +
303 | describeType(dictionaryType.keyType, meta, PLURALITY.PLURAL) +
304 | ' to ' +
305 | describeType(dictionaryType.valueType, meta, PLURALITY.PLURAL);
306 | break;
307 | case TypeKind.GENERIC:
308 | typeString = describeGeneric(type as GenericType);
309 | break;
310 | case TypeKind.ANY:
311 | typeString = plurality === PLURALITY.PLURAL ? 'any values' : 'any value';
312 | break;
313 | case TypeKind.NIL:
314 | typeString = 'nil';
315 | break;
316 | case TypeKind.VOID:
317 | typeString = 'nothing';
318 | break;
319 | case TypeKind.NEVER:
320 | typeString = 'a promise that never resolves';
321 | break;
322 | case TypeKind.BOOL:
323 | typeString = pluralizeName('boolean', plurality);
324 | break;
325 | case TypeKind.INT:
326 | typeString = pluralizeName('integer', plurality);
327 | break;
328 | case TypeKind.UINT:
329 | typeString = pluralizeName('unsigned integer', plurality);
330 | break;
331 | case TypeKind.FAIL:
332 | typeString = pluralizeName('failure state', plurality);
333 | break;
334 | default:
335 | typeString = pluralizeName(type.typeKind, plurality);
336 | break;
337 | }
338 | const useTag = type.tag && type.typeKind !== TypeKind.GENERIC;
339 | return (
340 | (useTag ? '_' + type.tag + '_ (' : '') +
341 | typeString +
342 | (type.genericParameters
343 | ? ' (of ' +
344 | joinList(
345 | type.genericParameters.map(param => describeType(param, meta, PLURALITY.SINGULAR)),
346 | ) +
347 | ')'
348 | : '') +
349 | (type.isMutable ? ' (which can be mutated)' : '') +
350 | (useTag ? ')' : '')
351 | );
352 | }
353 |
354 | export function getMetaDescription(type: Type, meta: MetaDescription) {
355 | switch (type.typeKind) {
356 | case TypeKind.FUNCTION:
357 | const functionType = type as FunctionType;
358 | if (functionType.genericTypes) {
359 | for (const param of functionType.genericTypes) {
360 | if (param.tag) {
361 | meta.generics[param.tag] = describeGeneric(param);
362 | getMetaDescription(param.extendingType, meta);
363 | }
364 | }
365 | }
366 | break;
367 | }
368 | if (type.genericParameters) {
369 | for (const param of type.genericParameters) {
370 | if (type.typeKind === TypeKind.ALIAS) {
371 | const name = (param as AliasType).aliasName;
372 | const commonName = getCommonNameForTypeVariable(name);
373 | if (commonName) {
374 | meta.generics[name] = commonName;
375 | }
376 | }
377 | }
378 | }
379 | return meta;
380 | }
381 |
--------------------------------------------------------------------------------
/tools/docublox/astTypings.ts:
--------------------------------------------------------------------------------
1 | export interface Node {
2 | type: string;
3 | loc: {
4 | start: {
5 | line: number;
6 | };
7 | };
8 | }
9 | export interface Identifier extends Node {
10 | name: string;
11 | }
12 | export interface MemberExpression extends Node {
13 | base: Identifier;
14 | identifier: Identifier | MemberExpression;
15 | }
16 | export interface FunctionDeclaration extends Node {
17 | identifier: Identifier | MemberExpression;
18 | parameters: Identifier[];
19 | }
20 | export interface Comment extends Node {
21 | raw: string;
22 | value: string;
23 | }
24 |
25 | export interface AssignmentStatement extends Node {
26 | variables: Node[];
27 | }
28 |
--------------------------------------------------------------------------------
/tools/docublox/generateMakeDocsYml.ts:
--------------------------------------------------------------------------------
1 | import { basename } from 'path';
2 |
3 | export function generateMakeDocsYml(files) {
4 | return `
5 | site_name: Rodash Documentation
6 | site_url: https://codekingdomsteam.github.io/rodash/
7 | repo_name: CodeKingdomsTeam/rodash
8 | repo_url: https://github.com/CodeKingdomsTeam/rodash
9 |
10 | theme:
11 | name: material
12 | palette:
13 | primary: 'Grey'
14 | accent: 'Blue'
15 |
16 | nav:
17 | - Home: index.md
18 | - Getting Started: getting-started.md
19 | - API Reference:
20 | ${files.map(name => ` - ${basename(name, '.md')}: api/${name}`).join('\n')}
21 | - Types: types.md
22 | - Glossary: glossary.md
23 |
24 | extra_css:
25 | - docublox.css
26 |
27 | markdown_extensions:
28 | - admonition
29 | - codehilite:
30 | guess_lang: false
31 | - toc:
32 | permalink: true
33 | - pymdownx.superfences
34 | `;
35 | }
36 |
--------------------------------------------------------------------------------
/tools/docublox/generateMd.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Node,
3 | Comment,
4 | MemberExpression,
5 | FunctionDeclaration,
6 | Identifier,
7 | AssignmentStatement,
8 | } from './astTypings';
9 | import { keyBy } from 'lodash';
10 | import { GlossaryMap } from './index';
11 | import * as parser from './typeParser';
12 | import {
13 | describeType,
14 | stringifyType,
15 | FunctionType,
16 | TypeKind,
17 | PLURALITY,
18 | getMetaDescription,
19 | describeGeneric,
20 | } from './LuaTypes';
21 |
22 | interface DocEntry {
23 | tag: string;
24 | content: string;
25 | }
26 |
27 | interface Doc {
28 | typeString: string;
29 | typing: FunctionType;
30 | comments: string[];
31 | entries: DocEntry[];
32 | }
33 | export interface MdDoc {
34 | name: string;
35 | content: string;
36 | sortName: string;
37 | comments: string[];
38 | }
39 |
40 | export interface LibraryProps {
41 | libName: string;
42 | fileName: string;
43 | glossaryMap: GlossaryMap;
44 | rootUrl: string;
45 | }
46 |
47 | export interface Nodes {
48 | [line: string]: Node;
49 | }
50 |
51 | export function generateMd(libraryProps: LibraryProps, nodes: Nodes, maxLine: number) {
52 | let topComment = '';
53 | let inHeader = true;
54 | const functions: MdDoc[] = [];
55 | const members: MdDoc[] = [];
56 | for (let i = 0; i <= maxLine; i++) {
57 | if (!nodes[i]) {
58 | continue;
59 | }
60 | const node = nodes[i];
61 | if (inHeader) {
62 | if (node.type === 'Comment') {
63 | const { nodeText } = getCommentTextAndEntries(node as Comment);
64 | topComment += nodeText + '\n';
65 | } else {
66 | inHeader = false;
67 | }
68 | }
69 | if (node.type === 'FunctionDeclaration' || node.type === 'AssignmentStatement') {
70 | const doc = getDocAtLocation(node.loc.start.line, nodes);
71 | if (!doc.typing) {
72 | console.log('Skipping untyped method:', doc.comments);
73 | } else {
74 | if (node.type === 'AssignmentStatement') {
75 | const member = getMemberDoc(libraryProps, node as AssignmentStatement, doc);
76 | if (member) {
77 | if (!member.comments.length) {
78 | console.log('Skipping undocumented method:', member.sortName);
79 | } else {
80 | members.push(member);
81 | }
82 | }
83 | } else {
84 | const fn = getFnDoc(libraryProps, node as FunctionDeclaration, doc);
85 | if (fn) {
86 | if (!fn.comments.length) {
87 | console.log('Skipping undocumented method:', fn.sortName);
88 | } else {
89 | functions.push(fn);
90 | }
91 | }
92 | }
93 | }
94 | }
95 | functions.sort((a, b) => (a.sortName.toLowerCase() < b.sortName.toLowerCase() ? -1 : 1));
96 | members.sort((a, b) => (a.sortName.toLowerCase() < b.sortName.toLowerCase() ? -1 : 1));
97 | }
98 |
99 | const functionDocs = functions.length
100 | ? `## Functions
101 |
102 | ${functions.map(fn => fn.content).join('\n\n---\n\n')}`
103 | : '';
104 |
105 | const memberDocs = members.length
106 | ? `## Members
107 |
108 | ${members.map(fn => fn.content).join('\n\n---\n\n')}`
109 | : '';
110 |
111 | return `
112 | # ${libraryProps.fileName}
113 |
114 | ${topComment}
115 |
116 | ${functionDocs}
117 |
118 | ${memberDocs}
119 |
120 | `;
121 | }
122 |
123 | function getDocAtLocation(loc: number, nodes: Nodes): Doc {
124 | let typing: FunctionType;
125 | let typeString: string;
126 | const comments = [];
127 | const entries = [];
128 | // Work backwards from the location to find comments above the specified point, which will form
129 | // documentation for the node at the location specified.
130 | for (let i = loc - 1; i >= 0; i--) {
131 | const node = nodes[i];
132 | if (!node) {
133 | continue;
134 | }
135 | if (node.type === 'Comment') {
136 | const comment = node as Comment;
137 | if (comment.raw.match(/^\-\-\:/)) {
138 | const type = comment.value.substring(1);
139 | try {
140 | typeString = type.trim();
141 | typing = parser.parse(typeString) as FunctionType;
142 | } catch (e) {
143 | console.warn('BadType:', type, e);
144 | }
145 | } else {
146 | const { nodeText, nodeEntries } = getCommentTextAndEntries(comment);
147 | comments.push(nodeText);
148 | entries.push(...nodeEntries);
149 | }
150 | } else {
151 | break;
152 | }
153 | }
154 | return {
155 | typeString,
156 | typing,
157 | comments: comments.reverse(),
158 | entries: entries,
159 | };
160 | }
161 |
162 | function getCommentTextAndEntries(commentNode: Comment) {
163 | const nodeEntries = [];
164 | let lastEntry;
165 | let content: string[] = [];
166 | commentNode.value.split('\n').forEach(line => {
167 | const lineWithoutIndent = line.replace(/^[\s\t][\s\t]?/g, '');
168 | const entryMatch = lineWithoutIndent.match(/^\@([a-z]+)\s?(.*)/);
169 | if (entryMatch) {
170 | lastEntry = {
171 | tag: entryMatch[1],
172 | content: entryMatch[2],
173 | };
174 | nodeEntries.push(lastEntry);
175 | } else if (lastEntry) {
176 | lastEntry.content += '\n' + lineWithoutIndent;
177 | } else {
178 | content.push(lineWithoutIndent);
179 | }
180 | });
181 |
182 | return {
183 | nodeText: content.join('\n'),
184 | nodeEntries,
185 | };
186 | }
187 |
188 | function getMemberDoc(
189 | libraryProps: LibraryProps,
190 | node: AssignmentStatement,
191 | doc: Doc,
192 | ): MdDoc | undefined {
193 | const member = node.variables[0] as MemberExpression;
194 | const name = (member.identifier as Identifier).name;
195 | const baseName = member.base.name;
196 | const prefixName = baseName === libraryProps.fileName ? libraryProps.libName : baseName;
197 | const sortName = baseName === libraryProps.fileName ? name : baseName + '.' + name;
198 | const lines = [];
199 | lines.push(
200 | `### ${name} \n`,
201 | '```lua' +
202 | `
203 | ${prefixName}.${name} -- ${doc.typeString}
204 | ` +
205 | '```',
206 | doc.comments,
207 | );
208 | const examples = filterEntries(doc.entries, 'example');
209 | if (examples.length) {
210 | lines.push(
211 | '\n**Examples**\n',
212 | ...examples.map(example => '```lua\n' + example.content + '\n```\n\n'),
213 | );
214 | }
215 | return {
216 | name,
217 | sortName,
218 | content: lines.join('\n'),
219 | comments: doc.comments,
220 | };
221 | }
222 |
223 | function getFnDoc(
224 | libraryProps: LibraryProps,
225 | node: FunctionDeclaration,
226 | doc: Doc,
227 | ): MdDoc | undefined {
228 | const lines = [];
229 | if (node.identifier && node.identifier.type === 'MemberExpression') {
230 | const member = node.identifier as MemberExpression;
231 | const name = (member.identifier as Identifier).name;
232 | const baseName = member.base.name;
233 | const params = node.parameters.map(id => (id.type === 'VarargLiteral' ? '...' : id.name));
234 | const prefixName = baseName === libraryProps.fileName ? libraryProps.libName : baseName;
235 | const sortName = baseName === libraryProps.fileName ? name : baseName + '.' + name;
236 |
237 | const returnType = doc.typing.returnType || { typeKind: TypeKind.ANY, isRestParameter: true };
238 | const returnTypeString = stringifyType(returnType);
239 |
240 | const traits = filterEntries(doc.entries, 'trait');
241 | if (traits.length) {
242 | lines.push(
243 | `${traits.map(entry => entry.content).join(' ')}
`,
244 | );
245 | }
246 | lines.push(
247 | `### ${sortName} \n`,
248 | '```lua' +
249 | `
250 | function ${prefixName}.${name}(${params.join(', ')}) --> ${returnTypeString}
251 | ` +
252 | '```',
253 | doc.comments,
254 | );
255 | const paramEntries = filterEntries(doc.entries, 'param');
256 | const paramMap = keyBy(
257 | paramEntries.map(entry => entry.content.match(/^\s*([A-Za-z.]+)\s(.*)/)),
258 | entry => entry && entry[1],
259 | );
260 | lines.push('\n**Type**\n', '`' + doc.typeString + '`');
261 |
262 | const metaDescription = getMetaDescription(doc.typing, {
263 | generics: {
264 | T: 'the type of _self_',
265 | },
266 | rootUrl: libraryProps.rootUrl,
267 | });
268 |
269 | if (doc.typing.genericTypes) {
270 | lines.push(
271 | '\n**Generics**\n',
272 | ...doc.typing.genericTypes.map(
273 | generic =>
274 | `\n> __${generic.tag}__ - \`${stringifyType(
275 | generic.extendingType,
276 | )}\` - ${describeGeneric(generic, metaDescription)}`,
277 | ),
278 | );
279 | }
280 | const parameterTypes = doc.typing.parameterTypes || [];
281 | if (params.length) {
282 | lines.push(
283 | '\n**Parameters**\n',
284 | ...params.map((param, i) => {
285 | const parameterType = parameterTypes[i] || {
286 | typeKind: TypeKind.ANY,
287 | };
288 | return `> __${param}__ - \`${stringifyType(parameterType)}\` - ${describeType(
289 | parameterType,
290 | metaDescription,
291 | PLURALITY.SINGULAR,
292 | )} ${paramMap[param] && paramMap[param][2] ? ' - ' + paramMap[param][2] : ''}\n>`;
293 | }),
294 | );
295 | }
296 | const returns = filterEntries(doc.entries, 'returns');
297 | lines.push('\n**Returns**\n');
298 | const returnTypeDescription = describeType(returnType, metaDescription, PLURALITY.SINGULAR);
299 | if (returns.length) {
300 | lines.push(
301 | ...returns.map(
302 | ({ content }) => `\n> \`${returnTypeString}\` - ${returnTypeDescription} - ${content}`,
303 | ),
304 | );
305 | } else {
306 | lines.push(`\n> \`${returnTypeString}\` - ${returnTypeDescription}`);
307 | }
308 | const throws = filterEntries(doc.entries, 'throws');
309 | if (throws.length) {
310 | lines.push('\n**Throws**\n');
311 | lines.push(...formatList(throws));
312 | }
313 |
314 | const rejects = filterEntries(doc.entries, 'rejects');
315 | if (rejects.length) {
316 | lines.push('\n**Rejects**\n');
317 | lines.push(
318 | ...formatList(rejects, line => {
319 | switch (line) {
320 | case 'passthrough':
321 | return '_passthrough_ - The returned promise will reject if promises passed as arguments reject.';
322 | default:
323 | return line;
324 | }
325 | }),
326 | );
327 | }
328 |
329 | const examples = filterEntries(doc.entries, 'example');
330 | if (examples.length) {
331 | lines.push(
332 | '\n**Examples**\n',
333 | ...examples.map(example => '```lua\n' + example.content + '\n```\n\n'),
334 | );
335 | }
336 | const usage = filterEntries(doc.entries, 'usage');
337 | if (usage.length) {
338 | lines.push('\n**Usage**\n', ...formatList(usage));
339 | }
340 | const see = filterEntries(doc.entries, 'see');
341 | if (see.length) {
342 | lines.push('\n**See**\n', ...see.map(({ content }) => `\n* ${content}`));
343 | }
344 | return {
345 | name,
346 | sortName,
347 | content: lines.join('\n'),
348 | comments: doc.comments,
349 | };
350 | }
351 | }
352 |
353 | function formatList(entries: DocEntry[], modifier?: (line: string) => string) {
354 | return entries.map(({ content }) => '\n* ' + (modifier ? modifier(content) : content));
355 | }
356 |
357 | function filterEntries(entries: DocEntry[], tag: string) {
358 | return entries.filter(entry => entry.tag === tag);
359 | }
360 |
--------------------------------------------------------------------------------
/tools/docublox/index.ts:
--------------------------------------------------------------------------------
1 | import { parse } from 'luaparse';
2 | import { readdir, readFile, writeFile } from 'fs-extra';
3 | import { basename, extname, join } from 'path';
4 | import { ArgumentParser } from 'argparse';
5 | import { generateMd, Nodes, LibraryProps } from './generateMd';
6 | import { generateMakeDocsYml } from './generateMakeDocsYml';
7 | import {
8 | FunctionDeclaration,
9 | MemberExpression,
10 | Identifier,
11 | AssignmentStatement,
12 | } from './astTypings';
13 | import { uniq } from 'lodash';
14 | const parser = new ArgumentParser({
15 | version: '1.0.0',
16 | addHelp: true,
17 | description: 'Generate markdown docs for lua files',
18 | });
19 | parser.addArgument(['-o', '--output'], {
20 | help: 'The directory where md files should be written to',
21 | defaultValue: '.',
22 | });
23 | parser.addArgument(['-l', '--libName'], {
24 | help: 'The name of the library',
25 | });
26 | parser.addArgument(['-r', '--rootUrl'], {
27 | help: 'The root URL library',
28 | });
29 | parser.addArgument('source', {
30 | help: 'The directory where any lua files should be read from',
31 | defaultValue: '.',
32 | });
33 | parser.addArgument('docsSource', {
34 | help: 'The directory where any md files should be read from',
35 | defaultValue: '.',
36 | });
37 |
38 | interface FileParse {
39 | name: string;
40 | maxLines: number;
41 | nodesByLine: Nodes;
42 | docNames: string[];
43 | }
44 | export interface Glossary {
45 | [module: string]: string[];
46 | }
47 |
48 | export interface Options {
49 | libName: string;
50 | rootUrl: string;
51 | source: string;
52 | docsSource: string;
53 | output: string;
54 | }
55 |
56 | export function substituteLinks(libraryProps: LibraryProps, text: string) {
57 | return text.replace(/`([A-Za-z]+)\.([A-Za-z]+)`/g, (match, libName, docName) => {
58 | const glossaryLink = libraryProps.glossaryMap[docName];
59 | if (!glossaryLink) {
60 | console.log('Missing glossary link', match);
61 | return match;
62 | } else {
63 | return glossaryLink.fullText;
64 | }
65 | });
66 | }
67 |
68 | async function processSourceFiles(options: Options) {
69 | const { source, docsSource, libName, rootUrl, output } = options;
70 | const files = await readdir(source);
71 | const fileParses: FileParse[] = await Promise.all(
72 | files
73 | .filter(file => extname(file) === '.lua' && basename(file) !== 'init.lua')
74 | .map(async file => {
75 | const text = await readFile(join(source, file), 'utf8');
76 | const nodesByLine: Nodes = {};
77 | let maxLines = 0;
78 | parse(text, {
79 | comments: true,
80 | locations: true,
81 | onCreateNode: node => {
82 | const line = node.loc.start.line;
83 | const currentNode = nodesByLine[line];
84 | if (!currentNode || currentNode.type !== 'Comment') {
85 | nodesByLine[line] = node;
86 | }
87 | maxLines = Math.max(line, maxLines);
88 | },
89 | });
90 | const name = basename(file, '.lua');
91 | const docNames = getDocNames(nodesByLine, maxLines);
92 | return { name, nodesByLine, maxLines, docNames };
93 | }),
94 | );
95 | const glossary: Glossary = {};
96 | for (const fileParse of fileParses) {
97 | glossary[fileParse.name] = fileParse.docNames;
98 | }
99 |
100 | const glossaryLinks = getGlossaryLinks(options, glossary);
101 | const glossaryWritePromise = writeFile(join(output, 'glossary.md'), getGlossary(glossaryLinks));
102 | const sourceFilesWritePromise = Promise.all(
103 | fileParses.map(async ({ name, nodesByLine, maxLines }) => {
104 | const outputName = name + '.md';
105 | const libraryProps = {
106 | fileName: name,
107 | libName,
108 | glossaryMap: glossaryLinks,
109 | rootUrl,
110 | };
111 | const mdText = generateMd(libraryProps, nodesByLine, maxLines);
112 | const mdTextWithLinks = substituteLinks(libraryProps, mdText);
113 | await writeFile(join(output, 'api', outputName), mdTextWithLinks);
114 | console.log('Built md:', outputName);
115 | return outputName;
116 | }),
117 | );
118 | const mdFilesWritePromise = processMdSourceFiles(docsSource, output, glossaryLinks);
119 |
120 | const filePromises = [
121 | glossaryWritePromise,
122 | sourceFilesWritePromise.then(mdFiles => writeFile('mkdocs.yml', generateMakeDocsYml(mdFiles))),
123 | mdFilesWritePromise,
124 | ];
125 |
126 | return Promise.all(filePromises);
127 | }
128 |
129 | async function processMdSourceFiles(docsSource: string, output: string, glossaryMap: GlossaryMap) {
130 | const files = await readdir(docsSource);
131 | return files
132 | .filter(file => extname(file) === '.md')
133 | .map(async file => {
134 | const libraryProps = {
135 | fileName: file,
136 | libName: 'dash',
137 | glossaryMap,
138 | rootUrl: '/rodash/',
139 | };
140 | const text = await readFile(join(docsSource, file), 'utf8');
141 | const textWithLinks = substituteLinks(libraryProps, text);
142 | return writeFile(join(output, file), textWithLinks);
143 | });
144 | }
145 |
146 | export function getDocNames(nodes: Nodes, maxLine: number): string[] {
147 | const names = [];
148 | for (const line in nodes) {
149 | const node = nodes[line];
150 | if (node.type === 'FunctionDeclaration') {
151 | const fnNode = node as FunctionDeclaration;
152 | if (fnNode.identifier && fnNode.identifier.type === 'MemberExpression') {
153 | const member = fnNode.identifier as MemberExpression;
154 | const name = (member.identifier as Identifier).name;
155 | names.push(member.base.name + '.' + name);
156 | }
157 | } else if (node.type === 'AssignmentStatement') {
158 | const assignmentNode = node as AssignmentStatement;
159 | const member = assignmentNode.variables[0] as MemberExpression;
160 | if (member && member.type === 'MemberExpression') {
161 | const name = (member.identifier as Identifier).name;
162 | names.push(member.base.name + '.' + name);
163 | }
164 | }
165 | }
166 | return names;
167 | }
168 |
169 | interface GlossaryLink {
170 | name: string;
171 | text: string;
172 | fullText: string;
173 | link: string;
174 | }
175 |
176 | export interface GlossaryMap {
177 | [name: string]: GlossaryLink;
178 | }
179 |
180 | function getGlossaryLinks(options: Options, glossary: Glossary) {
181 | const glossaryMap: GlossaryMap = {};
182 | for (const fileName in glossary) {
183 | for (const docName of glossary[fileName]) {
184 | const [memberName, idName] = docName.split('.');
185 | const shortName = memberName === fileName ? idName : docName;
186 | const link = `${options.rootUrl}api/${fileName}/#${shortName.toLowerCase()}`;
187 | glossaryMap[shortName] = {
188 | name: shortName,
189 | link,
190 | text: `[${shortName}](${link})`,
191 | fullText: `[${options.libName}.${shortName}](${link})`,
192 | };
193 | }
194 | }
195 | return glossaryMap;
196 | }
197 |
198 | function getGlossary(glossaryMap: GlossaryMap) {
199 | const textLinks = Object.values(glossaryMap).sort((a: GlossaryLink, b: GlossaryLink) =>
200 | a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1,
201 | );
202 | const list = uniq(textLinks.map(link => '* ' + link.text)).join('\n');
203 | return `
204 | # Glossary
205 |
206 | ${list}
207 | `;
208 | }
209 |
210 | (async function() {
211 | try {
212 | const args = parser.parseArgs();
213 | await processSourceFiles(args), console.log('Done!');
214 | } catch (e) {
215 | console.error(e);
216 | process.exit(1);
217 | }
218 | })();
219 |
--------------------------------------------------------------------------------
/tools/docublox/typeGrammar.peg:
--------------------------------------------------------------------------------
1 | Type "Type"
2 | = TypeDef
3 | / _ type:GenericFunction _ {
4 | return type;
5 | }
6 |
7 | TypeDef "TypeDef"
8 | = "type" _ left:Type _ "=" _ right:Type {
9 | return {
10 | typeKind: 'definition',
11 | left,
12 | right
13 | }
14 | }
15 |
16 | GenericFunction "GenericFunction"
17 | = generics:GenericTuple _ tuple:Tuple? {
18 | if ( tuple ) {
19 | tuple.genericTypes = generics;
20 | return tuple;
21 | }
22 | return {
23 | typeKind: 'tuple',
24 | elementTypes: [],
25 | genericTypes: generics
26 | }
27 | }
28 | / Tuple
29 |
30 | GenericTuple "GenericTuple"
31 | = "<" _ left:Generic right:(_ "," _ Generic)* _ ">" {
32 | const generics = [];
33 | generics.push(left);
34 | right.map(key => {
35 | generics.push(key[3]);
36 | })
37 | return generics;
38 | }
39 |
40 | Generic "Generic"
41 | = isRestParameter:"..."? _ left:GenericName right:(_ ":" _ UnitaryType)? {
42 | var generic = {
43 | tag: left,
44 | typeKind: 'generic',
45 | extendingType: right ? right[3] : {
46 | typeKind: 'any'
47 | }
48 | };
49 | if (isRestParameter) {
50 | generic.isRestParameter = true
51 | }
52 | return generic;
53 | }
54 |
55 | Tuple "Tuple"
56 | = left:Union right:(_ "," _ Union)* functionType:(_ "->" _ ReturnType)? {
57 | let elementTypes = [left].concat( right.map(key => key[3]) );
58 | if ( functionType ) {
59 | if ( !right.length && left.typeKind === 'tuple') {
60 | elementTypes = left.elementTypes
61 | }
62 | let fn = {
63 | typeKind: 'function',
64 | parameterTypes: elementTypes,
65 | returnType: functionType[3]
66 | };
67 | return fn;
68 | }
69 | if ( !right.length ) {
70 | return left;
71 | }
72 | return {
73 | typeKind: 'tuple',
74 | elementTypes
75 | };
76 | }
77 |
78 | ReturnType "ReturnType"
79 | = isYield:"yield"? type:Type {
80 | if (isYield) {
81 | type.isYielding = true;
82 | }
83 | return type;
84 | }
85 |
86 | Union "Union"
87 | = left:Intersection right:(_ "|" _ Intersection)* {
88 | if ( !right.length ) {
89 | return left;
90 | }
91 | return {
92 | typeKind: 'union',
93 | allowedTypes: [left].concat( right.map(key => key[3]) )
94 | }
95 | }
96 |
97 | Intersection "Intersection"
98 | = left:UnitaryType right:(_ "&" _ UnitaryType)* {
99 | if ( !right.length ) {
100 | return left;
101 | }
102 | return {
103 | typeKind: 'intersection',
104 | requiredTypes: [left].concat( right.map(key => key[3]) )
105 | }
106 | }
107 |
108 | UnitaryType "UnitaryType"
109 | = mutType:("mut" _)? tag:(ParameterTag _ ":")? restParameter:("..." _)? type:FixedType generics:(_ "<" _ GenericArgs _ ">")? capture:(_ "[]" / _ "{}")* optional:(_ "?")? {
110 | if ( generics ) {
111 | type.genericParameters = generics[3];
112 | }
113 | if (capture.length) {
114 | type = { typeKind: 'table', dimensions: capture.map(function(match) { return {isArray:match[1] === "[]"} }), elementType: type }
115 | }
116 | if (restParameter) {
117 | type.isRestParameter = true;
118 | }
119 | if (mutType) {
120 | type.isMutable = true;
121 | }
122 | if (optional) {
123 | type = {
124 | typeKind: 'optional',
125 | optionalType: type
126 | }
127 | }
128 | if ( tag ) {
129 | type.tag = tag[0];
130 | }
131 | return type;
132 | }
133 | / "..." {
134 | return {
135 | isRestParameter: true,
136 | typeKind: 'any'
137 | };
138 | }
139 |
140 | GenericArgs "GenericArgs"
141 | = left:UnitaryType right:(_ "," _ GenericArgs)? {
142 | return [left].concat(right ? right[3] : []);
143 | }
144 |
145 | FixedType "FixedType"
146 | = "{" _ tuple:Tuple?_ "}" {
147 | return {
148 | typeKind: 'array',
149 | valueType: tuple
150 | };
151 | }
152 | / "{" _ iterator:IteratorType _ "}" {
153 | return {
154 | typeKind: 'dictionary',
155 | keyType: iterator.keyType,
156 | valueType: iterator.valueType
157 | }
158 | }
159 | / TypeName
160 | / "(" _ type:Type? _ ")" {
161 | return type || {
162 | typeKind: 'void'
163 | };
164 | }
165 |
166 | IteratorType "IteratorType"
167 | = "[" _ key:UnitaryType _ "]" _ ":" _ value:Tuple {
168 | return {
169 | keyType: key,
170 | valueType: value
171 | };
172 | }
173 |
174 | GenericName "GenericName"
175 | = _ [A-Za-z_][A-Za-z0-9_]* {
176 | return text();
177 | }
178 |
179 | ParameterTag "ParameterTag"
180 | = _ [A-Za-z_][A-Za-z0-9_]* {
181 | return text();
182 | }
183 |
184 | TypeName "TypeName"
185 | = _ name:([A-Za-z][A-Za-z0-9._]*) {
186 |
187 | name = name[0] + name[1].join('');
188 |
189 | switch (name) {
190 |
191 | case 'char':
192 | case 'string':
193 | case 'number':
194 | case 'int':
195 | case 'uint':
196 | case 'float':
197 | case 'number':
198 | case 'bool':
199 | case 'nil':
200 | case 'never':
201 | case 'fail':
202 | case 'any':
203 | case 'void':
204 |
205 | return {
206 | typeKind: name
207 | };
208 |
209 | default:
210 |
211 | return {
212 | typeKind: 'alias',
213 | aliasName: name
214 | }
215 |
216 | }
217 | }
218 |
219 | _ "whitespace"
220 | = [ \t\n\r]*
--------------------------------------------------------------------------------
/tools/format.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -o nounset
4 | set -o errexit
5 | set -o pipefail
6 |
7 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
8 | cd "$SCRIPT_DIR"
9 | cd ..
10 |
11 | if [ $# -eq 0 ]
12 | then
13 | find src spec -name '*.lua' -exec node_modules/lua-fmt/dist/bin/luafmt.js --use-tabs --write-mode replace {} \;
14 | else
15 | for FILE in "$@"
16 | do
17 | node_modules/lua-fmt/dist/bin/luafmt.js --use-tabs --write-mode replace "$FILE"
18 | done
19 | fi
20 |
--------------------------------------------------------------------------------
/tools/luacheck.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -o nounset
4 | set -o errexit
5 | set -o pipefail
6 |
7 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
8 | cd "$SCRIPT_DIR"
9 | cd ..
10 |
11 | export PATH="lua_install/bin:$PATH"
12 |
13 | if [ $# -eq 0 ]
14 | then
15 | luacheck src spec tools
16 | else
17 | luacheck "$@"
18 | fi
19 |
20 |
--------------------------------------------------------------------------------
/tools/testInit.lua:
--------------------------------------------------------------------------------
1 | if arg[1] == "debug" then
2 | package.cpath = package.cpath .. ";tools/?.dylib"
3 | local lrdb = require("lrdb_server")
4 | print("Waiting for debugger to attach...")
5 | lrdb.activate(21110)
6 | end
7 |
8 | script = {
9 | Async = "Async",
10 | Tables = "Tables",
11 | Classes = "Classes",
12 | Functions = "Functions",
13 | Arrays = "Arrays",
14 | Strings = "Strings",
15 | Parent = {
16 | Async = "Async",
17 | Tables = "Tables",
18 | Classes = "Classes",
19 | Functions = "Functions",
20 | Arrays = "Arrays",
21 | Strings = "Strings",
22 | Parent = {
23 | t = "t",
24 | Promise = "roblox-lua-promise",
25 | luassert = "luassert"
26 | }
27 | }
28 | }
29 | Random = {
30 | new = function()
31 | local n = 0
32 | return {
33 | NextNumber = function()
34 | n = n + 1
35 | return n
36 | end
37 | }
38 | end
39 | }
40 | warn = function(...)
41 | print("[WARN]", ...)
42 | end
43 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "pretty": true,
4 | "target": "es2017"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@types/commander@^2.3.31":
6 | version "2.12.2"
7 | resolved "https://registry.yarnpkg.com/@types/commander/-/commander-2.12.2.tgz#183041a23842d4281478fa5d23c5ca78e6fd08ae"
8 | dependencies:
9 | commander "*"
10 |
11 | "@types/diff@^3.2.0":
12 | version "3.5.1"
13 | resolved "https://registry.yarnpkg.com/@types/diff/-/diff-3.5.1.tgz#30253f6e177564ad7da707b1ebe46d3eade71706"
14 |
15 | "@types/get-stdin@^5.0.0":
16 | version "5.0.1"
17 | resolved "https://registry.yarnpkg.com/@types/get-stdin/-/get-stdin-5.0.1.tgz#46afbcaf09e94fe025afa07ae994ac3168adbdf3"
18 | dependencies:
19 | "@types/node" "*"
20 |
21 | "@types/node@*":
22 | version "10.9.4"
23 | resolved "https://registry.yarnpkg.com/@types/node/-/node-10.9.4.tgz#0f4cb2dc7c1de6096055357f70179043c33e9897"
24 |
25 | arg@^4.1.0:
26 | version "4.1.1"
27 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.1.tgz#485f8e7c390ce4c5f78257dbea80d4be11feda4c"
28 | integrity sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==
29 |
30 | argparse@^1.0.10:
31 | version "1.0.10"
32 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
33 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
34 | dependencies:
35 | sprintf-js "~1.0.2"
36 |
37 | buffer-from@^1.0.0:
38 | version "1.1.1"
39 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
40 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
41 |
42 | commander@*, commander@^2.9.0:
43 | version "2.17.1"
44 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
45 |
46 | diff@^3.3.0:
47 | version "3.5.0"
48 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
49 |
50 | diff@^4.0.1:
51 | version "4.0.1"
52 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff"
53 | integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==
54 |
55 | fs-extra@^8.1.0:
56 | version "8.1.0"
57 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
58 | integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
59 | dependencies:
60 | graceful-fs "^4.2.0"
61 | jsonfile "^4.0.0"
62 | universalify "^0.1.0"
63 |
64 | get-stdin@^5.0.1:
65 | version "5.0.1"
66 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
67 |
68 | graceful-fs@^4.1.6, graceful-fs@^4.2.0:
69 | version "4.2.0"
70 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b"
71 | integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==
72 |
73 | jsonfile@^4.0.0:
74 | version "4.0.0"
75 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
76 | integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
77 | optionalDependencies:
78 | graceful-fs "^4.1.6"
79 |
80 | lodash@^4.17.15:
81 | version "4.17.15"
82 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
83 | integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
84 |
85 | lua-fmt@^2.6.0:
86 | version "2.6.0"
87 | resolved "https://registry.yarnpkg.com/lua-fmt/-/lua-fmt-2.6.0.tgz#ef9ac0573d1da7330dca09c022c39a33aed347a3"
88 | dependencies:
89 | "@types/commander" "^2.3.31"
90 | "@types/diff" "^3.2.0"
91 | "@types/get-stdin" "^5.0.0"
92 | commander "^2.9.0"
93 | diff "^3.3.0"
94 | get-stdin "^5.0.1"
95 | luaparse oxyc/luaparse#ac42a00ebf4020b8c9d3219e4b0f84bf7ce6e802
96 |
97 | luaparse@^0.2.1, luaparse@oxyc/luaparse#ac42a00ebf4020b8c9d3219e4b0f84bf7ce6e802:
98 | version "0.2.1"
99 | resolved "https://codeload.github.com/oxyc/luaparse/tar.gz/ac42a00ebf4020b8c9d3219e4b0f84bf7ce6e802"
100 |
101 | make-error@^1.1.1:
102 | version "1.3.5"
103 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8"
104 | integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==
105 |
106 | source-map-support@^0.5.6:
107 | version "0.5.12"
108 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599"
109 | integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==
110 | dependencies:
111 | buffer-from "^1.0.0"
112 | source-map "^0.6.0"
113 |
114 | source-map@^0.6.0:
115 | version "0.6.1"
116 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
117 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
118 |
119 | sprintf-js@~1.0.2:
120 | version "1.0.3"
121 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
122 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
123 |
124 | ts-node@^8.3.0:
125 | version "8.3.0"
126 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.3.0.tgz#e4059618411371924a1fb5f3b125915f324efb57"
127 | integrity sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==
128 | dependencies:
129 | arg "^4.1.0"
130 | diff "^4.0.1"
131 | make-error "^1.1.1"
132 | source-map-support "^0.5.6"
133 | yn "^3.0.0"
134 |
135 | typescript@^3.5.3:
136 | version "3.5.3"
137 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
138 | integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
139 |
140 | universalify@^0.1.0:
141 | version "0.1.2"
142 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
143 | integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
144 |
145 | yn@^3.0.0:
146 | version "3.1.0"
147 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.0.tgz#fcbe2db63610361afcc5eb9e0ac91e976d046114"
148 | integrity sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==
149 |
--------------------------------------------------------------------------------