1import {has, isArray} from "./util"
2import {SourceLocation} from "./locutil"
3
4// A second optional argument can be given to further configure
5// the parser process. These options are recognized:
6
7export const defaultOptions = {
8  // `ecmaVersion` indicates the ECMAScript version to parse. Must
9  // be either 3, 5, 6 (2015), 7 (2016), or 8 (2017). This influences support
10  // for strict mode, the set of reserved words, and support for
11  // new syntax features. The default is 7.
12  ecmaVersion: 7,
13  // `sourceType` indicates the mode the code should be parsed in.
14  // Can be either `"script"` or `"module"`. This influences global
15  // strict mode and parsing of `import` and `export` declarations.
16  sourceType: "script",
17  // `onInsertedSemicolon` can be a callback that will be called
18  // when a semicolon is automatically inserted. It will be passed
19  // th position of the comma as an offset, and if `locations` is
20  // enabled, it is given the location as a `{line, column}` object
21  // as second argument.
22  onInsertedSemicolon: null,
23  // `onTrailingComma` is similar to `onInsertedSemicolon`, but for
24  // trailing commas.
25  onTrailingComma: null,
26  // By default, reserved words are only enforced if ecmaVersion >= 5.
27  // Set `allowReserved` to a boolean value to explicitly turn this on
28  // an off. When this option has the value "never", reserved words
29  // and keywords can also not be used as property names.
30  allowReserved: null,
31  // When enabled, a return at the top level is not considered an
32  // error.
33  allowReturnOutsideFunction: false,
34  // When enabled, import/export statements are not constrained to
35  // appearing at the top of the program.
36  allowImportExportEverywhere: false,
37  // When enabled, hashbang directive in the beginning of file
38  // is allowed and treated as a line comment.
39  allowHashBang: false,
40  // When `locations` is on, `loc` properties holding objects with
41  // `start` and `end` properties in `{line, column}` form (with
42  // line being 1-based and column 0-based) will be attached to the
43  // nodes.
44  locations: false,
45  // A function can be passed as `onToken` option, which will
46  // cause Acorn to call that function with object in the same
47  // format as tokens returned from `tokenizer().getToken()`. Note
48  // that you are not allowed to call the parser from the
49  // callback—that will corrupt its internal state.
50  onToken: null,
51  // A function can be passed as `onComment` option, which will
52  // cause Acorn to call that function with `(block, text, start,
53  // end)` parameters whenever a comment is skipped. `block` is a
54  // boolean indicating whether this is a block (`/* */`) comment,
55  // `text` is the content of the comment, and `start` and `end` are
56  // character offsets that denote the start and end of the comment.
57  // When the `locations` option is on, two more parameters are
58  // passed, the full `{line, column}` locations of the start and
59  // end of the comments. Note that you are not allowed to call the
60  // parser from the callback—that will corrupt its internal state.
61  onComment: null,
62  // Nodes have their start and end characters offsets recorded in
63  // `start` and `end` properties (directly on the node, rather than
64  // the `loc` object, which holds line/column data. To also add a
65  // [semi-standardized][range] `range` property holding a `[start,
66  // end]` array with the same numbers, set the `ranges` option to
67  // `true`.
68  //
69  // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678
70  ranges: false,
71  // It is possible to parse multiple files into a single AST by
72  // passing the tree produced by parsing the first file as
73  // `program` option in subsequent parses. This will add the
74  // toplevel forms of the parsed file to the `Program` (top) node
75  // of an existing parse tree.
76  program: null,
77  // When `locations` is on, you can pass this to record the source
78  // file in every node's `loc` object.
79  sourceFile: null,
80  // This value, if given, is stored in every node, whether
81  // `locations` is on or off.
82  directSourceFile: null,
83  // When enabled, parenthesized expressions are represented by
84  // (non-standard) ParenthesizedExpression nodes
85  preserveParens: false,
86  plugins: {}
87}
88
89// Interpret and default an options object
90
91export function getOptions(opts) {
92  let options = {}
93
94  for (let opt in defaultOptions)
95    options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt]
96
97  if (options.ecmaVersion >= 2015)
98    options.ecmaVersion -= 2009
99
100  if (options.allowReserved == null)
101    options.allowReserved = options.ecmaVersion < 5
102
103  if (isArray(options.onToken)) {
104    let tokens = options.onToken
105    options.onToken = (token) => tokens.push(token)
106  }
107  if (isArray(options.onComment))
108    options.onComment = pushComment(options, options.onComment)
109
110  return options
111}
112
113function pushComment(options, array) {
114  return function (block, text, start, end, startLoc, endLoc) {
115    let comment = {
116      type: block ? 'Block' : 'Line',
117      value: text,
118      start: start,
119      end: end
120    }
121    if (options.locations)
122      comment.loc = new SourceLocation(this, startLoc, endLoc)
123    if (options.ranges)
124      comment.range = [start, end]
125    array.push(comment)
126  }
127}
128
129